@botsigged/sdk 1.0.0

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 BotSigged
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,151 @@
1
+ # BotSigged SDK
2
+
3
+ A lightweight SDK for real-time bot detection via WebSocket to be connected to botsigged.com (account required).
4
+
5
+ ## Bundle Size
6
+
7
+ The SDK uses code splitting to minimize initial load time. Optional features are lazy-loaded only when enabled.
8
+
9
+ ### ESM Build (npm package)
10
+
11
+ | File | Size | Gzipped | When Loaded |
12
+ |------|------|---------|-------------|
13
+ | **index.js** | 66 KB | **17 KB** | Always (initial) |
14
+ | challenge-*.js | 6 KB | 2 KB | Only if `action: 'challenge'` |
15
+ | hash-*.js | 9 KB | 4 KB | Only if `hashVerification.enabled` |
16
+
17
+ ### IIFE Build (script tag)
18
+
19
+ | File | Size | Gzipped |
20
+ |------|------|---------|
21
+ | botsigged.js | 85 KB | 25 KB |
22
+
23
+ The IIFE build includes all features in a single file for simplicity.
24
+
25
+ ## Features
26
+
27
+ - **Lightweight** - ~17 KB gzipped initial bundle (ESM)
28
+ - **Code splitting** - Challenge and hash modules lazy-loaded on demand
29
+ - **Modular architecture**:
30
+ - Mouse, scroll, and form behavior tracking
31
+ - Browser fingerprinting
32
+ - WebSocket transport (Phoenix channels)
33
+ - Form protection (optionally auto-blocks bots before detection completes)
34
+ - PoW challenge system (optional)
35
+
36
+ ## Installation
37
+
38
+ ```bash
39
+ npm install @botsigged/sdk
40
+ ```
41
+
42
+ Or include directly in HTML:
43
+
44
+ ```html
45
+ <script src="https://unpkg.com/@botsigged/sdk/dist/botsigged.js"></script>
46
+ ```
47
+
48
+ ## Usage
49
+
50
+ ### Basic
51
+
52
+ ```typescript
53
+ import { BotSigged } from '@botsigged/sdk';
54
+
55
+ const botsigged = new BotSigged({
56
+ apiKey: 'pk_your_api_key_here',
57
+ });
58
+ ```
59
+
60
+ The SDK auto-starts and begins collecting behavioral signals immediately.
61
+
62
+ ### With Account Identification
63
+
64
+ Track risk across sessions by associating a user account:
65
+
66
+ ```typescript
67
+ const botsigged = new BotSigged({
68
+ apiKey: 'pk_your_api_key_here',
69
+ accountId: 'user_123', // Associate session with account on init
70
+ });
71
+
72
+ // Or identify later (e.g., after login)
73
+ await botsigged.identify({ accountId: 'user_123' });
74
+ ```
75
+
76
+ ### Server-Side Verification
77
+
78
+ Pass the session ID to your backend for server-side score lookup:
79
+
80
+ ```typescript
81
+ const botsigged = new BotSigged({
82
+ apiKey: 'pk_your_api_key_here',
83
+
84
+ // Option 1: Cookie (for traditional form posts)
85
+ cookie: true, // Sets '_bsid' cookie
86
+
87
+ // Option 2: Headers (for SPAs using fetch/XHR)
88
+ headers: true, // Adds 'X-BotSigged-ID' header to requests
89
+
90
+ // Option 3: Hidden form field (cookie-free forms)
91
+ formInject: true, // Injects '_bsid' hidden input
92
+ });
93
+ ```
94
+
95
+ Then verify on your backend:
96
+ ```
97
+ GET https://api.botsigged.com/v1/sessions/{session_id}
98
+ Authorization: Bearer sk_your_secret_key
99
+ ```
100
+
101
+ ### Form Protection
102
+
103
+ Automatically hold form submissions until bot detection completes:
104
+
105
+ ```typescript
106
+ const botsigged = new BotSigged({
107
+ apiKey: 'pk_your_api_key_here',
108
+ formProtection: {
109
+ mode: 'holdUntilReady', // Wait for score before allowing submit
110
+ maxHoldTime: 3000, // Max 3s wait
111
+ },
112
+ });
113
+ ```
114
+
115
+ ### React / SPA Usage
116
+
117
+ For programmatic form submissions:
118
+
119
+ ```typescript
120
+ const botsigged = new BotSigged({ apiKey: 'pk_your_api_key_here' });
121
+
122
+ // Wait for detection before submitting
123
+ const handleSubmit = async (data) => {
124
+ const { score, timedOut } = await botsigged.waitUntilReady();
125
+
126
+ if (score && score > 70) {
127
+ return; // Block suspicious submissions
128
+ }
129
+
130
+ await fetch('/api/submit', {
131
+ method: 'POST',
132
+ body: JSON.stringify(data),
133
+ });
134
+ };
135
+ ```
136
+
137
+ ### Blocking Bots
138
+
139
+ Automatically block or challenge high-scoring sessions:
140
+
141
+ ```typescript
142
+ const botsigged = new BotSigged({
143
+ apiKey: 'pk_your_api_key_here',
144
+ action: 'block', // or 'challenge' for PoW
145
+ actionThreshold: 70, // Score threshold
146
+ });
147
+ ```
148
+
149
+ ## License
150
+
151
+ MIT
@@ -0,0 +1,82 @@
1
+ (()=>{var{defineProperty:v,getOwnPropertyNames:NA,getOwnPropertyDescriptor:wA}=Object,LA=Object.prototype.hasOwnProperty;var CA=new WeakMap,kA=(A)=>{var B=CA.get(A),Q;if(B)return B;if(B=v({},"__esModule",{value:!0}),A&&typeof A==="object"||typeof A==="function")NA(A).map((E)=>!LA.call(B,E)&&v(B,E,{get:()=>A[E],enumerable:!(Q=wA(A,E))||Q.enumerable}));return CA.set(A,B),B};var g=(A,B)=>{for(var Q in B)v(A,Q,{get:B[Q],enumerable:!0,configurable:!0,set:(E)=>B[Q]=()=>E})};var u=(A,B)=>()=>(A&&(B=A(A=0)),B);var ZA="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";function UA(A){let B=atob(A),Q=new Uint8Array(B.length);for(let E=0;E<B.length;E++)Q[E]=B.charCodeAt(E);return Q}async function i(){if(j)return j;return j=(async()=>{try{let A=UA(ZA),B=await WebAssembly.compile(A);return c=(await WebAssembly.instantiate(B,{env:{abort:(E,I,C,Y)=>{}}})).exports,OA(c)}catch(A){throw j=null,A}})(),j}function a(){return c!==null}function OA(A){function B(I){let C=A.__new(I.length,1);return new Uint8Array(A.memory.buffer,C,I.length).set(I),C}function Q(I){let C=new Uint16Array(I.length);for(let Z=0;Z<I.length;Z++)C[Z]=I.charCodeAt(Z);let Y=A.__new(C.length*2,2);return new Uint16Array(A.memory.buffer,Y,C.length).set(C),Y}function E(I,C=1024){let Y=new Uint8Array(A.memory.buffer),G=Y.length;if(I<0||I>=G)return"";let Z=I,K=Math.min(I+C,G);while(Z<K&&Y[Z]!==0)Z++;let X=Y.slice(I,Z);return new TextDecoder().decode(X)}return{xxHash32(I,C=0){let Y=B(I);try{return A.xxHash32(Y,C)}finally{A.__unpin(Y)}},hashString(I,C=0){let Y=Q(I);try{return A.hashString(Y,C)}finally{A.__unpin(Y)}},hashStringToHex(I,C=0){let Y=Q(I);try{let G=A.hashStringToHex(Y,C);return E(G)}finally{A.__unpin(Y)}},verifyHash(I,C,Y=0){let G=B(I);try{return A.verifyHash(G,C,Y)}finally{A.__unpin(G)}},verifyStringHash(I,C,Y=0){let G=Q(I);try{return A.verifyStringHash(G,C,Y)}finally{A.__unpin(G)}}}}function M(){let A=new TextEncoder;function B(E,I=0){let X=($,D)=>($<<D|$>>>32-D)>>>0,N=($,D)=>($[D]|$[D+1]<<8|$[D+2]<<16|$[D+3]<<24)>>>0,V=E.length,z,W=0;if(V>=16){let $=V-16,D=I+2654435761+2246822519>>>0,T=I+2246822519>>>0,x=I>>>0,h=I-2654435761>>>0;while(W<=$)D=Math.imul(X(D+Math.imul(N(E,W),2246822519)>>>0,13),2654435761)>>>0,W+=4,T=Math.imul(X(T+Math.imul(N(E,W),2246822519)>>>0,13),2654435761)>>>0,W+=4,x=Math.imul(X(x+Math.imul(N(E,W),2246822519)>>>0,13),2654435761)>>>0,W+=4,h=Math.imul(X(h+Math.imul(N(E,W),2246822519)>>>0,13),2654435761)>>>0,W+=4;z=X(D,1)+X(T,7)+X(x,12)+X(h,18)>>>0}else z=I+374761393>>>0;z=z+V>>>0;while(W<=V-4)z=Math.imul(X(z+Math.imul(N(E,W),3266489917)>>>0,17),668265263)>>>0,W+=4;while(W<V)z=Math.imul(X(z+Math.imul(E[W],374761393)>>>0,11),2654435761)>>>0,W++;return z^=z>>>15,z=Math.imul(z,2246822519)>>>0,z^=z>>>13,z=Math.imul(z,3266489917)>>>0,z^=z>>>16,z>>>0}function Q(E){return(E>>>0).toString(16).padStart(8,"0")}return{xxHash32:B,hashString(E,I=0){return B(A.encode(E),I)},hashStringToHex(E,I=0){return Q(B(A.encode(E),I))},verifyHash(E,I,C=0){return B(E,C)===I},verifyStringHash(E,I,C=0){return B(A.encode(E),C)===I}}}var c=null,j=null;var XA=()=>{};var zA={};g(zA,{verifySignature:()=>MA,verify:()=>PA,loadHashModule:()=>i,isUsingWasm:()=>jA,isHashModuleLoaded:()=>a,initHashModule:()=>FA,hashToHex:()=>s,hash:()=>_A,getHash:()=>U,createSignature:()=>RA,createFallbackHashModule:()=>M});async function FA(A={}){let{preferWasm:B=!0,onWasmLoaded:Q,onFallback:E}=A;if(H)return H;if(y)return y;return y=(async()=>{if(B)try{return H=await i(),S=!0,Q?.(),H}catch(I){let C=I instanceof Error?I.message:"Unknown error";E?.(C)}else E?.("WASM disabled by configuration");return H=M(),S=!1,H})(),y}function U(){if(H)return H;return H=M(),S=!1,H}function jA(){return S&&a()}function _A(A,B=0){let Q=U();if(typeof A==="string")return Q.hashString(A,B);return Q.xxHash32(A,B)}function s(A,B=0){let Q=U();if(typeof A==="string")return Q.hashStringToHex(A,B);return Q.xxHash32(A,B).toString(16).padStart(8,"0")}function PA(A,B,Q=0){let E=U(),I=typeof B==="string"?parseInt(B,16):B;if(typeof A==="string")return E.verifyStringHash(A,I,Q);return E.verifyHash(A,I,Q)}function RA(A,B){let Q=U(),E=Q.hashString(B,0);return Q.hashString(A,E).toString(16).padStart(8,"0")}function MA(A,B,Q){return RA(A,Q)===B}var H=null,y=null,S=!0;var b=u(()=>{XA()});class BA{overlay=null;messageEl=null;progressEl=null;config;constructor(A){this.config=A}show(){if(!this.config.enabled||this.overlay)return;this.overlay=document.createElement("div"),this.overlay.id="botsigged-challenge-overlay",this.overlay.style.cssText=`
2
+ position: fixed;
3
+ top: 0;
4
+ left: 0;
5
+ width: 100%;
6
+ height: 100%;
7
+ background: ${this.config.backgroundColor};
8
+ display: flex;
9
+ flex-direction: column;
10
+ align-items: center;
11
+ justify-content: center;
12
+ z-index: ${this.config.zIndex};
13
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
14
+ `;let A=document.createElement("div");A.style.cssText=`
15
+ width: 48px;
16
+ height: 48px;
17
+ border: 4px solid ${this.config.textColor}33;
18
+ border-top-color: ${this.config.spinnerColor};
19
+ border-radius: 50%;
20
+ animation: botsigged-spin 1s linear infinite;
21
+ margin-bottom: 20px;
22
+ `,this.messageEl=document.createElement("span"),this.messageEl.textContent=this.config.message,this.messageEl.style.cssText=`
23
+ color: ${this.config.textColor};
24
+ font-size: 18px;
25
+ font-weight: 500;
26
+ margin-bottom: 12px;
27
+ `;let B=document.createElement("div");B.style.cssText=`
28
+ width: 200px;
29
+ height: 4px;
30
+ background: ${this.config.textColor}33;
31
+ border-radius: 2px;
32
+ overflow: hidden;
33
+ `,this.progressEl=document.createElement("div"),this.progressEl.style.cssText=`
34
+ width: 0%;
35
+ height: 100%;
36
+ background: ${this.config.spinnerColor};
37
+ border-radius: 2px;
38
+ transition: width 0.1s ease-out;
39
+ `,B.appendChild(this.progressEl);let Q=document.createElement("style");Q.textContent=`
40
+ @keyframes botsigged-spin {
41
+ to { transform: rotate(360deg); }
42
+ }
43
+ `,document.head.appendChild(Q),this.overlay.appendChild(A),this.overlay.appendChild(this.messageEl),this.overlay.appendChild(B),document.body.appendChild(this.overlay)}setProgress(A){if(this.progressEl){let B=Math.min(100,Math.max(0,A*100));this.progressEl.style.width=`${B}%`}}showSuccess(){if(this.messageEl)this.messageEl.textContent=this.config.successMessage;if(this.progressEl)this.progressEl.style.width="100%"}hide(){if(this.overlay)this.overlay.remove(),this.overlay=null,this.messageEl=null,this.progressEl=null}isVisible(){return this.overlay!==null}}var HA={};g(HA,{ChallengeManager:()=>DA});function SA(){let A=new Uint8Array(16);if(typeof crypto<"u"&&crypto.getRandomValues)crypto.getRandomValues(A);else for(let B=0;B<16;B++)A[B]=Math.floor(Math.random()*256);return A}function bA(A){if(A===0)return 32;let B=0;if((A&4294901760)===0)B+=16,A<<=16;if((A&4278190080)===0)B+=8,A<<=8;if((A&4026531840)===0)B+=4,A<<=4;if((A&3221225472)===0)B+=2,A<<=2;if((A&2147483648)===0)B+=1;return B}function TA(A,B,Q,E){let I=U(),C=new Uint8Array(A.length+4);C.set(A);let Y=E,G=0;while(G<Q){C[A.length]=Y&255,C[A.length+1]=Y>>>8&255,C[A.length+2]=Y>>>16&255,C[A.length+3]=Y>>>24&255;let Z=I.xxHash32(C,0);if(G++,bA(Z)>=B)return{nonce:Y,found:!0,iterations:G};Y=Y+1>>>0}return{nonce:Y,found:!1,iterations:G}}class DA{config;overlay;solving=!1;solved=!1;pendingForms=new Map;formHandler=null;formObserver=null;resubmitting=!1;debug;constructor(A,B=!1){this.config=A,this.debug=B,this.overlay=new BA(A.ui)}getDifficultyForLevel(A){let B=this.config.difficulty;switch(A){case"critical":return B.critical;case"high":return B.high;case"medium":return B.medium;default:return 0}}shouldChallenge(A){if(!this.config.enabled||this.solved)return!1;let B=["low","medium","high","critical"],Q=B.indexOf(A),E=B.indexOf(this.config.minLevel);return Q>=E}blockFormsUntilSolved(A){if(this.formHandler)return;this.formHandler=(B)=>{if(this.solved||this.resubmitting)return;B.preventDefault(),B.stopPropagation();let Q=B.target;if(!this.pendingForms.has(Q))this.pendingForms.set(Q,B);if(!this.solving)this.startChallenge(A)},document.querySelectorAll("form").forEach((B)=>{B.addEventListener("submit",this.formHandler,!0)}),this.formObserver=new MutationObserver((B)=>{B.forEach((Q)=>{Q.addedNodes.forEach((E)=>{if(E instanceof HTMLFormElement&&this.formHandler)E.addEventListener("submit",this.formHandler,!0);if(E instanceof HTMLElement&&this.formHandler)E.querySelectorAll("form").forEach((I)=>{I.addEventListener("submit",this.formHandler,!0)})})})}),this.formObserver.observe(document.body,{childList:!0,subtree:!0}),this.log("Forms blocked, challenge required")}async startChallenge(A){if(this.solving||this.solved)return;this.solving=!0;let B=this.getDifficultyForLevel(A),Q=SA(),E=performance.now();this.log(`Starting challenge: difficulty=${B}, level=${A}`),this.config.onChallengeStart?.(A,B),this.overlay.show();let I=1<<B,C=0,Y=0,G;do{await new Promise((N)=>setTimeout(N,0)),G=TA(Q,B,this.config.chunkSize,C),Y+=G.iterations,C=G.nonce+1;let X=Math.min(1,Y/I);this.overlay.setProgress(X),this.config.onChallengeProgress?.(X,Y)}while(!G.found);let Z=performance.now()-E;this.log(`Challenge solved: nonce=${G.nonce}, iterations=${Y}, time=${Z.toFixed(0)}ms`),this.overlay.showSuccess(),await new Promise((X)=>setTimeout(X,500)),this.overlay.hide(),this.solved=!0,this.solving=!1;let K={solveTimeMs:Z,iterations:Y,difficulty:B,level:A,nonce:G.nonce};this.config.onChallengeComplete?.(K),this.unblockForms()}unblockForms(){if(this.formObserver)this.formObserver.disconnect(),this.formObserver=null;if(this.formHandler)document.querySelectorAll("form").forEach((A)=>{A.removeEventListener("submit",this.formHandler,!0)}),this.formHandler=null;this.log("Forms unblocked"),this.resubmitting=!0,this.pendingForms.forEach((A,B)=>{if(this.log("Resubmitting pending form"),B.requestSubmit)B.requestSubmit();else B.submit()}),this.pendingForms.clear(),this.resubmitting=!1}isSolving(){return this.solving}isSolved(){return this.solved}reset(){if(this.formObserver)this.formObserver.disconnect(),this.formObserver=null;if(this.formHandler)document.querySelectorAll("form").forEach((A)=>{A.removeEventListener("submit",this.formHandler,!0)}),this.formHandler=null;this.solved=!1,this.solving=!1,this.resubmitting=!1,this.pendingForms.clear()}log(...A){if(this.debug);}}var $A=u(()=>{b()});var hA={};g(hA,{init:()=>QA,getInstance:()=>EA,destroy:()=>IA,BotSigged:()=>_});function YA(A){return typeof A==="object"&&A!==null&&"code"in A&&A.code==="LIMIT_EXCEEDED"}var R={endpoint:"wss://api.botsigged.com/socket/websocket",debug:!1,sendInterval:2000,maxBufferSize:1000,mouseSampleRate:0.5,autoStart:!0,actionThreshold:70,action:"none",minAlertLevel:"high",botScoreThresholds:{medium:40,high:70,critical:90},hashVerification:{enabled:!1,preferWasm:!0},challenge:{enabled:!1,minLevel:"high",chunkSize:1e4,difficulty:{medium:12,high:16,critical:20},ui:{enabled:!0,message:"Verifying you're human...",successMessage:"Verified!",backgroundColor:"rgba(0, 0, 0, 0.7)",textColor:"#ffffff",spinnerColor:"#3b82f6",zIndex:999999}},formProtection:{mode:"auto",minTimeBeforeSubmit:500,maxHoldTime:3000,showLoadingUI:!0,loadingMessage:"Please wait..."},fallbackMode:"degraded"},GA={action:"challenge",challenge:{difficulty:{suspicious:14,bot:18},timeout_ms:30000},form_protection_mode:"holdUntilReady"};function JA(A){let B=A.action??R.action,Q=B==="challenge"||A.challenge?.enabled;return{apiKey:A.apiKey,accountId:A.accountId,endpoint:A.endpoint??R.endpoint,debug:A.debug??R.debug,sendInterval:A.sendInterval??R.sendInterval,maxBufferSize:A.maxBufferSize??R.maxBufferSize,mouseSampleRate:A.mouseSampleRate??R.mouseSampleRate,autoStart:A.autoStart??R.autoStart,actionThreshold:A.actionThreshold??R.actionThreshold,action:B,minAlertLevel:A.minAlertLevel??R.minAlertLevel,botScoreThresholds:{...R.botScoreThresholds,...A.botScoreThresholds},hashVerification:{...R.hashVerification,...A.hashVerification},challenge:{enabled:Q,minLevel:A.challenge?.minLevel??R.challenge.minLevel,chunkSize:A.challenge?.chunkSize??R.challenge.chunkSize,difficulty:{...R.challenge.difficulty,...A.challenge?.difficulty},ui:{...R.challenge.ui,...A.challenge?.ui},onChallengeStart:A.challenge?.onChallengeStart,onChallengeComplete:A.challenge?.onChallengeComplete,onChallengeProgress:A.challenge?.onChallengeProgress},formProtection:{mode:A.formProtection?.mode??R.formProtection.mode,minTimeBeforeSubmit:A.formProtection?.minTimeBeforeSubmit??R.formProtection.minTimeBeforeSubmit,maxHoldTime:A.formProtection?.maxHoldTime??R.formProtection.maxHoldTime,showLoadingUI:A.formProtection?.showLoadingUI??R.formProtection.showLoadingUI,loadingMessage:A.formProtection?.loadingMessage??R.formProtection.loadingMessage,onHold:A.formProtection?.onHold,onRelease:A.formProtection?.onRelease,onBlock:A.formProtection?.onBlock},fallbackMode:A.fallbackMode??R.fallbackMode,cookie:A.cookie,headers:A.headers,formInject:A.formInject,onScoreUpdate:A.onScoreUpdate,onConnectionChange:A.onConnectionChange,onError:A.onError,onUsageLimitExceeded:A.onUsageLimitExceeded,onHighBotScore:A.onHighBotScore,onServerConfig:A.onServerConfig,onServerAction:A.onServerAction}}class p{events=[];startTime=0;sampleRate;maxBufferSize;isListening=!1;boundHandleMouseMove;boundHandleMouseDown;boundHandleMouseUp;boundHandleClick;constructor(A={}){this.sampleRate=A.sampleRate??0.5,this.maxBufferSize=A.maxBufferSize??500,this.boundHandleMouseMove=this.handleMouseMove.bind(this),this.boundHandleMouseDown=this.handleMouseDown.bind(this),this.boundHandleMouseUp=this.handleMouseUp.bind(this),this.boundHandleClick=this.handleClick.bind(this)}start(){if(this.isListening)return;this.startTime=Date.now(),document.addEventListener("mousemove",this.boundHandleMouseMove,{passive:!0}),document.addEventListener("mousedown",this.boundHandleMouseDown,{passive:!0}),document.addEventListener("mouseup",this.boundHandleMouseUp,{passive:!0}),document.addEventListener("click",this.boundHandleClick,{passive:!0}),this.isListening=!0}stop(){if(!this.isListening)return;document.removeEventListener("mousemove",this.boundHandleMouseMove),document.removeEventListener("mousedown",this.boundHandleMouseDown),document.removeEventListener("mouseup",this.boundHandleMouseUp),document.removeEventListener("click",this.boundHandleClick),this.isListening=!1}addEvent(A){if(this.events.push(A),this.events.length>this.maxBufferSize)this.events.shift()}handleMouseMove(A){if(Math.random()>this.sampleRate)return;this.addEvent({type:"move",x:A.clientX,y:A.clientY,t:Date.now()})}handleMouseDown(A){this.addEvent({type:"down",x:A.clientX,y:A.clientY,t:Date.now(),button:A.button})}handleMouseUp(A){this.addEvent({type:"up",x:A.clientX,y:A.clientY,t:Date.now(),button:A.button})}handleClick(A){let B=A.target,Q,E;if(B&&B.getBoundingClientRect){let I=B.getBoundingClientRect();Q={top:I.top,left:I.left,width:I.width,height:I.height},E=B.tagName?.toLowerCase()}this.addEvent({type:"click",x:A.clientX,y:A.clientY,t:Date.now(),button:A.button,targetRect:Q,targetTag:E})}getSignal(){return{events:[...this.events],start_time:this.startTime}}flush(){this.events=[]}getBufferSize(){return this.events.length}reset(){this.events=[],this.startTime=Date.now()}}class m{events=[];startTime=0;maxBufferSize;isListening=!1;boundHandleScroll;constructor(A={}){this.maxBufferSize=A.maxBufferSize??200,this.boundHandleScroll=this.handleScroll.bind(this)}start(){if(this.isListening)return;this.startTime=Date.now(),window.addEventListener("scroll",this.boundHandleScroll,{passive:!0}),this.isListening=!0}stop(){if(!this.isListening)return;window.removeEventListener("scroll",this.boundHandleScroll),this.isListening=!1}handleScroll(){if(this.events.push({y:window.scrollY,t:Date.now()}),this.events.length>this.maxBufferSize)this.events.shift()}getSignal(){return{events:[...this.events],start_time:this.startTime}}flush(){this.events=[]}getBufferSize(){return this.events.length}reset(){this.events=[],this.startTime=Date.now()}}class w{static instance=null;timings={signalRoundtrips:[]};pendingSignals=new Map;constructor(){this.timings.scriptStart=performance.now()}static getInstance(){if(!w.instance)w.instance=new w;return w.instance}static reset(){w.instance=null}markScriptStart(){this.timings.scriptStart=performance.now()}markConstructorStart(){this.timings.constructorStart=performance.now()}markConstructorEnd(){this.timings.constructorEnd=performance.now()}markStartCalled(){this.timings.startCalled=performance.now()}markSdkReady(){this.timings.sdkReady=performance.now()}markFingerprintStart(){this.timings.fingerprintStart=performance.now()}markFingerprintEnd(){this.timings.fingerprintEnd=performance.now()}markWsConnectStart(){this.timings.wsConnectStart=performance.now()}markWsConnectEnd(){this.timings.wsConnectEnd=performance.now()}markChannelJoinStart(){this.timings.channelJoinStart=performance.now()}markChannelJoinEnd(){this.timings.channelJoinEnd=performance.now()}markInitialScoreReceived(){this.timings.initialScoreReceived=performance.now()}markFormCollectorStart(){this.timings.formCollectorStart=performance.now()}markFormCollectorReady(){this.timings.formCollectorReady=performance.now()}markFirstFormInteraction(){if(!this.timings.firstFormInteraction){if(this.timings.firstFormInteraction=performance.now(),this.timings.sdkReady)this.timings.timeToFirstInteraction=this.timings.firstFormInteraction-this.timings.sdkReady}}markFirstSubmitAttempt(A){if(!this.timings.firstSubmitAttempt)this.timings.firstSubmitAttempt=performance.now(),this.timings.hadScoreBeforeSubmit=A}markSignalSent(A){this.pendingSignals.set(A,performance.now())}markSignalResponseReceived(A){let B=this.pendingSignals.get(A);if(B!==void 0){let Q=performance.now(),E={sentAt:B,receivedAt:Q,roundtripMs:Q-B,seq:A};this.timings.signalRoundtrips?.push(E),this.pendingSignals.delete(A)}}getTimings(){return{...this.timings}}getSummary(){let A=this.timings,B=A.signalRoundtrips||[],Q=0,E=1/0,I=0;if(B.length>0)Q=B.reduce((V,z)=>V+z.roundtripMs,0)/B.length,E=Math.min(...B.map((V)=>V.roundtripMs)),I=Math.max(...B.map((V)=>V.roundtripMs));let C=(A.sdkReady??0)-(A.scriptStart??0),Y=(A.fingerprintEnd??0)-(A.fingerprintStart??0),G=(A.wsConnectEnd??0)-(A.wsConnectStart??0),Z=(A.channelJoinEnd??0)-(A.channelJoinStart??0),K=(A.initialScoreReceived??0)-(A.startCalled??0),X=(A.initialScoreReceived??0)-(A.scriptStart??0);return{totalStartupMs:Math.round(C),fingerprintMs:Math.round(Y),wsConnectionMs:Math.round(G),channelJoinMs:Math.round(Z),timeToFirstScoreMs:Math.round(K),avgSignalRoundtripMs:Math.round(Q),minSignalRoundtripMs:E===1/0?0:Math.round(E),maxSignalRoundtripMs:Math.round(I),vulnerabilityWindowMs:Math.round(X),protectedBeforeSubmit:A.hadScoreBeforeSubmit??!1}}logSummary(){let A=this.getSummary(),B=this.timings;if(B.firstFormInteraction);if(B.firstSubmitAttempt);if(A.vulnerabilityWindowMs>0);}getReport(){return{timings:this.timings,summary:this.getSummary(),userAgent:navigator.userAgent,timestamp:Date.now()}}}var J=w.getInstance();function O(){return w.getInstance()}var P="__bs_ghost_value";class d{keyEvents=[];focusEvents=[];pasteEvents=[];inputEvents=[];submitCount=0;startTime=0;maxKeyEvents;maxFocusEvents;maxInputEvents;isListening=!1;valueSetterHooked=!1;onSubmit;originalInputDescriptor;originalTextareaDescriptor;lastKeyWasTab=!1;currentField=null;emailDomains=new Set;boundHandleFocusIn;boundHandleFocusOut;boundHandleKeyDown;boundHandleKeyUp;boundHandlePaste;boundHandleSubmit;boundHandleClick;boundHandleInput;boundHandleGhostValue;constructor(A={}){this.maxKeyEvents=A.maxKeyEvents??500,this.maxFocusEvents=A.maxFocusEvents??100,this.maxInputEvents=A.maxInputEvents??200,this.onSubmit=A.onSubmit,this.boundHandleFocusIn=this.handleFocusIn.bind(this),this.boundHandleFocusOut=this.handleFocusOut.bind(this),this.boundHandleKeyDown=this.handleKeyDown.bind(this),this.boundHandleKeyUp=this.handleKeyUp.bind(this),this.boundHandlePaste=this.handlePaste.bind(this),this.boundHandleSubmit=this.handleSubmit.bind(this),this.boundHandleClick=this.handleClick.bind(this),this.boundHandleInput=this.handleInput.bind(this),this.boundHandleGhostValue=this.handleGhostValue.bind(this)}start(){if(this.isListening)return;this.startTime=Date.now(),document.addEventListener("focusin",this.boundHandleFocusIn,{passive:!0,capture:!0}),document.addEventListener("focusout",this.boundHandleFocusOut,{passive:!0,capture:!0}),document.addEventListener("keydown",this.boundHandleKeyDown,{passive:!0}),document.addEventListener("keyup",this.boundHandleKeyUp,{passive:!0}),document.addEventListener("paste",this.boundHandlePaste,{passive:!0}),document.addEventListener("submit",this.boundHandleSubmit,{passive:!0}),document.addEventListener("click",this.boundHandleClick,{passive:!0}),document.addEventListener("input",this.boundHandleInput,{passive:!0}),document.addEventListener(P,this.boundHandleGhostValue,{passive:!0}),this.hookValueSetters(),this.isListening=!0}stop(){if(!this.isListening)return;document.removeEventListener("focusin",this.boundHandleFocusIn,{capture:!0}),document.removeEventListener("focusout",this.boundHandleFocusOut,{capture:!0}),document.removeEventListener("keydown",this.boundHandleKeyDown),document.removeEventListener("keyup",this.boundHandleKeyUp),document.removeEventListener("paste",this.boundHandlePaste),document.removeEventListener("submit",this.boundHandleSubmit),document.removeEventListener("click",this.boundHandleClick),document.removeEventListener("input",this.boundHandleInput),document.removeEventListener(P,this.boundHandleGhostValue),this.unhookValueSetters(),this.isListening=!1}isFormInput(A){if(!A||!(A instanceof HTMLElement))return!1;let B=A.tagName.toLowerCase();if(B==="textarea"||B==="select")return!0;if(B==="input"){let Q=A.type.toLowerCase();return!["submit","button","reset","hidden","image"].includes(Q)}return!1}isEmailField(A){let B=A.type?.toLowerCase()||"",Q=(A.name||"").toLowerCase(),E=(A.id||"").toLowerCase();return B==="email"||Q.includes("email")||Q.includes("e-mail")||E.includes("email")||E.includes("e-mail")}extractEmailDomain(A){if(!A||typeof A!=="string")return null;let B=A.trim();if(!B)return null;let Q=B.match(/@([a-zA-Z0-9.-]+\.[a-zA-Z]{2,})$/);return Q?Q[1].toLowerCase():null}getFieldId(A){return A.id||A.getAttribute("name")||`field-${A.tagName.toLowerCase()}`}handleFocusIn(A){if(!this.isFormInput(A.target))return;O().markFirstFormInteraction();let B=this.getFieldId(A.target),Q="direct";if(this.lastKeyWasTab)Q="tab";if(this.focusEvents.push({type:"focus",field:B,t:Date.now(),method:Q}),this.focusEvents.length>this.maxFocusEvents)this.focusEvents.shift();this.currentField=B,this.lastKeyWasTab=!1}handleFocusOut(A){if(!this.isFormInput(A.target))return;let B=A.target,Q=this.getFieldId(B);if(this.focusEvents.push({type:"blur",field:Q,t:Date.now()}),this.focusEvents.length>this.maxFocusEvents)this.focusEvents.shift();if(B instanceof HTMLInputElement&&this.isEmailField(B)){let E=this.extractEmailDomain(B.value);if(E)this.emailDomains.add(E)}this.currentField=null}handleClick(A){if(!this.isFormInput(A.target))return;let B=this.focusEvents[this.focusEvents.length-1];if(B&&B.type==="focus"&&Date.now()-B.t<50)B.method="click"}handleKeyDown(A){if(A.key==="Tab"){this.lastKeyWasTab=!0;return}if(!this.isFormInput(A.target))return;let B="key";if(A.key==="Backspace")B="backspace";else if(A.key==="Delete")B="delete";else if(A.key==="Enter")B="enter";else if(A.key==="Tab")B="tab";else if(A.key.length===1)B="char";else if(A.key.startsWith("Arrow"))B="arrow";if(this.keyEvents.push({type:"down",code:B,t:Date.now(),field:this.currentField||void 0}),this.keyEvents.length>this.maxKeyEvents)this.keyEvents.shift()}handleKeyUp(A){if(!this.isFormInput(A.target))return;let B="key";if(A.key==="Backspace")B="backspace";else if(A.key==="Delete")B="delete";else if(A.key.length===1)B="char";if(this.keyEvents.push({type:"up",code:B,t:Date.now(),field:this.currentField||void 0}),this.keyEvents.length>this.maxKeyEvents)this.keyEvents.shift()}handleInput(A){if(!this.isFormInput(A.target))return;let B=A.target,E=A.inputType||"unknown",I=B.value?.length??0;if(this.inputEvents.push({field:this.getFieldId(B),t:Date.now(),inputType:E,valueLength:I}),this.inputEvents.length>this.maxInputEvents)this.inputEvents.shift()}handlePaste(A){if(!this.isFormInput(A.target))return;let B=A.clipboardData?.getData("text")||"";this.pasteEvents.push({field:this.getFieldId(A.target),t:Date.now(),length:B.length})}handleSubmit(A){this.submitCount++;let B=A.target;if(B&&B.elements)for(let Q=0;Q<B.elements.length;Q++){let E=B.elements[Q];if(E instanceof HTMLInputElement&&this.isEmailField(E)){let I=this.extractEmailDomain(E.value);if(I)this.emailDomains.add(I)}}this.onSubmit?.()}getSignal(){return{keys:[...this.keyEvents],focus:[...this.focusEvents],pastes:[...this.pasteEvents],inputs:[...this.inputEvents],submits:this.submitCount,start_time:this.startTime,email_domains:this.emailDomains.size>0?Array.from(this.emailDomains):void 0}}flush(){this.keyEvents=[],this.focusEvents=[],this.pasteEvents=[],this.inputEvents=[]}getBufferSize(){return this.keyEvents.length+this.focusEvents.length+this.pasteEvents.length+this.inputEvents.length}reset(){this.keyEvents=[],this.focusEvents=[],this.pasteEvents=[],this.inputEvents=[],this.submitCount=0,this.startTime=Date.now(),this.lastKeyWasTab=!1,this.currentField=null,this.emailDomains.clear()}hookValueSetters(){if(this.valueSetterHooked)return;if(this.originalInputDescriptor=Object.getOwnPropertyDescriptor(HTMLInputElement.prototype,"value"),this.originalInputDescriptor){let A=this.originalInputDescriptor.set,B=this.originalInputDescriptor.get;Object.defineProperty(HTMLInputElement.prototype,"value",{configurable:!0,enumerable:!0,get(){return B?.call(this)},set(Q){let E=B?.call(this)??"";A?.call(this,Q);let I=Q??"";if(I!==E)this.dispatchEvent(new CustomEvent(P,{bubbles:!0,detail:{valueLength:I.length,wasEmpty:E.length===0}}))}})}if(this.originalTextareaDescriptor=Object.getOwnPropertyDescriptor(HTMLTextAreaElement.prototype,"value"),this.originalTextareaDescriptor){let A=this.originalTextareaDescriptor.set,B=this.originalTextareaDescriptor.get;Object.defineProperty(HTMLTextAreaElement.prototype,"value",{configurable:!0,enumerable:!0,get(){return B?.call(this)},set(Q){let E=B?.call(this)??"";A?.call(this,Q);let I=Q??"";if(I!==E)this.dispatchEvent(new CustomEvent(P,{bubbles:!0,detail:{valueLength:I.length,wasEmpty:E.length===0}}))}})}this.valueSetterHooked=!0}unhookValueSetters(){if(!this.valueSetterHooked)return;if(this.originalInputDescriptor)Object.defineProperty(HTMLInputElement.prototype,"value",this.originalInputDescriptor);if(this.originalTextareaDescriptor)Object.defineProperty(HTMLTextAreaElement.prototype,"value",this.originalTextareaDescriptor);this.valueSetterHooked=!1}handleGhostValue(A){let B=A.target;if(!this.isFormInput(B))return;let E=A.detail?.valueLength??0;if(this.inputEvents.push({field:this.getFieldId(B),t:Date.now(),inputType:"programmatic",valueLength:E}),this.inputEvents.length>this.maxInputEvents)this.inputEvents.shift()}}class f{cachedSignal=null;collect(){if(this.cachedSignal)return this.cachedSignal;let A=navigator,B=window;return this.cachedSignal={user_agent:navigator.userAgent,platform:navigator.platform,language:navigator.language,languages:[...navigator.languages||[]],hardware_concurrency:navigator.hardwareConcurrency??null,device_memory:A.deviceMemory??null,max_touch_points:navigator.maxTouchPoints??0,screen_width:screen.width,screen_height:screen.height,screen_avail_width:screen.availWidth,screen_avail_height:screen.availHeight,color_depth:screen.colorDepth,pixel_ratio:window.devicePixelRatio??1,...this.getWebGLInfo(),plugins_count:navigator.plugins?.length??0,mime_types_count:navigator.mimeTypes?.length??0,timezone:this.getTimezone(),timezone_offset:new Date().getTimezoneOffset(),has_webdriver:A.webdriver===!0,has_chrome_runtime:!!B.chrome?.runtime,has_chrome_app:!!B.chrome?.app,has_notification_api:"Notification"in window,has_permissions_api:"permissions"in navigator,outer_dimensions:{width:window.outerWidth,height:window.outerHeight},inner_dimensions:{width:window.innerWidth,height:window.innerHeight},notification_permission:this.getNotificationPermission()},this.cachedSignal}getWebGLInfo(){try{let A=document.createElement("canvas"),B=A.getContext("webgl")||A.getContext("experimental-webgl");if(!B||!(B instanceof WebGLRenderingContext))return{webgl_vendor:null,webgl_renderer:null};let Q=B.getExtension("WEBGL_debug_renderer_info");if(!Q)return{webgl_vendor:null,webgl_renderer:null};return{webgl_vendor:B.getParameter(Q.UNMASKED_VENDOR_WEBGL),webgl_renderer:B.getParameter(Q.UNMASKED_RENDERER_WEBGL)}}catch{return{webgl_vendor:null,webgl_renderer:null}}}getTimezone(){try{return Intl.DateTimeFormat().resolvedOptions().timeZone}catch{return null}}getNotificationPermission(){if("Notification"in window)return Notification.permission;return null}getSignal(){return this.collect()}reset(){this.cachedSignal=null}}b();class n{cachedFingerprint=null;async generate(){if(this.cachedFingerprint)return this.cachedFingerprint;let[A,B,Q,E,I]=await Promise.all([this.getCanvasHash(),this.getWebGLData(),this.getAudioHash(),this.getFontData(),this.getScreenHash()]),C={hash:"",canvas_hash:A,webgl_hash:B.hash,audio_hash:Q,font_hash:E.hash,screen_hash:I,webgl_vendor:B.vendor,webgl_renderer:B.renderer,timezone:this.getTimezone(),language:this.getLanguage(),platform:this.getPlatform(),font_count:E.count};return C.hash=await this.generateMainHash(C),this.cachedFingerprint=C,C}getFingerprint(){return this.cachedFingerprint}reset(){this.cachedFingerprint=null}async getCanvasHash(){try{let A=document.createElement("canvas");A.width=200,A.height=50;let B=A.getContext("2d");if(!B)return null;B.textBaseline="top",B.font="14px 'Arial'",B.fillStyle="#f60",B.fillRect(125,1,62,20),B.fillStyle="#069",B.fillText("BotSigged,\uD83C\uDFA8",2,15),B.fillStyle="rgba(102, 204, 0, 0.7)",B.fillText("BotSigged,\uD83C\uDFA8",4,17);let Q=A.toDataURL();return this.hashString(Q)}catch{return null}}async getWebGLData(){try{let A=document.createElement("canvas"),B=A.getContext("webgl")||A.getContext("experimental-webgl");if(!B||!(B instanceof WebGLRenderingContext))return{hash:null,vendor:null,renderer:null};let Q=[],E=[B.ALIASED_LINE_WIDTH_RANGE,B.ALIASED_POINT_SIZE_RANGE,B.ALPHA_BITS,B.BLUE_BITS,B.DEPTH_BITS,B.GREEN_BITS,B.MAX_COMBINED_TEXTURE_IMAGE_UNITS,B.MAX_CUBE_MAP_TEXTURE_SIZE,B.MAX_FRAGMENT_UNIFORM_VECTORS,B.MAX_RENDERBUFFER_SIZE,B.MAX_TEXTURE_IMAGE_UNITS,B.MAX_TEXTURE_SIZE,B.MAX_VARYING_VECTORS,B.MAX_VERTEX_ATTRIBS,B.MAX_VERTEX_TEXTURE_IMAGE_UNITS,B.MAX_VERTEX_UNIFORM_VECTORS,B.MAX_VIEWPORT_DIMS,B.RED_BITS,B.RENDERER,B.SHADING_LANGUAGE_VERSION,B.STENCIL_BITS,B.VENDOR,B.VERSION];for(let K of E)try{let X=B.getParameter(K);Q.push(String(X))}catch{Q.push("")}let I=B.getSupportedExtensions();if(I)Q.push(I.sort().join(","));let C=null,Y=null,G=B.getExtension("WEBGL_debug_renderer_info");if(G)C=B.getParameter(G.UNMASKED_VENDOR_WEBGL),Y=B.getParameter(G.UNMASKED_RENDERER_WEBGL);return{hash:this.hashString(Q.join("|")),vendor:C,renderer:Y}}catch{return{hash:null,vendor:null,renderer:null}}}async getAudioHash(){try{let A=window.OfflineAudioContext||window.webkitOfflineAudioContext;if(!A)return null;let B=new A(1,4500,44100),Q=B.createOscillator(),E=B.createDynamicsCompressor();Q.type="triangle",Q.frequency.setValueAtTime(1e4,B.currentTime),E.threshold.setValueAtTime(-50,B.currentTime),E.knee.setValueAtTime(40,B.currentTime),E.ratio.setValueAtTime(12,B.currentTime),E.attack.setValueAtTime(0,B.currentTime),E.release.setValueAtTime(0.25,B.currentTime),Q.connect(E),E.connect(B.destination),Q.start(0);let C=(await B.startRendering()).getChannelData(0),Y=[];for(let G=0;G<C.length;G+=100)Y.push(C[G]);return this.hashString(Y.join(","))}catch{return null}}async getFontData(){let A=["Arial","Arial Black","Arial Narrow","Calibri","Cambria","Cambria Math","Comic Sans MS","Consolas","Courier","Courier New","Georgia","Helvetica","Impact","Lucida Console","Lucida Sans Unicode","Microsoft Sans Serif","MS Gothic","MS PGothic","MS Sans Serif","MS Serif","Palatino Linotype","Segoe Print","Segoe Script","Segoe UI","Symbol","Tahoma","Times","Times New Roman","Trebuchet MS","Verdana","Wingdings"],B=["monospace","sans-serif","serif"],Q="mmmmmmmmmmlli",E="72px",I=document.createElement("span");I.style.position="absolute",I.style.left="-9999px",I.style.fontSize="72px",I.style.lineHeight="normal",I.innerHTML="mmmmmmmmmmlli",document.body.appendChild(I);let C={};for(let Z of B)I.style.fontFamily=Z,C[Z]=I.offsetWidth;let Y=[];for(let Z of A){let K=!1;for(let X of B)if(I.style.fontFamily=`'${Z}', ${X}`,I.offsetWidth!==C[X]){K=!0;break}if(K)Y.push(Z)}return document.body.removeChild(I),{hash:this.hashString(Y.join(",")),count:Y.length}}async getScreenHash(){let A=[String(screen.width),String(screen.height),String(screen.availWidth),String(screen.availHeight),String(screen.colorDepth),String(screen.pixelDepth),String(window.devicePixelRatio||1)];return this.hashString(A.join("|"))}getTimezone(){try{return Intl.DateTimeFormat().resolvedOptions().timeZone}catch{return null}}getLanguage(){return navigator.language||null}getPlatform(){return navigator.platform||null}generateMainHash(A){let B=[A.canvas_hash||"",A.webgl_hash||"",A.audio_hash||"",A.font_hash||"",A.screen_hash||"",A.timezone||"",A.language||"",A.platform||""];return this.hashString(B.join("|"))}hashString(A){return s(A)}}class t{ws=null;endpoint;apiKey;heartbeatInterval;reconnectAttempts;reconnectDelay;debug;state="disconnected";channelState="closed";refCounter=0;joinRef=null;heartbeatTimer=null;reconnectTimer=null;reconnectCount=0;pendingReplies=new Map;onConnectionChange;onError;channelCallbacks={};topic=null;constructor(A){this.endpoint=A.endpoint,this.apiKey=A.apiKey,this.heartbeatInterval=A.heartbeatInterval??30000,this.reconnectAttempts=A.reconnectAttempts??10,this.reconnectDelay=A.reconnectDelay??((B)=>Math.min(1000*Math.pow(2,B),30000)),this.debug=A.debug??!1,this.onConnectionChange=A.onConnectionChange,this.onError=A.onError}connect(){return new Promise((A,B)=>{if(this.ws&&this.state==="connected"){A();return}this.setState("connecting");let Q=this.buildUrl();this.log("Connecting to",Q);try{this.ws=new WebSocket(Q),this.ws.onopen=()=>{this.log("WebSocket connected"),this.setState("connected"),this.reconnectCount=0,this.startHeartbeat(),A()},this.ws.onclose=(E)=>{this.log("WebSocket closed",E.code,E.reason),this.handleClose()},this.ws.onerror=(E)=>{this.log("WebSocket error",E);let I=Error("WebSocket connection error");this.handleError(I),B(I)},this.ws.onmessage=(E)=>{this.handleMessage(E.data)}}catch(E){let I=E instanceof Error?E:Error(String(E));this.handleError(I),B(I)}})}disconnect(){if(this.stopHeartbeat(),this.stopReconnect(),this.ws)this.ws.close(1000,"Client disconnect"),this.ws=null;this.setState("disconnected"),this.setChannelState("closed")}joinChannel(A,B,Q,E,I={},C){return this.channelCallbacks=I,this.topic=`detection:${A}`,new Promise((Y,G)=>{if(this.state!=="connected"){G(Error("WebSocket not connected"));return}this.setChannelState("joining"),this.joinRef=this.makeRef();let Z={session_id:A,api_key:this.apiKey,fingerprint:B,session:Q,browser:E};if(C)Z.account_id=C;this.push("phx_join",Z,this.joinRef).then((K)=>{this.log("Channel joined",K),this.setChannelState("joined"),this.channelCallbacks.onJoin?.(),Y(K)}).catch((K)=>{this.log("Channel join failed",K),this.setChannelState("error"),this.channelCallbacks.onError?.(K),G(K)})})}leaveChannel(){return new Promise((A,B)=>{if(this.channelState!=="joined"){A();return}this.setChannelState("leaving"),this.push("phx_leave",{}).then(()=>{this.log("Channel left"),this.setChannelState("closed"),this.joinRef=null,this.topic=null,this.channelCallbacks.onLeave?.(),A()}).catch((Q)=>{this.setChannelState("error"),B(Q)})})}sendSignal(A){if(this.channelState!=="joined")return Promise.reject(Error("Channel not joined"));return this.push("signal",A)}sendFormStatus(A){if(this.channelState!=="joined")return Promise.reject(Error("Channel not joined"));return this.push("form_status",{status:A})}sendEvent(A,B){if(this.channelState!=="joined")return Promise.reject(Error("Channel not joined"));return this.push(A,B)}getState(){return this.state}getChannelState(){return this.channelState}isReady(){return this.state==="connected"&&this.channelState==="joined"}buildUrl(){let A=new URL(this.endpoint);return A.searchParams.set("vsn","2.0.0"),A.searchParams.set("api_key",this.apiKey),A.toString()}makeRef(){return this.refCounter++,String(this.refCounter)}push(A,B,Q){return new Promise((E,I)=>{if(!this.ws||this.ws.readyState!==WebSocket.OPEN){I(Error("WebSocket not open"));return}if(!this.topic){I(Error("Channel topic not set"));return}let C=Q??this.makeRef(),Y=[this.joinRef,C,this.topic,A,B],G=setTimeout(()=>{this.pendingReplies.delete(C),I(Error(`Timeout waiting for reply to ${A}`))},1e4);this.pendingReplies.set(C,{resolve:E,reject:I,timeout:G}),this.log("Sending",A,B),this.ws.send(JSON.stringify(Y))})}handleMessage(A){try{let[B,Q,E,I,C]=JSON.parse(A);if(this.log("Received",I,C),I==="phx_reply"&&Q){let Y=this.pendingReplies.get(Q);if(Y){clearTimeout(Y.timeout),this.pendingReplies.delete(Q);let G=C;if(G.status==="ok")Y.resolve(G.response??{});else if(G.response&&typeof G.response==="object"&&"code"in G.response)Y.reject(G.response);else{let Z=this.buildErrorMessage(G.status,G.response);Y.reject(Error(Z))}}return}if(I==="phx_error"){let Y=Error("Channel error");this.setChannelState("error"),this.channelCallbacks.onError?.(Y);return}if(I==="phx_close"){this.setChannelState("closed"),this.channelCallbacks.onLeave?.();return}if(I==="score_update"){this.channelCallbacks.onScoreUpdate?.(C);return}if(I==="action"){this.channelCallbacks.onAction?.(C);return}this.channelCallbacks.onMessage?.(I,C)}catch(B){this.log("Error parsing message",B)}}handleClose(){this.stopHeartbeat(),this.setState("disconnected"),this.setChannelState("closed");for(let[A,B]of this.pendingReplies)clearTimeout(B.timeout),B.reject(Error("Connection closed"));this.pendingReplies.clear(),this.scheduleReconnect()}handleError(A){this.setState("error"),this.onError?.(A)}startHeartbeat(){this.stopHeartbeat(),this.heartbeatTimer=setInterval(()=>{if(this.ws&&this.ws.readyState===WebSocket.OPEN){let A=[null,this.makeRef(),"phoenix","heartbeat",{}];if(this.ws.send(JSON.stringify(A)),this.channelState==="joined")this.push("heartbeat",{}).then((B)=>{if(B.bot_score!==void 0)this.channelCallbacks.onScoreUpdate?.({bot_score:B.bot_score,classification:B.classification,triggered_rules:[],event_count:0})}).catch(()=>{})}},this.heartbeatInterval)}stopHeartbeat(){if(this.heartbeatTimer)clearInterval(this.heartbeatTimer),this.heartbeatTimer=null}scheduleReconnect(){if(this.reconnectCount>=this.reconnectAttempts){this.log("Max reconnect attempts reached");return}let A=this.reconnectDelay(this.reconnectCount);this.reconnectCount++,this.log(`Scheduling reconnect attempt ${this.reconnectCount} in ${A}ms`),this.reconnectTimer=setTimeout(()=>{this.connect().catch((B)=>{this.log("Reconnect failed",B)})},A)}stopReconnect(){if(this.reconnectTimer)clearTimeout(this.reconnectTimer),this.reconnectTimer=null;this.reconnectCount=0}setState(A){if(this.state!==A)this.state=A,this.onConnectionChange?.(A)}setChannelState(A){this.channelState=A}buildErrorMessage(A,B){if(B){if(typeof B.reason==="string")return`Channel error: ${B.reason}`;if(Object.keys(B).length>0)return`Channel error (${A??"error"}): ${JSON.stringify(B)}`}return A??"Unknown error"}log(...A){if(this.debug);}}class o{config;isReady=!1;hasScore=!1;hasFormScore=!1;currentScore=null;pendingSubmissions=[];pendingRequests=[];protectedForms=new Set;releasingForms=new Set;loadingOverlay=null;formObserver=null;startTime;originalFetch=null;originalXHROpen=null;originalXHRSend=null;constructor(A={}){if(this.startTime=performance.now(),this.config={mode:A.mode??"none",minTimeBeforeSubmit:A.minTimeBeforeSubmit??500,maxHoldTime:A.maxHoldTime??5000,showLoadingUI:A.showLoadingUI??!0,loadingMessage:A.loadingMessage??"Please wait...",onHold:A.onHold,onRelease:A.onRelease,onBlock:A.onBlock,flushAndWaitForScore:A.flushAndWaitForScore},this.config.mode!=="none")this.setup()}setup(){if(this.config.mode==="auto")this.interceptFetch(),this.interceptXHR();let A=()=>{document.querySelectorAll("form").forEach((B)=>{this.protectForm(B)}),this.formObserver=new MutationObserver((B)=>{B.forEach((Q)=>{Q.addedNodes.forEach((E)=>{if(E instanceof HTMLFormElement)this.protectForm(E);if(E instanceof HTMLElement)E.querySelectorAll("form").forEach((I)=>{this.protectForm(I)})})})}),this.formObserver.observe(document.body,{childList:!0,subtree:!0})};if(document.body)A();else document.addEventListener("DOMContentLoaded",A,{once:!0})}isFormLikeRequest(A,B){if((B?.method?.toUpperCase()||"GET")!=="POST")return!1;try{if((typeof A==="string"?new URL(A,window.location.origin):A instanceof URL?A:new URL(A.url)).origin!==window.location.origin)return!1}catch{return!1}let E=B?.headers instanceof Headers?B.headers.get("content-type"):typeof B?.headers==="object"&&B.headers!==null?B.headers["content-type"]||B.headers["Content-Type"]:null;if(E){let I=E.toLowerCase();if(I.includes("application/x-www-form-urlencoded")||I.includes("multipart/form-data")||I.includes("application/json"))return!0;return!1}if(B?.body)return!0;return!1}interceptFetch(){this.originalFetch=window.fetch.bind(window);let A=this;window.fetch=async function(B,Q){if(!A.isFormLikeRequest(B,Q))return A.originalFetch(B,Q);if(A.hasScore)return A.originalFetch(B,Q);return new Promise((E,I)=>{let C={resolve:E,reject:I,execute:()=>A.originalFetch(B,Q),timestamp:performance.now()};if(A.pendingRequests.push(C),A.config.showLoadingUI&&A.pendingRequests.length===1)A.showLoading(document.createElement("form"));if(setTimeout(()=>{if(A.pendingRequests.includes(C))A.releaseRequest(C)},A.config.maxHoldTime),A.hasScore)A.releaseRequest(C)})}}interceptXHR(){this.originalXHROpen=XMLHttpRequest.prototype.open,this.originalXHRSend=XMLHttpRequest.prototype.send;let A=this;XMLHttpRequest.prototype.open=function(B,Q,E=!0,I,C){let Y=this;return Y._bsMethod=B.toUpperCase(),Y._bsUrl=Q.toString(),A.originalXHROpen.call(this,B,Q,E,I,C)},XMLHttpRequest.prototype.send=function(B){let Q=this,E=Q._bsMethod||"GET",I=Q._bsUrl||"";if(E!=="POST")return A.originalXHRSend.call(this,B);try{if(new URL(I,window.location.origin).origin!==window.location.origin)return A.originalXHRSend.call(this,B)}catch{return A.originalXHRSend.call(this,B)}if(A.hasScore)return A.originalXHRSend.call(this,B);let C=performance.now(),Y=()=>{if(A.hasScore){if(A.config.showLoadingUI)A.hideLoading();A.originalXHRSend.call(Q,B)}else if(performance.now()-C>=A.config.maxHoldTime){if(A.config.showLoadingUI)A.hideLoading();A.originalXHRSend.call(Q,B)}else setTimeout(Y,50)};if(A.config.showLoadingUI)A.showLoading(document.createElement("form"));Y()}}releaseRequest(A){let B=this.pendingRequests.indexOf(A);if(B===-1)return;if(this.pendingRequests.splice(B,1),this.pendingRequests.length===0&&this.config.showLoadingUI)this.hideLoading();A.execute().then(A.resolve).catch(A.reject)}protectForm(A){if(this.protectedForms.has(A))return;this.protectedForms.add(A),A.addEventListener("submit",(B)=>this.handleSubmit(B,A),{capture:!0})}handleSubmit(A,B){if(this.releasingForms.has(B)){this.releasingForms.delete(B);return}let E=performance.now()-this.startTime;switch(O().markFirstSubmitAttempt(this.hasScore),this.config.mode){case"holdUntilReady":if(!this.hasScore)A.preventDefault(),A.stopPropagation(),this.holdSubmission(B,A);break;case"holdUntilFormScored":A.preventDefault(),A.stopPropagation(),this.holdAndScoreSubmission(B,A);break;case"blockInstant":if(E<this.config.minTimeBeforeSubmit)A.preventDefault(),A.stopPropagation(),this.config.onBlock?.(B,"instant_submission");break;case"challengeFirst":if(!this.hasScore)A.preventDefault(),A.stopPropagation(),this.holdSubmission(B,A);break;case"none":default:break}}holdSubmission(A,B){if(this.config.onHold?.(A),this.config.showLoadingUI)this.showLoading(A);let Q={form:A,event:B,timestamp:performance.now(),resolver:()=>{},rejecter:()=>{}},E=new Promise((I,C)=>{Q.resolver=I,Q.rejecter=C});if(this.pendingSubmissions.push(Q),setTimeout(()=>{if(this.pendingSubmissions.includes(Q))this.releaseSubmission(Q,!1)},this.config.maxHoldTime),this.hasScore)this.releaseSubmission(Q,!1);E.catch(()=>{})}async holdAndScoreSubmission(A,B){if(this.config.onHold?.(A),this.config.showLoadingUI)this.showLoading(A);let Q=performance.now();try{if(!this.config.flushAndWaitForScore){this.submitForm(A);return}let E=this.config.flushAndWaitForScore(),I=new Promise((G)=>{setTimeout(()=>G(null),this.config.maxHoldTime)}),C=await Promise.race([E,I]),Y=performance.now()-Q;if(C===null);else this.currentScore=C,this.hasFormScore=!0;if(this.config.showLoadingUI)this.hideLoading();this.config.onRelease?.(A,!1),this.submitForm(A)}catch(E){if(this.config.showLoadingUI)this.hideLoading();this.config.onRelease?.(A,!1),this.submitForm(A)}}submitForm(A){if(this.releasingForms.add(A),A.requestSubmit)A.requestSubmit();else A.submit()}releaseSubmission(A,B){let Q=this.pendingSubmissions.indexOf(A);if(Q===-1)return;if(this.pendingSubmissions.splice(Q,1),this.config.showLoadingUI)this.hideLoading();if(this.config.onRelease?.(A.form,B),!B)if(A.resolver(),A.form.requestSubmit)A.form.requestSubmit();else A.form.submit();else A.rejecter("blocked")}showLoading(A){if(this.loadingOverlay)return;this.loadingOverlay=document.createElement("div"),this.loadingOverlay.innerHTML=`
44
+ <div style="
45
+ position: fixed;
46
+ top: 0;
47
+ left: 0;
48
+ right: 0;
49
+ bottom: 0;
50
+ background: rgba(0, 0, 0, 0.5);
51
+ display: flex;
52
+ align-items: center;
53
+ justify-content: center;
54
+ z-index: 999999;
55
+ ">
56
+ <div style="
57
+ background: white;
58
+ padding: 24px 48px;
59
+ border-radius: 8px;
60
+ text-align: center;
61
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
62
+ ">
63
+ <div style="
64
+ width: 32px;
65
+ height: 32px;
66
+ border: 3px solid #e5e7eb;
67
+ border-top-color: #3b82f6;
68
+ border-radius: 50%;
69
+ margin: 0 auto 16px;
70
+ animation: bs-spin 0.8s linear infinite;
71
+ "></div>
72
+ <div style="color: #374151; font-size: 14px;">
73
+ ${this.config.loadingMessage}
74
+ </div>
75
+ </div>
76
+ </div>
77
+ <style>
78
+ @keyframes bs-spin {
79
+ to { transform: rotate(360deg); }
80
+ }
81
+ </style>
82
+ `,document.body.appendChild(this.loadingOverlay)}hideLoading(){if(this.loadingOverlay)this.loadingOverlay.remove(),this.loadingOverlay=null}notifyReady(A){this.isReady=!0,this.hasScore=!0,this.currentScore=A,[...this.pendingSubmissions].forEach((E)=>{this.releaseSubmission(E,!1)}),[...this.pendingRequests].forEach((E)=>{this.releaseRequest(E)}),this.hideLoading()}blockAllPending(A){[...this.pendingSubmissions].forEach((Q)=>{this.config.onBlock?.(Q.form,A),this.releaseSubmission(Q,!0)})}getStatus(){return{mode:this.config.mode,isReady:this.isReady,hasScore:this.hasScore,pendingCount:this.pendingSubmissions.length,protectedFormCount:this.protectedForms.size}}waitUntilReady(){if(this.hasScore)return Promise.resolve({score:this.currentScore,timedOut:!1});return new Promise((A)=>{let B=performance.now(),Q=()=>{if(this.hasScore){A({score:this.currentScore,timedOut:!1});return}if(performance.now()-B>=this.config.maxHoldTime){A({score:null,timedOut:!0});return}setTimeout(Q,50)};Q()})}withProtection(A){return async(...B)=>{let Q=performance.now()-this.startTime;if(O().markFirstSubmitAttempt(this.hasScore),this.config.mode==="blockInstant"&&Q<this.config.minTimeBeforeSubmit)throw this.config.onBlock?.(document.createElement("form"),"instant_submission"),Error("Submission blocked: too fast");if(this.config.mode==="holdUntilReady"&&!this.hasScore){if(this.config.showLoadingUI)this.showLoading(document.createElement("form"));let{timedOut:E}=await this.waitUntilReady();if(this.config.showLoadingUI)this.hideLoading()}return A(...B)}}protectedFetch(){return this.withProtection(async(A,B)=>{return fetch(A,B)})}setMode(A){if(this.config.mode=A,A==="none")[...this.pendingSubmissions].forEach((Q)=>this.releaseSubmission(Q,!1))}setMaxHoldTime(A){this.config.maxHoldTime=A}canSubmit(){let A=performance.now()-this.startTime;if(this.config.mode==="blockInstant"&&A<this.config.minTimeBeforeSubmit)return{allowed:!1,reason:"too_fast",score:this.currentScore};if(this.config.mode==="holdUntilReady"&&!this.hasScore)return{allowed:!1,reason:"waiting_for_score",score:null};return{allowed:!0,score:this.currentScore}}destroy(){if(this.formObserver)this.formObserver.disconnect(),this.formObserver=null;if(this.originalFetch)window.fetch=this.originalFetch,this.originalFetch=null;if(this.originalXHROpen)XMLHttpRequest.prototype.open=this.originalXHROpen,this.originalXHROpen=null;if(this.originalXHRSend)XMLHttpRequest.prototype.send=this.originalXHRSend,this.originalXHRSend=null;this.hideLoading(),this.pendingSubmissions=[],this.pendingRequests=[],this.protectedForms.clear()}}var KA={suspicious:40,bot:70},q={name:"_bsid",riskName:"_bsrisk",path:"/",sameSite:"Strict"};function WA(A){if(!A)return null;if(A===!0)return{...q};return{...q,...A}}function yA(A){if(A>=KA.bot)return"bot";if(A>=KA.suspicious)return"suspicious";return"human"}class r{config;sessionIdGetter;sessionCookieSet=!1;currentRiskTier=null;constructor(A,B){this.config={...q,...A},this.sessionIdGetter=B}buildCookieString(A,B){let Q=this.config.path||q.path,E=this.config.sameSite||q.sameSite,I=this.config.secure??location.protocol==="https:",C=[`${encodeURIComponent(A)}=${encodeURIComponent(B)}`,`Path=${Q}`,`SameSite=${E}`];if(I||E==="None")C.push("Secure");return C.join("; ")}deleteCookie(A){let B=this.config.path||q.path;document.cookie=`${encodeURIComponent(A)}=; Path=${B}; Max-Age=0`}setSessionCookie(){if(this.sessionCookieSet)return;let A=this.sessionIdGetter();if(!A)return;let B=this.config.name||q.name;document.cookie=this.buildCookieString(B,A),this.sessionCookieSet=!0}updateRiskTier(A){let B=yA(A);if(B===this.currentRiskTier)return!1;let Q=this.config.riskName||q.riskName;document.cookie=this.buildCookieString(Q,B);let E=this.currentRiskTier;return this.currentRiskTier=B,!0}removeCookies(){let A=this.config.name||q.name,B=this.config.riskName||q.riskName;if(this.sessionCookieSet)this.deleteCookie(A),this.sessionCookieSet=!1;if(this.currentRiskTier!==null)this.deleteCookie(B),this.currentRiskTier=null}setCookie(){this.setSessionCookie()}removeCookie(){this.removeCookies()}isSessionCookieSet(){return this.sessionCookieSet}getCurrentRiskTier(){return this.currentRiskTier}getSessionCookieName(){return this.config.name||q.name}getRiskCookieName(){return this.config.riskName||q.riskName}}var F={name:"X-BotSigged-ID"};function qA(A){if(!A)return null;if(A===!0)return{...F};return{...F,...A}}class e{config;sessionIdGetter;started=!1;originalFetch=null;originalXHROpen=null;originalXHRSend=null;originalXHRSetRequestHeader=null;xhrInjectionMap=new WeakMap;constructor(A,B){this.config={...F,...A},this.sessionIdGetter=B}start(){if(this.started)return;this.started=!0,this.patchFetch(),this.patchXHR()}stop(){if(!this.started)return;if(this.originalFetch)window.fetch=this.originalFetch,this.originalFetch=null;if(this.originalXHROpen)XMLHttpRequest.prototype.open=this.originalXHROpen,this.originalXHROpen=null;if(this.originalXHRSend)XMLHttpRequest.prototype.send=this.originalXHRSend,this.originalXHRSend=null;if(this.originalXHRSetRequestHeader)XMLHttpRequest.prototype.setRequestHeader=this.originalXHRSetRequestHeader,this.originalXHRSetRequestHeader=null;this.started=!1}isSameOrigin(A){try{let B;if(A instanceof Request)B=new URL(A.url,window.location.origin);else if(A instanceof URL)B=A;else B=new URL(A,window.location.origin);return B.origin===window.location.origin}catch{return!0}}patchFetch(){this.originalFetch=window.fetch.bind(window);let A=this,B=this.config.name||F.name;window.fetch=function(Q,E){if(!A.isSameOrigin(Q))return A.originalFetch(Q,E);let I=A.sessionIdGetter();if(!I)return A.originalFetch(Q,E);let C=new Headers(E?.headers);if(!C.has(B))C.set(B,I);return A.originalFetch(Q,{...E,headers:C})}}patchXHR(){this.originalXHROpen=XMLHttpRequest.prototype.open,this.originalXHRSend=XMLHttpRequest.prototype.send,this.originalXHRSetRequestHeader=XMLHttpRequest.prototype.setRequestHeader;let A=this,B=this.config.name||F.name;XMLHttpRequest.prototype.open=function(Q,E,I=!0,C,Y){let G=A.isSameOrigin(E);return A.xhrInjectionMap.set(this,G),A.originalXHROpen.call(this,Q,E,I,C,Y)},XMLHttpRequest.prototype.send=function(Q){if(A.xhrInjectionMap.get(this)){let E=A.sessionIdGetter();if(E)try{A.originalXHRSetRequestHeader.call(this,B,E)}catch{}}return A.originalXHRSend.call(this,Q)}}getHeaderName(){return this.config.name||F.name}isStarted(){return this.started}}var L={selector:"form",inputName:"_bsid"};function VA(A){if(!A)return null;if(A===!0)return{...L};return{...L,...A}}class AA{config;sessionIdGetter;observer=null;started=!1;constructor(A,B){this.config={...L,...A},this.sessionIdGetter=B}start(){if(this.started)return;this.started=!0;let A=()=>{this.setupExistingForms(),this.setupObserver()};if(document.readyState==="loading")document.addEventListener("DOMContentLoaded",A,{once:!0});else A()}stop(){if(!this.started)return;if(this.observer)this.observer.disconnect(),this.observer=null;let A=this.config.selector||L.selector,B=this.config.inputName||L.inputName;document.querySelectorAll(`${A}[data-bs-inject-setup]`).forEach((Q)=>{if(Q instanceof HTMLFormElement)Q.removeEventListener("submit",this.handleSubmit,{capture:!0});Q.removeAttribute("data-bs-inject-setup");let E=Q.querySelector(`input[name="${B}"][data-bs-injected]`);if(E)E.remove()}),this.started=!1}setupExistingForms(){let A=this.config.selector||L.selector;document.querySelectorAll(A).forEach((B)=>{if(B instanceof HTMLFormElement)this.setupForm(B)})}setupObserver(){if(!document.body)return;let A=this.config.selector||L.selector;this.observer=new MutationObserver((B)=>{B.forEach((Q)=>{Q.addedNodes.forEach((E)=>{if(E instanceof HTMLFormElement&&E.matches(A))this.setupForm(E);if(E instanceof HTMLElement)E.querySelectorAll(A).forEach((I)=>{if(I instanceof HTMLFormElement)this.setupForm(I)})})})}),this.observer.observe(document.body,{childList:!0,subtree:!0})}setupForm(A){if(A.hasAttribute("data-bs-inject-setup"))return;A.setAttribute("data-bs-inject-setup","true"),A.addEventListener("submit",this.handleSubmit,{capture:!0})}handleSubmit=(A)=>{let B=A.currentTarget;this.injectInput(B)};injectInput(A){let B=this.config.inputName||L.inputName,Q=A.querySelector(`input[name="${B}"]`);if(Q){if(Q.hasAttribute("data-bs-injected"))Q.value=this.sessionIdGetter();return}let E=document.createElement("input");E.type="hidden",E.name=B,E.value=this.sessionIdGetter(),E.setAttribute("data-bs-injected","true"),A.appendChild(E)}getConfig(){return{...this.config}}isStarted(){return this.started}}class _{config;mouseCollector;scrollCollector;formCollector;browserCollector;fingerprintGenerator;socket=null;sessionId;sequenceNumber=0;isRunning=!1;sendTimer=null;fingerprint=null;browserSignal=null;lastScore=null;hasSentInitial=!1;boundBeforeUnload=null;boundVisibilityChange=null;hashModule=null;formBlocked=!1;formObserver=null;highScoreTriggeredLevels=new Set;challengeManager=null;challengeManagerPromise=null;formProtectionManager=null;formSubmissionStatus="no_submission";cookieManager=null;headerInjector=null;formInjector=null;serverConfig=null;connectionState="disconnected";reconnectTimer=null;readyPromise;readyResolver=null;constructor(A){if(J.markConstructorStart(),!A.apiKey)throw Error("BotSigged: apiKey is required");if(this.config=JA(A),this.sessionId=this.generateSessionId(),this.readyPromise=new Promise((I)=>{this.readyResolver=I}),this.mouseCollector=new p({sampleRate:this.config.mouseSampleRate,maxBufferSize:this.config.maxBufferSize}),this.scrollCollector=new m({maxBufferSize:Math.floor(this.config.maxBufferSize/3)}),this.formCollector=new d({maxKeyEvents:this.config.maxBufferSize,onSubmit:()=>this.handleFormSubmit()}),this.browserCollector=new f,this.fingerprintGenerator=new n,this.config.hashVerification.enabled)this.initializeHashModule();if(this.config.action==="challenge"||this.config.challenge.enabled)this.challengeManagerPromise=this.initializeChallengeManager();if(this.config.formProtection.mode!=="none")this.formProtectionManager=new o({mode:this.config.formProtection.mode,minTimeBeforeSubmit:this.config.formProtection.minTimeBeforeSubmit,maxHoldTime:this.config.formProtection.maxHoldTime,showLoadingUI:this.config.formProtection.showLoadingUI,loadingMessage:this.config.formProtection.loadingMessage,onHold:(I)=>{this.updateFormStatus("challenged"),this.config.formProtection.onHold?.(I)},onRelease:(I,C)=>{if(!C)this.updateFormStatus("completed");this.config.formProtection.onRelease?.(I,C)},onBlock:(I,C)=>{this.updateFormStatus("blocked"),this.config.formProtection.onBlock?.(I,C)},flushAndWaitForScore:()=>this.sendSignalAndGetScore()}),this.log("Form protection enabled:",this.config.formProtection.mode);else this.log("Form protection disabled (mode='none')");let B=WA(this.config.cookie);if(B)this.cookieManager=new r(B,()=>this.sessionId),this.log("Cookie manager enabled:",B.name);let Q=qA(this.config.headers);if(Q)this.headerInjector=new e(Q,()=>this.sessionId),this.headerInjector.start(),this.log("Header injector enabled:",Q.name);let E=VA(this.config.formInject);if(E)this.formInjector=new AA(E,()=>this.sessionId),this.formInjector.start(),this.log("Form injector enabled:",E.inputName);if(this.config.autoStart)if(document.readyState==="loading")document.addEventListener("DOMContentLoaded",()=>this.start());else this.start();J.markConstructorEnd(),this.log("Constructor completed in",(J.getTimings().constructorEnd??0)-(J.getTimings().constructorStart??0),"ms")}async initializeHashModule(){try{let{initHashModule:A}=await Promise.resolve().then(() => (b(),zA));this.hashModule=await A({preferWasm:this.config.hashVerification.preferWasm,onWasmLoaded:()=>{this.log("WASM hash module loaded"),this.config.hashVerification.onWasmLoaded?.()},onFallback:(B)=>{this.log("Using JS hash fallback:",B),this.config.hashVerification.onWasmFallback?.(B)}})}catch(A){this.log("Failed to initialize hash module",A)}}async initializeChallengeManager(){try{let{ChallengeManager:A}=await Promise.resolve().then(() => ($A(),HA));this.challengeManager=new A(this.config.challenge,this.config.debug),this.log("Challenge manager loaded")}catch(A){this.log("Failed to initialize challenge manager",A)}}async start(){if(this.isRunning){this.log("Already running");return}J.markStartCalled(),this.log("Starting BotSigged SDK"),this.isRunning=!0,this.connectionState="connecting";try{this.browserSignal=this.browserCollector.collect(),J.markFormCollectorStart(),this.mouseCollector.start(),this.scrollCollector.start(),this.formCollector.start(),J.markFormCollectorReady(),this.log("Collectors started in",(J.getTimings().formCollectorReady??0)-(J.getTimings().formCollectorStart??0),"ms"),J.markFingerprintStart(),J.markWsConnectStart();let[A]=await Promise.all([this.fingerprintGenerator.generate(),this.connectWithRetry()]);this.fingerprint=A,J.markFingerprintEnd(),this.log("Fingerprint generated in",(J.getTimings().fingerprintEnd??0)-(J.getTimings().fingerprintStart??0),"ms"),await this.joinChannel(),this.connectionState="connected",this.readyResolver?.(),J.markSdkReady(),this.startSendInterval(),this.registerBeforeUnload();let B=J.getSummary();if(this.log("SDK started successfully"),this.log("Total startup time:",B.totalStartupMs,"ms"),this.log("Time to first score:",B.timeToFirstScoreMs,"ms"),this.log("Vulnerability window:",B.vulnerabilityWindowMs,"ms"),this.config.debug)J.logSummary()}catch(A){let B=A instanceof Error?A:Error(String(A));this.log("Failed to start",B),this.handleConnectionFailure(B)}}async stop(){if(!this.isRunning)return;if(this.log("Stopping BotSigged SDK"),this.formProtectionManager)this.formProtectionManager.destroy(),this.formProtectionManager=null;if(this.cookieManager)this.cookieManager.removeCookies(),this.cookieManager=null;if(this.headerInjector)this.headerInjector.stop(),this.headerInjector=null;if(this.formInjector)this.formInjector.stop(),this.formInjector=null;if(this.formObserver)this.formObserver.disconnect(),this.formObserver=null;this.unregisterBeforeUnload(),this.mouseCollector.stop(),this.scrollCollector.stop(),this.formCollector.stop(),this.stopSendInterval(),await this.sendSignal(),await this.disconnect(),this.isRunning=!1,this.log("SDK stopped")}async sendSignal(){if(!this.socket?.isReady()){this.log("Cannot send signal: not connected");return}let A=this.buildPayload(),B=A.seq;this.log("Sending signal seq:",B),J.markSignalSent(B);try{let Q=await this.socket.sendSignal(A);J.markSignalResponseReceived(B);let E=J.getTimings().signalRoundtrips||[],I=E[E.length-1];if(I)this.log("Signal roundtrip:",I.roundtripMs,"ms");if(Q.bot_score!==void 0){let C={bot_score:Q.bot_score,classification:Q.classification||"unknown",triggered_rules:Q.triggered_rules||[]};this.lastScore=C,this.config.onScoreUpdate?.(C),this.handleScoreUpdate(C)}this.mouseCollector.flush(),this.scrollCollector.flush(),this.formCollector.flush(),this.hasSentInitial=!0}catch(Q){let E=Q instanceof Error?Q:Error(String(Q));this.log("Failed to send signal",E),this.config.onError?.(E)}}async sendSignalAndGetScore(){if(!this.socket?.isReady())return this.log("Cannot send signal: not connected"),null;let A=this.buildPayload(),B=A.seq;this.log("Sending signal for form scoring, seq:",B);try{let Q=await this.socket.sendSignal(A);if(Q.bot_score!==void 0){let E={bot_score:Q.bot_score,classification:Q.classification||"unknown",triggered_rules:Q.triggered_rules||[]};return this.lastScore=E,this.config.onScoreUpdate?.(E),this.handleScoreUpdate(E),this.mouseCollector.flush(),this.scrollCollector.flush(),this.formCollector.flush(),this.hasSentInitial=!0,E.bot_score}return this.mouseCollector.flush(),this.scrollCollector.flush(),this.formCollector.flush(),this.hasSentInitial=!0,null}catch(Q){let E=Q instanceof Error?Q:Error(String(Q));return this.log("Failed to send signal for form scoring",E),this.config.onError?.(E),null}}getSessionId(){return this.sessionId}getFingerprint(){return this.fingerprint}getFormSubmissionStatus(){return this.formSubmissionStatus}getLastScore(){return this.lastScore}isConnected(){return this.socket?.isReady()??!1}whenReady(){if(this.connectionState==="connected")return Promise.resolve();return this.readyPromise}getConnectionState(){return this.connectionState}getServerConfig(){return this.serverConfig}async identify(A){let{accountId:B}=A;if(!B||typeof B!=="string")throw Error("BotSigged: accountId is required and must be a string");if(B.length>255)throw Error("BotSigged: accountId must be 255 characters or less");this.log("Identifying account:",B),await this.whenReady();try{let Q=await this.socket.sendEvent("identify",{account_id:B,timestamp:Date.now()});if(Q.identified)this.log("Account identified successfully");else throw Error(Q.reason?.toString()||"Failed to identify account")}catch(Q){let E=Q instanceof Error?Q:Error(String(Q));throw this.log("Failed to identify account:",E),this.config.onError?.(E),E}}isDegraded(){return this.connectionState==="degraded"||this.connectionState==="failed"}getCurrentSignals(){return{mouse:this.mouseCollector.getSignal(),scroll:this.scrollCollector.getSignal(),form:this.formCollector.getSignal(),browser:this.browserSignal}}getBufferSizes(){return{mouse:this.mouseCollector.getBufferSize(),scroll:this.scrollCollector.getBufferSize(),form:this.formCollector.getBufferSize()}}resetSignals(){this.mouseCollector.reset(),this.scrollCollector.reset(),this.formCollector.reset(),this.browserCollector.reset(),this.sequenceNumber=0,this.hasSentInitial=!1}async connectSocket(){this.socket=new t({endpoint:this.config.endpoint,apiKey:this.config.apiKey,debug:this.config.debug,onConnectionChange:(A)=>{this.config.onConnectionChange?.(A==="connected")},onError:(A)=>{this.config.onError?.(A)}}),await this.socket.connect(),J.markWsConnectEnd(),this.log("WebSocket connected in",(J.getTimings().wsConnectEnd??0)-(J.getTimings().wsConnectStart??0),"ms")}async connectWithRetry(){let B=[1000,2000,4000];for(let Q=0;Q<3;Q++)try{await this.connectSocket();return}catch(E){if(this.log(`Connection attempt ${Q+1} failed:`,E),Q<2)await this.sleep(B[Q]);else throw E}}sleep(A){return new Promise((B)=>setTimeout(B,A))}handleConnectionFailure(A){this.connectionState="failed";let B=this.config.fallbackMode||"degraded";switch(this.log("Connection failed, applying fallback mode:",B),B){case"open":if(this.connectionState="degraded",this.formProtectionManager)this.formProtectionManager.setMode("none"),this.formProtectionManager.notifyReady(0);break;case"closed":this.blockFormsUntilConnected(),this.scheduleReconnect();break;case"cached":let Q=this.loadCachedConfig();if(Q)this.applyServerConfig(Q),this.connectionState="degraded";else this.applyFallbackConfig();this.scheduleReconnect();break;case"degraded":default:this.applyFallbackConfig(),this.connectionState="degraded",this.scheduleReconnect();break}this.config.onError?.(A),this.config.onConnectionChange?.(!1)}applyFallbackConfig(){if(this.log("Applying fallback config"),this.serverConfig=GA,this.formProtectionManager&&this.serverConfig.form_protection_mode)this.formProtectionManager.setMode(this.serverConfig.form_protection_mode);this.config.onServerConfig?.(this.serverConfig,"fallback")}blockFormsUntilConnected(){if(this.formProtectionManager)this.formProtectionManager.setMode("holdUntilReady"),this.formProtectionManager.setMaxHoldTime(30000)}scheduleReconnect(){if(this.reconnectTimer)clearTimeout(this.reconnectTimer);this.reconnectTimer=setTimeout(()=>{this.attemptReconnect()},5000)}async attemptReconnect(){this.log("Attempting reconnection..."),this.connectionState="connecting";try{if(await this.connectWithRetry(),!this.fingerprint)this.fingerprint=await this.fingerprintGenerator.generate();if(await this.joinChannel(),this.connectionState="connected",this.readyResolver?.(),this.log("Reconnection successful"),!this.sendTimer)this.startSendInterval()}catch(A){this.log("Reconnection failed:",A),this.connectionState="failed"}}cacheServerConfig(A){try{localStorage.setItem(`botsigged_config_${this.config.apiKey}`,JSON.stringify({config:A,timestamp:Date.now()}))}catch{}}loadCachedConfig(){try{let A=localStorage.getItem(`botsigged_config_${this.config.apiKey}`);if(!A)return null;let{config:B,timestamp:Q}=JSON.parse(A);if(Date.now()-Q>86400000)return localStorage.removeItem(`botsigged_config_${this.config.apiKey}`),null;return B}catch{return null}}applyServerConfig(A){if(this.log("Applying server config:",A),this.serverConfig=A,this.formProtectionManager&&A.form_protection_mode)this.formProtectionManager.setMode(A.form_protection_mode);if(A.action&&A.action!=="none")this.applyServerAction(A.action,A.challenge);this.cacheServerConfig(A),this.config.onServerConfig?.(A,"server")}async applyServerAction(A,B){switch(this.log("Applying server action:",A),A){case"block":if(!this.formBlocked)this.blockForms();break;case"challenge":if(!this.challengeManager&&!this.challengeManagerPromise)this.log("Lazily loading challenge manager for server-requested challenge"),this.challengeManagerPromise=this.initializeChallengeManager();if(this.challengeManagerPromise)await this.challengeManagerPromise;if(this.challengeManager){let Q=B?.difficulty?.bot??16,E=Q>=18?"critical":Q>=16?"high":"medium";this.challengeManager.blockFormsUntilSolved(E)}else this.log("Challenge requested but challenge manager failed to load");break;case"flag":this.log("Session flagged by server");break;case"none":default:break}}handleServerAction(A){this.log("Received server action:",A),this.config.onServerAction?.(A);let B=A.challenge?{difficulty:{suspicious:A.challenge.difficulty,bot:A.challenge.difficulty},timeout_ms:A.challenge.timeout_ms}:void 0;this.applyServerAction(A.type,B)}async joinChannel(){if(!this.socket)throw Error("WebSocket not initialized");J.markChannelJoinStart();let A;try{A=await this.socket.joinChannel(this.sessionId,this.fingerprint,this.getSessionData(),this.browserSignal,{onScoreUpdate:(B)=>{this.lastScore=B,this.config.onScoreUpdate?.(B),this.handleScoreUpdate(B)},onError:(B)=>{this.config.onError?.(B)},onAction:(B)=>{this.handleServerAction(B)}},this.config.accountId)}catch(B){if(YA(B)){if(this.log("Usage limit exceeded:",B),this.config.onUsageLimitExceeded)this.config.onUsageLimitExceeded(B);else this.config.onError?.(Error(`Usage limit exceeded: ${B.current_usage}/${B.limit} verifications (${B.plan_name} plan). Please upgrade your plan.`));return}throw B}if(J.markChannelJoinEnd(),this.log("Channel joined in",(J.getTimings().channelJoinEnd??0)-(J.getTimings().channelJoinStart??0),"ms"),A.config){let B=A.config;this.applyServerConfig(B)}if(A.initial_score!==void 0){J.markInitialScoreReceived();let B={bot_score:A.initial_score,classification:A.classification||"unknown",triggered_rules:A.triggered_rules||[]};if(this.lastScore=B,this.config.onScoreUpdate?.(B),this.handleScoreUpdate(B),this.formProtectionManager)this.formProtectionManager.notifyReady(B.bot_score);if(this.cookieManager)this.cookieManager.setCookie();this.log("Initial score received:",B.bot_score,"in",(J.getTimings().initialScoreReceived??0)-(J.getTimings().startCalled??0),"ms from start")}}handleScoreUpdate(A){if(this.cookieManager)this.cookieManager.updateRiskTier(A.bot_score);let B=this.getBotScoreLevel(A.bot_score),Q=A.bot_score>=this.config.actionThreshold;if(this.shouldTriggerAlert(B)){let E={score:A.bot_score,level:B,scoreUpdate:A,sessionId:this.sessionId,fingerprintHash:this.fingerprint?.hash};if(Q&&!this.highScoreTriggeredLevels.has(B))this.executeAction(E);this.config.onHighBotScore?.(E),this.highScoreTriggeredLevels.add(B)}}getBotScoreLevel(A){let B=this.config.botScoreThresholds;if(A>=B.critical)return"critical";if(A>=B.high)return"high";if(A>=B.medium)return"medium";return"low"}shouldTriggerAlert(A){if(this.highScoreTriggeredLevels.has(A))return!1;let B=["low","medium","high","critical"],Q=this.config.minAlertLevel,E=B.indexOf(A),I=B.indexOf(Q);return E>=I}async executeAction(A){let B=this.config.action;switch(this.log(`Executing action '${B}' for score ${A.score}`),B){case"challenge":if(this.challengeManagerPromise)await this.challengeManagerPromise;if(this.challengeManager)this.challengeManager.blockFormsUntilSolved(A.level);break;case"block":if(!this.formBlocked)this.blockForms();break;case"none":default:break}}blockForms(){if(this.formBlocked)return;this.formBlocked=!0,document.querySelectorAll("form").forEach((A)=>{A.addEventListener("submit",this.blockFormSubmit,!0)}),this.formObserver=new MutationObserver((A)=>{A.forEach((B)=>{B.addedNodes.forEach((Q)=>{if(Q instanceof HTMLFormElement)Q.addEventListener("submit",this.blockFormSubmit,!0);if(Q instanceof HTMLElement)Q.querySelectorAll("form").forEach((E)=>{E.addEventListener("submit",this.blockFormSubmit,!0)})})})}),this.formObserver.observe(document.body,{childList:!0,subtree:!0}),this.log("Forms blocked due to high bot score")}blockFormSubmit=(A)=>{A.preventDefault(),A.stopPropagation(),this.log("Form submission blocked due to high bot score");return};isFormsBlocked(){return this.formBlocked}unblockForms(){if(!this.formBlocked)return;if(this.formObserver)this.formObserver.disconnect(),this.formObserver=null;document.querySelectorAll("form").forEach((A)=>{A.removeEventListener("submit",this.blockFormSubmit,!0)}),this.formBlocked=!1,this.log("Forms unblocked")}getHashModule(){return this.hashModule}createSignature(A){let B=this.config.hashVerification.secret;if(!B)return this.log("Cannot create signature: no secret configured"),null;return createSignature(A,B)}verifySignature(A,B){let Q=this.config.hashVerification.secret;if(!Q)return this.log("Cannot verify signature: no secret configured"),!1;return verifySignature(A,B,Q)}isChallengeSolving(){return this.challengeManager?.isSolving()??!1}isChallengeSolved(){return this.challengeManager?.isSolved()??!1}getPerformanceSummary(){return J.getSummary()}logPerformance(){J.logSummary()}getPerformanceReport(){return J.getReport()}async waitUntilReady(){if(this.lastScore)return{score:this.lastScore.bot_score,timedOut:!1};if(this.formProtectionManager)return this.formProtectionManager.waitUntilReady();return new Promise((A)=>{let B=performance.now(),Q=5000,E=()=>{if(this.lastScore){A({score:this.lastScore.bot_score,timedOut:!1});return}if(performance.now()-B>=5000){A({score:null,timedOut:!0});return}setTimeout(E,50)};E()})}withProtection(A,B={}){let Q=B.blockThreshold??this.config.actionThreshold;return async(...E)=>{let{score:I,timedOut:C}=await this.waitUntilReady();if(J.markFirstSubmitAttempt(I!==null),I!==null&&I>=Q)throw this.log(`Blocking submission: score ${I} >= threshold ${Q}`),Error(`Submission blocked: bot score ${I} exceeds threshold`);if(C)this.log("Warning: submitting without detection score (timed out)");return A(...E)}}protectedFetch(A={}){return this.withProtection(async(B,Q)=>{return fetch(B,Q)},A)}canSubmit(){if(!this.lastScore)return{allowed:!1,reason:"waiting_for_score",score:null};if(this.lastScore.bot_score>=this.config.actionThreshold)return{allowed:!1,reason:"high_bot_score",score:this.lastScore.bot_score};return{allowed:!0,score:this.lastScore.bot_score}}async triggerChallenge(A="high"){if(this.challengeManagerPromise)await this.challengeManagerPromise;if(!this.challengeManager){this.log("Challenge not enabled");return}this.challengeManager.blockFormsUntilSolved(A)}async disconnect(){if(this.socket)await this.socket.leaveChannel(),this.socket.disconnect(),this.socket=null}startSendInterval(){this.stopSendInterval(),this.sendTimer=setInterval(()=>{this.sendSignal()},this.config.sendInterval)}stopSendInterval(){if(this.sendTimer)clearInterval(this.sendTimer),this.sendTimer=null}registerBeforeUnload(){this.boundBeforeUnload=()=>{this.handleBeforeUnload()},this.boundVisibilityChange=()=>{if(document.visibilityState==="hidden")this.handleBeforeUnload()},window.addEventListener("beforeunload",this.boundBeforeUnload),document.addEventListener("visibilitychange",this.boundVisibilityChange)}unregisterBeforeUnload(){if(this.boundBeforeUnload)window.removeEventListener("beforeunload",this.boundBeforeUnload),this.boundBeforeUnload=null;if(this.boundVisibilityChange)document.removeEventListener("visibilitychange",this.boundVisibilityChange),this.boundVisibilityChange=null}handleBeforeUnload(){if(!this.isRunning||!this.socket)return;try{let A=this.buildPayload();if(this.socket.isReady())this.socket.sendSignal(A).catch(()=>{})}catch{}}handleFormSubmit(){if(!this.isRunning)return;if(J.markFirstSubmitAttempt(this.lastScore!==null),this.log("Form submitted, flushing signals via beacon"),this.log("Had score before submit:",this.lastScore!==null),this.updateFormStatus("completed"),!this.sessionId){this.log("No session ID yet, cannot send beacon");return}let A=this.buildPayload();if(!this.sendViaBeacon(A))this.sendSignal().catch((Q)=>{this.log("Failed to flush signals on form submit",Q)});else this.mouseCollector.flush(),this.scrollCollector.flush(),this.formCollector.flush()}sendViaBeacon(A){if(!navigator.sendBeacon)return this.log("sendBeacon not available"),!1;try{let B=new URL(this.config.endpoint),Q=`${B.protocol==="wss:"?"https:":"http:"}//${B.host}/api/signal`,E=JSON.stringify({session_id:this.sessionId,api_key:this.config.apiKey,payload:A,form_status:this.formSubmissionStatus}),I=new Blob([E],{type:"application/json"}),C=navigator.sendBeacon(Q,I);return this.log("Beacon sent:",C),C}catch(B){return this.log("Beacon send failed:",B),!1}}buildPayload(){this.sequenceNumber++;let A={session_id:this.sessionId,seq:this.sequenceNumber,mouse:this.mouseCollector.getSignal(),scroll:this.scrollCollector.getSignal(),form:this.formCollector.getSignal(),timestamp:Date.now()};if(!this.hasSentInitial)A.session=this.getSessionData(),A.fingerprint=this.fingerprint,A.browser=this.browserSignal;return A}getSessionData(){let A=new URL(window.location.href),B={};A.searchParams.forEach((E,I)=>{B[I]=E});let Q=null;if(document.referrer)try{Q=new URL(document.referrer).hostname}catch{}return{url_path:A.pathname,url_params:B,referrer_url:document.referrer||null,referrer_domain:Q,user_agent:navigator.userAgent}}generateSessionId(){if(crypto.randomUUID)return crypto.randomUUID();return"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,(A)=>{let B=Math.random()*16|0;return(A==="x"?B:B&3|8).toString(16)})}updateFormStatus(A){if(this.formSubmissionStatus==="blocked"||this.formSubmissionStatus==="completed"){this.log(`Form status already terminal (${this.formSubmissionStatus}), ignoring ${A}`);return}if(this.formSubmissionStatus==="challenged"&&A!=="completed"){this.log(`Form status is challenged, can only become completed, ignoring ${A}`);return}if(this.formSubmissionStatus=A,this.log(`Form status updated to: ${A}`),this.socket?.isReady())this.socket.sendFormStatus(A).catch((B)=>{this.log("Failed to send form status:",B)})}log(...A){if(this.config.debug);}}var k=null;function QA(A){if(k)return k;return k=new _(A),k}function EA(){return k}async function IA(){if(k)await k.stop(),k=null}var xA=Object.assign(_,{init:QA,getInstance:EA,destroy:IA});if(typeof window<"u")window.BotSigged=xA;})();
@@ -0,0 +1,45 @@
1
+ import{c as V}from"./hash-q46pgar4.js";class U{overlay=null;messageEl=null;progressEl=null;config;constructor(j){this.config=j}show(){if(!this.config.enabled||this.overlay)return;this.overlay=document.createElement("div"),this.overlay.id="botsigged-challenge-overlay",this.overlay.style.cssText=`
2
+ position: fixed;
3
+ top: 0;
4
+ left: 0;
5
+ width: 100%;
6
+ height: 100%;
7
+ background: ${this.config.backgroundColor};
8
+ display: flex;
9
+ flex-direction: column;
10
+ align-items: center;
11
+ justify-content: center;
12
+ z-index: ${this.config.zIndex};
13
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
14
+ `;let j=document.createElement("div");j.style.cssText=`
15
+ width: 48px;
16
+ height: 48px;
17
+ border: 4px solid ${this.config.textColor}33;
18
+ border-top-color: ${this.config.spinnerColor};
19
+ border-radius: 50%;
20
+ animation: botsigged-spin 1s linear infinite;
21
+ margin-bottom: 20px;
22
+ `,this.messageEl=document.createElement("span"),this.messageEl.textContent=this.config.message,this.messageEl.style.cssText=`
23
+ color: ${this.config.textColor};
24
+ font-size: 18px;
25
+ font-weight: 500;
26
+ margin-bottom: 12px;
27
+ `;let q=document.createElement("div");q.style.cssText=`
28
+ width: 200px;
29
+ height: 4px;
30
+ background: ${this.config.textColor}33;
31
+ border-radius: 2px;
32
+ overflow: hidden;
33
+ `,this.progressEl=document.createElement("div"),this.progressEl.style.cssText=`
34
+ width: 0%;
35
+ height: 100%;
36
+ background: ${this.config.spinnerColor};
37
+ border-radius: 2px;
38
+ transition: width 0.1s ease-out;
39
+ `,q.appendChild(this.progressEl);let A=document.createElement("style");A.textContent=`
40
+ @keyframes botsigged-spin {
41
+ to { transform: rotate(360deg); }
42
+ }
43
+ `,document.head.appendChild(A),this.overlay.appendChild(j),this.overlay.appendChild(this.messageEl),this.overlay.appendChild(q),document.body.appendChild(this.overlay)}setProgress(j){if(this.progressEl){let q=Math.min(100,Math.max(0,j*100));this.progressEl.style.width=`${q}%`}}showSuccess(){if(this.messageEl)this.messageEl.textContent=this.config.successMessage;if(this.progressEl)this.progressEl.style.width="100%"}hide(){if(this.overlay)this.overlay.remove(),this.overlay=null,this.messageEl=null,this.progressEl=null}isVisible(){return this.overlay!==null}}function _(){let j=new Uint8Array(16);if(typeof crypto<"u"&&crypto.getRandomValues)crypto.getRandomValues(j);else for(let q=0;q<16;q++)j[q]=Math.floor(Math.random()*256);return j}function $(j){if(j===0)return 32;let q=0;if((j&4294901760)===0)q+=16,j<<=16;if((j&4278190080)===0)q+=8,j<<=8;if((j&4026531840)===0)q+=4,j<<=4;if((j&3221225472)===0)q+=2,j<<=2;if((j&2147483648)===0)q+=1;return q}function B(j,q,A,E){let G=V(),F=new Uint8Array(j.length+4);F.set(j);let w=E,D=0;while(D<A){F[j.length]=w&255,F[j.length+1]=w>>>8&255,F[j.length+2]=w>>>16&255,F[j.length+3]=w>>>24&255;let K=G.xxHash32(F,0);if(D++,$(K)>=q)return{nonce:w,found:!0,iterations:D};w=w+1>>>0}return{nonce:w,found:!1,iterations:D}}class H{config;overlay;solving=!1;solved=!1;pendingForms=new Map;formHandler=null;formObserver=null;resubmitting=!1;debug;constructor(j,q=!1){this.config=j,this.debug=q,this.overlay=new U(j.ui)}getDifficultyForLevel(j){let q=this.config.difficulty;switch(j){case"critical":return q.critical;case"high":return q.high;case"medium":return q.medium;default:return 0}}shouldChallenge(j){if(!this.config.enabled||this.solved)return!1;let q=["low","medium","high","critical"],A=q.indexOf(j),E=q.indexOf(this.config.minLevel);return A>=E}blockFormsUntilSolved(j){if(this.formHandler)return;this.formHandler=(q)=>{if(this.solved||this.resubmitting)return;q.preventDefault(),q.stopPropagation();let A=q.target;if(!this.pendingForms.has(A))this.pendingForms.set(A,q);if(!this.solving)this.startChallenge(j)},document.querySelectorAll("form").forEach((q)=>{q.addEventListener("submit",this.formHandler,!0)}),this.formObserver=new MutationObserver((q)=>{q.forEach((A)=>{A.addedNodes.forEach((E)=>{if(E instanceof HTMLFormElement&&this.formHandler)E.addEventListener("submit",this.formHandler,!0);if(E instanceof HTMLElement&&this.formHandler)E.querySelectorAll("form").forEach((G)=>{G.addEventListener("submit",this.formHandler,!0)})})})}),this.formObserver.observe(document.body,{childList:!0,subtree:!0}),this.log("Forms blocked, challenge required")}async startChallenge(j){if(this.solving||this.solved)return;this.solving=!0;let q=this.getDifficultyForLevel(j),A=_(),E=performance.now();this.log(`Starting challenge: difficulty=${q}, level=${j}`),this.config.onChallengeStart?.(j,q),this.overlay.show();let G=1<<q,F=0,w=0,D;do{await new Promise((Y)=>setTimeout(Y,0)),D=B(A,q,this.config.chunkSize,F),w+=D.iterations,F=D.nonce+1;let Q=Math.min(1,w/G);this.overlay.setProgress(Q),this.config.onChallengeProgress?.(Q,w)}while(!D.found);let K=performance.now()-E;this.log(`Challenge solved: nonce=${D.nonce}, iterations=${w}, time=${K.toFixed(0)}ms`),this.overlay.showSuccess(),await new Promise((Q)=>setTimeout(Q,500)),this.overlay.hide(),this.solved=!0,this.solving=!1;let X={solveTimeMs:K,iterations:w,difficulty:q,level:j,nonce:D.nonce};this.config.onChallengeComplete?.(X),this.unblockForms()}unblockForms(){if(this.formObserver)this.formObserver.disconnect(),this.formObserver=null;if(this.formHandler)document.querySelectorAll("form").forEach((j)=>{j.removeEventListener("submit",this.formHandler,!0)}),this.formHandler=null;this.log("Forms unblocked"),this.resubmitting=!0,this.pendingForms.forEach((j,q)=>{if(this.log("Resubmitting pending form"),q.requestSubmit)q.requestSubmit();else q.submit()}),this.pendingForms.clear(),this.resubmitting=!1}isSolving(){return this.solving}isSolved(){return this.solved}reset(){if(this.formObserver)this.formObserver.disconnect(),this.formObserver=null;if(this.formHandler)document.querySelectorAll("form").forEach((j)=>{j.removeEventListener("submit",this.formHandler,!0)}),this.formHandler=null;this.solved=!1,this.solving=!1,this.resubmitting=!1,this.pendingForms.clear()}log(...j){if(this.debug);}}export{H as ChallengeManager};
44
+
45
+ //# debugId=0A392991821A252964756E2164756E21
@@ -0,0 +1,3 @@
1
+ var O=Object.create;var{getPrototypeOf:c,defineProperty:f,getOwnPropertyNames:T}=Object;var j=Object.prototype.hasOwnProperty;var $=(A,E,I)=>{I=A!=null?O(c(A)):{};let Q=E||!A||!A.__esModule?f(I,"default",{value:A,enumerable:!0}):I;for(let B of T(A))if(!j.call(Q,B))f(Q,B,{get:()=>A[B],enumerable:!0});return Q};var i=((A)=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(A,{get:(E,I)=>(typeof require<"u"?require:E)[I]}):A)(function(A){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+A+'" is not supported')});var W="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";var V=null,Z=null;function P(A){let E=atob(A),I=new Uint8Array(E.length);for(let Q=0;Q<E.length;Q++)I[Q]=E.charCodeAt(Q);return I}async function K(){if(Z)return Z;return Z=(async()=>{try{let A=P(W),E=await WebAssembly.compile(A);return V=(await WebAssembly.instantiate(E,{env:{abort:(Q,B,g,C)=>{}}})).exports,v(V)}catch(A){throw Z=null,A}})(),Z}function b(){return V!==null}function v(A){function E(B){let g=A.__new(B.length,1);return new Uint8Array(A.memory.buffer,g,B.length).set(B),g}function I(B){let g=new Uint16Array(B.length);for(let U=0;U<B.length;U++)g[U]=B.charCodeAt(U);let C=A.__new(g.length*2,2);return new Uint16Array(A.memory.buffer,C,g.length).set(g),C}function Q(B,g=1024){let C=new Uint8Array(A.memory.buffer),R=C.length;if(B<0||B>=R)return"";let U=B,q=Math.min(B+g,R);while(U<q&&C[U]!==0)U++;let D=C.slice(B,U);return new TextDecoder().decode(D)}return{xxHash32(B,g=0){let C=E(B);try{return A.xxHash32(C,g)}finally{A.__unpin(C)}},hashString(B,g=0){let C=I(B);try{return A.hashString(C,g)}finally{A.__unpin(C)}},hashStringToHex(B,g=0){let C=I(B);try{let R=A.hashStringToHex(C,g);return Q(R)}finally{A.__unpin(C)}},verifyHash(B,g,C=0){let R=E(B);try{return A.verifyHash(R,g,C)}finally{A.__unpin(R)}},verifyStringHash(B,g,C=0){let R=I(B);try{return A.verifyStringHash(R,g,C)}finally{A.__unpin(R)}}}}function H(){let A=new TextEncoder;function E(Q,B=0){let D=(Y,L)=>(Y<<L|Y>>>32-L)>>>0,y=(Y,L)=>(Y[L]|Y[L+1]<<8|Y[L+2]<<16|Y[L+3]<<24)>>>0,k=Q.length,G,F=0;if(k>=16){let Y=k-16,L=B+2654435761+2246822519>>>0,S=B+2246822519>>>0,M=B>>>0,z=B-2654435761>>>0;while(F<=Y)L=Math.imul(D(L+Math.imul(y(Q,F),2246822519)>>>0,13),2654435761)>>>0,F+=4,S=Math.imul(D(S+Math.imul(y(Q,F),2246822519)>>>0,13),2654435761)>>>0,F+=4,M=Math.imul(D(M+Math.imul(y(Q,F),2246822519)>>>0,13),2654435761)>>>0,F+=4,z=Math.imul(D(z+Math.imul(y(Q,F),2246822519)>>>0,13),2654435761)>>>0,F+=4;G=D(L,1)+D(S,7)+D(M,12)+D(z,18)>>>0}else G=B+374761393>>>0;G=G+k>>>0;while(F<=k-4)G=Math.imul(D(G+Math.imul(y(Q,F),3266489917)>>>0,17),668265263)>>>0,F+=4;while(F<k)G=Math.imul(D(G+Math.imul(Q[F],374761393)>>>0,11),2654435761)>>>0,F++;return G^=G>>>15,G=Math.imul(G,2246822519)>>>0,G^=G>>>13,G=Math.imul(G,3266489917)>>>0,G^=G>>>16,G>>>0}function I(Q){return(Q>>>0).toString(16).padStart(8,"0")}return{xxHash32:E,hashString(Q,B=0){return E(A.encode(Q),B)},hashStringToHex(Q,B=0){return I(E(A.encode(Q),B))},verifyHash(Q,B,g=0){return E(Q,g)===B},verifyStringHash(Q,B,g=0){return E(A.encode(Q),g)===B}}}var J=null,N=null,X=!0;async function o(A={}){let{preferWasm:E=!0,onWasmLoaded:I,onFallback:Q}=A;if(J)return J;if(N)return N;return N=(async()=>{if(E)try{return J=await K(),X=!0,I?.(),J}catch(B){let g=B instanceof Error?B.message:"Unknown error";Q?.(g)}else Q?.("WASM disabled by configuration");return J=H(),X=!1,J})(),N}function w(){if(J)return J;return J=H(),X=!1,J}function l(){return X&&b()}function m(A,E=0){let I=w();if(typeof A==="string")return I.hashString(A,E);return I.xxHash32(A,E)}function r(A,E=0){let I=w();if(typeof A==="string")return I.hashStringToHex(A,E);return I.xxHash32(A,E).toString(16).padStart(8,"0")}function s(A,E,I=0){let Q=w(),B=typeof E==="string"?parseInt(E,16):E;if(typeof A==="string")return Q.verifyStringHash(A,B,I);return Q.verifyHash(A,B,I)}function _(A,E){let I=w(),Q=I.hashString(E,0);return I.hashString(A,Q).toString(16).padStart(8,"0")}function d(A,E,I){return _(A,I)===E}export{d as verifySignature,s as verify,K as loadHashModule,l as isUsingWasm,b as isHashModuleLoaded,o as initHashModule,r as hashToHex,m as hash,w as getHash,_ as createSignature,H as createFallbackHashModule};export{$ as a,i as b,w as c,r as d};
2
+
3
+ //# debugId=9360384D0FF3974B64756E2164756E21
package/dist/index.js ADDED
@@ -0,0 +1,42 @@
1
+ import{a as y,b as U,d as v}from"./hash-q46pgar4.js";function T(Q){return typeof Q==="object"&&Q!==null&&"code"in Q&&Q.code==="LIMIT_EXCEEDED"}var q={endpoint:"wss://api.botsigged.com/socket/websocket",debug:!1,sendInterval:2000,maxBufferSize:1000,mouseSampleRate:0.5,autoStart:!0,actionThreshold:70,action:"none",minAlertLevel:"high",botScoreThresholds:{medium:40,high:70,critical:90},hashVerification:{enabled:!1,preferWasm:!0},challenge:{enabled:!1,minLevel:"high",chunkSize:1e4,difficulty:{medium:12,high:16,critical:20},ui:{enabled:!0,message:"Verifying you're human...",successMessage:"Verified!",backgroundColor:"rgba(0, 0, 0, 0.7)",textColor:"#ffffff",spinnerColor:"#3b82f6",zIndex:999999}},formProtection:{mode:"auto",minTimeBeforeSubmit:500,maxHoldTime:3000,showLoadingUI:!0,loadingMessage:"Please wait..."},fallbackMode:"degraded"},F={action:"challenge",challenge:{difficulty:{suspicious:14,bot:18},timeout_ms:30000},form_protection_mode:"holdUntilReady"};function h(Q){let X=Q.action??q.action,Y=X==="challenge"||Q.challenge?.enabled;return{apiKey:Q.apiKey,accountId:Q.accountId,endpoint:Q.endpoint??q.endpoint,debug:Q.debug??q.debug,sendInterval:Q.sendInterval??q.sendInterval,maxBufferSize:Q.maxBufferSize??q.maxBufferSize,mouseSampleRate:Q.mouseSampleRate??q.mouseSampleRate,autoStart:Q.autoStart??q.autoStart,actionThreshold:Q.actionThreshold??q.actionThreshold,action:X,minAlertLevel:Q.minAlertLevel??q.minAlertLevel,botScoreThresholds:{...q.botScoreThresholds,...Q.botScoreThresholds},hashVerification:{...q.hashVerification,...Q.hashVerification},challenge:{enabled:Y,minLevel:Q.challenge?.minLevel??q.challenge.minLevel,chunkSize:Q.challenge?.chunkSize??q.challenge.chunkSize,difficulty:{...q.challenge.difficulty,...Q.challenge?.difficulty},ui:{...q.challenge.ui,...Q.challenge?.ui},onChallengeStart:Q.challenge?.onChallengeStart,onChallengeComplete:Q.challenge?.onChallengeComplete,onChallengeProgress:Q.challenge?.onChallengeProgress},formProtection:{mode:Q.formProtection?.mode??q.formProtection.mode,minTimeBeforeSubmit:Q.formProtection?.minTimeBeforeSubmit??q.formProtection.minTimeBeforeSubmit,maxHoldTime:Q.formProtection?.maxHoldTime??q.formProtection.maxHoldTime,showLoadingUI:Q.formProtection?.showLoadingUI??q.formProtection.showLoadingUI,loadingMessage:Q.formProtection?.loadingMessage??q.formProtection.loadingMessage,onHold:Q.formProtection?.onHold,onRelease:Q.formProtection?.onRelease,onBlock:Q.formProtection?.onBlock},fallbackMode:Q.fallbackMode??q.fallbackMode,cookie:Q.cookie,headers:Q.headers,formInject:Q.formInject,onScoreUpdate:Q.onScoreUpdate,onConnectionChange:Q.onConnectionChange,onError:Q.onError,onUsageLimitExceeded:Q.onUsageLimitExceeded,onHighBotScore:Q.onHighBotScore,onServerConfig:Q.onServerConfig,onServerAction:Q.onServerAction}}class k{events=[];startTime=0;sampleRate;maxBufferSize;isListening=!1;boundHandleMouseMove;boundHandleMouseDown;boundHandleMouseUp;boundHandleClick;constructor(Q={}){this.sampleRate=Q.sampleRate??0.5,this.maxBufferSize=Q.maxBufferSize??500,this.boundHandleMouseMove=this.handleMouseMove.bind(this),this.boundHandleMouseDown=this.handleMouseDown.bind(this),this.boundHandleMouseUp=this.handleMouseUp.bind(this),this.boundHandleClick=this.handleClick.bind(this)}start(){if(this.isListening)return;this.startTime=Date.now(),document.addEventListener("mousemove",this.boundHandleMouseMove,{passive:!0}),document.addEventListener("mousedown",this.boundHandleMouseDown,{passive:!0}),document.addEventListener("mouseup",this.boundHandleMouseUp,{passive:!0}),document.addEventListener("click",this.boundHandleClick,{passive:!0}),this.isListening=!0}stop(){if(!this.isListening)return;document.removeEventListener("mousemove",this.boundHandleMouseMove),document.removeEventListener("mousedown",this.boundHandleMouseDown),document.removeEventListener("mouseup",this.boundHandleMouseUp),document.removeEventListener("click",this.boundHandleClick),this.isListening=!1}addEvent(Q){if(this.events.push(Q),this.events.length>this.maxBufferSize)this.events.shift()}handleMouseMove(Q){if(Math.random()>this.sampleRate)return;this.addEvent({type:"move",x:Q.clientX,y:Q.clientY,t:Date.now()})}handleMouseDown(Q){this.addEvent({type:"down",x:Q.clientX,y:Q.clientY,t:Date.now(),button:Q.button})}handleMouseUp(Q){this.addEvent({type:"up",x:Q.clientX,y:Q.clientY,t:Date.now(),button:Q.button})}handleClick(Q){let X=Q.target,Y,Z;if(X&&X.getBoundingClientRect){let $=X.getBoundingClientRect();Y={top:$.top,left:$.left,width:$.width,height:$.height},Z=X.tagName?.toLowerCase()}this.addEvent({type:"click",x:Q.clientX,y:Q.clientY,t:Date.now(),button:Q.button,targetRect:Y,targetTag:Z})}getSignal(){return{events:[...this.events],start_time:this.startTime}}flush(){this.events=[]}getBufferSize(){return this.events.length}reset(){this.events=[],this.startTime=Date.now()}}class x{events=[];startTime=0;maxBufferSize;isListening=!1;boundHandleScroll;constructor(Q={}){this.maxBufferSize=Q.maxBufferSize??200,this.boundHandleScroll=this.handleScroll.bind(this)}start(){if(this.isListening)return;this.startTime=Date.now(),window.addEventListener("scroll",this.boundHandleScroll,{passive:!0}),this.isListening=!0}stop(){if(!this.isListening)return;window.removeEventListener("scroll",this.boundHandleScroll),this.isListening=!1}handleScroll(){if(this.events.push({y:window.scrollY,t:Date.now()}),this.events.length>this.maxBufferSize)this.events.shift()}getSignal(){return{events:[...this.events],start_time:this.startTime}}flush(){this.events=[]}getBufferSize(){return this.events.length}reset(){this.events=[],this.startTime=Date.now()}}class w{static instance=null;timings={signalRoundtrips:[]};pendingSignals=new Map;constructor(){this.timings.scriptStart=performance.now()}static getInstance(){if(!w.instance)w.instance=new w;return w.instance}static reset(){w.instance=null}markScriptStart(){this.timings.scriptStart=performance.now()}markConstructorStart(){this.timings.constructorStart=performance.now()}markConstructorEnd(){this.timings.constructorEnd=performance.now()}markStartCalled(){this.timings.startCalled=performance.now()}markSdkReady(){this.timings.sdkReady=performance.now()}markFingerprintStart(){this.timings.fingerprintStart=performance.now()}markFingerprintEnd(){this.timings.fingerprintEnd=performance.now()}markWsConnectStart(){this.timings.wsConnectStart=performance.now()}markWsConnectEnd(){this.timings.wsConnectEnd=performance.now()}markChannelJoinStart(){this.timings.channelJoinStart=performance.now()}markChannelJoinEnd(){this.timings.channelJoinEnd=performance.now()}markInitialScoreReceived(){this.timings.initialScoreReceived=performance.now()}markFormCollectorStart(){this.timings.formCollectorStart=performance.now()}markFormCollectorReady(){this.timings.formCollectorReady=performance.now()}markFirstFormInteraction(){if(!this.timings.firstFormInteraction){if(this.timings.firstFormInteraction=performance.now(),this.timings.sdkReady)this.timings.timeToFirstInteraction=this.timings.firstFormInteraction-this.timings.sdkReady}}markFirstSubmitAttempt(Q){if(!this.timings.firstSubmitAttempt)this.timings.firstSubmitAttempt=performance.now(),this.timings.hadScoreBeforeSubmit=Q}markSignalSent(Q){this.pendingSignals.set(Q,performance.now())}markSignalResponseReceived(Q){let X=this.pendingSignals.get(Q);if(X!==void 0){let Y=performance.now(),Z={sentAt:X,receivedAt:Y,roundtripMs:Y-X,seq:Q};this.timings.signalRoundtrips?.push(Z),this.pendingSignals.delete(Q)}}getTimings(){return{...this.timings}}getSummary(){let Q=this.timings,X=Q.signalRoundtrips||[],Y=0,Z=1/0,$=0;if(X.length>0)Y=X.reduce((G,g)=>G+g.roundtripMs,0)/X.length,Z=Math.min(...X.map((G)=>G.roundtripMs)),$=Math.max(...X.map((G)=>G.roundtripMs));let J=(Q.sdkReady??0)-(Q.scriptStart??0),z=(Q.fingerprintEnd??0)-(Q.fingerprintStart??0),W=(Q.wsConnectEnd??0)-(Q.wsConnectStart??0),B=(Q.channelJoinEnd??0)-(Q.channelJoinStart??0),V=(Q.initialScoreReceived??0)-(Q.startCalled??0),R=(Q.initialScoreReceived??0)-(Q.scriptStart??0);return{totalStartupMs:Math.round(J),fingerprintMs:Math.round(z),wsConnectionMs:Math.round(W),channelJoinMs:Math.round(B),timeToFirstScoreMs:Math.round(V),avgSignalRoundtripMs:Math.round(Y),minSignalRoundtripMs:Z===1/0?0:Math.round(Z),maxSignalRoundtripMs:Math.round($),vulnerabilityWindowMs:Math.round(R),protectedBeforeSubmit:Q.hadScoreBeforeSubmit??!1}}logSummary(){let Q=this.getSummary(),X=this.timings;if(X.firstFormInteraction);if(X.firstSubmitAttempt);if(Q.vulnerabilityWindowMs>0);}getReport(){return{timings:this.timings,summary:this.getSummary(),userAgent:navigator.userAgent,timestamp:Date.now()}}}var K=w.getInstance();function N(){return w.getInstance()}function l(){return K.getSummary()}function f(){K.logSummary()}var j="__bs_ghost_value";class C{keyEvents=[];focusEvents=[];pasteEvents=[];inputEvents=[];submitCount=0;startTime=0;maxKeyEvents;maxFocusEvents;maxInputEvents;isListening=!1;valueSetterHooked=!1;onSubmit;originalInputDescriptor;originalTextareaDescriptor;lastKeyWasTab=!1;currentField=null;emailDomains=new Set;boundHandleFocusIn;boundHandleFocusOut;boundHandleKeyDown;boundHandleKeyUp;boundHandlePaste;boundHandleSubmit;boundHandleClick;boundHandleInput;boundHandleGhostValue;constructor(Q={}){this.maxKeyEvents=Q.maxKeyEvents??500,this.maxFocusEvents=Q.maxFocusEvents??100,this.maxInputEvents=Q.maxInputEvents??200,this.onSubmit=Q.onSubmit,this.boundHandleFocusIn=this.handleFocusIn.bind(this),this.boundHandleFocusOut=this.handleFocusOut.bind(this),this.boundHandleKeyDown=this.handleKeyDown.bind(this),this.boundHandleKeyUp=this.handleKeyUp.bind(this),this.boundHandlePaste=this.handlePaste.bind(this),this.boundHandleSubmit=this.handleSubmit.bind(this),this.boundHandleClick=this.handleClick.bind(this),this.boundHandleInput=this.handleInput.bind(this),this.boundHandleGhostValue=this.handleGhostValue.bind(this)}start(){if(this.isListening)return;this.startTime=Date.now(),document.addEventListener("focusin",this.boundHandleFocusIn,{passive:!0,capture:!0}),document.addEventListener("focusout",this.boundHandleFocusOut,{passive:!0,capture:!0}),document.addEventListener("keydown",this.boundHandleKeyDown,{passive:!0}),document.addEventListener("keyup",this.boundHandleKeyUp,{passive:!0}),document.addEventListener("paste",this.boundHandlePaste,{passive:!0}),document.addEventListener("submit",this.boundHandleSubmit,{passive:!0}),document.addEventListener("click",this.boundHandleClick,{passive:!0}),document.addEventListener("input",this.boundHandleInput,{passive:!0}),document.addEventListener(j,this.boundHandleGhostValue,{passive:!0}),this.hookValueSetters(),this.isListening=!0}stop(){if(!this.isListening)return;document.removeEventListener("focusin",this.boundHandleFocusIn,{capture:!0}),document.removeEventListener("focusout",this.boundHandleFocusOut,{capture:!0}),document.removeEventListener("keydown",this.boundHandleKeyDown),document.removeEventListener("keyup",this.boundHandleKeyUp),document.removeEventListener("paste",this.boundHandlePaste),document.removeEventListener("submit",this.boundHandleSubmit),document.removeEventListener("click",this.boundHandleClick),document.removeEventListener("input",this.boundHandleInput),document.removeEventListener(j,this.boundHandleGhostValue),this.unhookValueSetters(),this.isListening=!1}isFormInput(Q){if(!Q||!(Q instanceof HTMLElement))return!1;let X=Q.tagName.toLowerCase();if(X==="textarea"||X==="select")return!0;if(X==="input"){let Y=Q.type.toLowerCase();return!["submit","button","reset","hidden","image"].includes(Y)}return!1}isEmailField(Q){let X=Q.type?.toLowerCase()||"",Y=(Q.name||"").toLowerCase(),Z=(Q.id||"").toLowerCase();return X==="email"||Y.includes("email")||Y.includes("e-mail")||Z.includes("email")||Z.includes("e-mail")}extractEmailDomain(Q){if(!Q||typeof Q!=="string")return null;let X=Q.trim();if(!X)return null;let Y=X.match(/@([a-zA-Z0-9.-]+\.[a-zA-Z]{2,})$/);return Y?Y[1].toLowerCase():null}getFieldId(Q){return Q.id||Q.getAttribute("name")||`field-${Q.tagName.toLowerCase()}`}handleFocusIn(Q){if(!this.isFormInput(Q.target))return;N().markFirstFormInteraction();let X=this.getFieldId(Q.target),Y="direct";if(this.lastKeyWasTab)Y="tab";if(this.focusEvents.push({type:"focus",field:X,t:Date.now(),method:Y}),this.focusEvents.length>this.maxFocusEvents)this.focusEvents.shift();this.currentField=X,this.lastKeyWasTab=!1}handleFocusOut(Q){if(!this.isFormInput(Q.target))return;let X=Q.target,Y=this.getFieldId(X);if(this.focusEvents.push({type:"blur",field:Y,t:Date.now()}),this.focusEvents.length>this.maxFocusEvents)this.focusEvents.shift();if(X instanceof HTMLInputElement&&this.isEmailField(X)){let Z=this.extractEmailDomain(X.value);if(Z)this.emailDomains.add(Z)}this.currentField=null}handleClick(Q){if(!this.isFormInput(Q.target))return;let X=this.focusEvents[this.focusEvents.length-1];if(X&&X.type==="focus"&&Date.now()-X.t<50)X.method="click"}handleKeyDown(Q){if(Q.key==="Tab"){this.lastKeyWasTab=!0;return}if(!this.isFormInput(Q.target))return;let X="key";if(Q.key==="Backspace")X="backspace";else if(Q.key==="Delete")X="delete";else if(Q.key==="Enter")X="enter";else if(Q.key==="Tab")X="tab";else if(Q.key.length===1)X="char";else if(Q.key.startsWith("Arrow"))X="arrow";if(this.keyEvents.push({type:"down",code:X,t:Date.now(),field:this.currentField||void 0}),this.keyEvents.length>this.maxKeyEvents)this.keyEvents.shift()}handleKeyUp(Q){if(!this.isFormInput(Q.target))return;let X="key";if(Q.key==="Backspace")X="backspace";else if(Q.key==="Delete")X="delete";else if(Q.key.length===1)X="char";if(this.keyEvents.push({type:"up",code:X,t:Date.now(),field:this.currentField||void 0}),this.keyEvents.length>this.maxKeyEvents)this.keyEvents.shift()}handleInput(Q){if(!this.isFormInput(Q.target))return;let X=Q.target,Z=Q.inputType||"unknown",$=X.value?.length??0;if(this.inputEvents.push({field:this.getFieldId(X),t:Date.now(),inputType:Z,valueLength:$}),this.inputEvents.length>this.maxInputEvents)this.inputEvents.shift()}handlePaste(Q){if(!this.isFormInput(Q.target))return;let X=Q.clipboardData?.getData("text")||"";this.pasteEvents.push({field:this.getFieldId(Q.target),t:Date.now(),length:X.length})}handleSubmit(Q){this.submitCount++;let X=Q.target;if(X&&X.elements)for(let Y=0;Y<X.elements.length;Y++){let Z=X.elements[Y];if(Z instanceof HTMLInputElement&&this.isEmailField(Z)){let $=this.extractEmailDomain(Z.value);if($)this.emailDomains.add($)}}this.onSubmit?.()}getSignal(){return{keys:[...this.keyEvents],focus:[...this.focusEvents],pastes:[...this.pasteEvents],inputs:[...this.inputEvents],submits:this.submitCount,start_time:this.startTime,email_domains:this.emailDomains.size>0?Array.from(this.emailDomains):void 0}}flush(){this.keyEvents=[],this.focusEvents=[],this.pasteEvents=[],this.inputEvents=[]}getBufferSize(){return this.keyEvents.length+this.focusEvents.length+this.pasteEvents.length+this.inputEvents.length}reset(){this.keyEvents=[],this.focusEvents=[],this.pasteEvents=[],this.inputEvents=[],this.submitCount=0,this.startTime=Date.now(),this.lastKeyWasTab=!1,this.currentField=null,this.emailDomains.clear()}hookValueSetters(){if(this.valueSetterHooked)return;if(this.originalInputDescriptor=Object.getOwnPropertyDescriptor(HTMLInputElement.prototype,"value"),this.originalInputDescriptor){let Q=this.originalInputDescriptor.set,X=this.originalInputDescriptor.get;Object.defineProperty(HTMLInputElement.prototype,"value",{configurable:!0,enumerable:!0,get(){return X?.call(this)},set(Y){let Z=X?.call(this)??"";Q?.call(this,Y);let $=Y??"";if($!==Z)this.dispatchEvent(new CustomEvent(j,{bubbles:!0,detail:{valueLength:$.length,wasEmpty:Z.length===0}}))}})}if(this.originalTextareaDescriptor=Object.getOwnPropertyDescriptor(HTMLTextAreaElement.prototype,"value"),this.originalTextareaDescriptor){let Q=this.originalTextareaDescriptor.set,X=this.originalTextareaDescriptor.get;Object.defineProperty(HTMLTextAreaElement.prototype,"value",{configurable:!0,enumerable:!0,get(){return X?.call(this)},set(Y){let Z=X?.call(this)??"";Q?.call(this,Y);let $=Y??"";if($!==Z)this.dispatchEvent(new CustomEvent(j,{bubbles:!0,detail:{valueLength:$.length,wasEmpty:Z.length===0}}))}})}this.valueSetterHooked=!0}unhookValueSetters(){if(!this.valueSetterHooked)return;if(this.originalInputDescriptor)Object.defineProperty(HTMLInputElement.prototype,"value",this.originalInputDescriptor);if(this.originalTextareaDescriptor)Object.defineProperty(HTMLTextAreaElement.prototype,"value",this.originalTextareaDescriptor);this.valueSetterHooked=!1}handleGhostValue(Q){let X=Q.target;if(!this.isFormInput(X))return;let Z=Q.detail?.valueLength??0;if(this.inputEvents.push({field:this.getFieldId(X),t:Date.now(),inputType:"programmatic",valueLength:Z}),this.inputEvents.length>this.maxInputEvents)this.inputEvents.shift()}}class L{cachedSignal=null;collect(){if(this.cachedSignal)return this.cachedSignal;let Q=navigator,X=window;return this.cachedSignal={user_agent:navigator.userAgent,platform:navigator.platform,language:navigator.language,languages:[...navigator.languages||[]],hardware_concurrency:navigator.hardwareConcurrency??null,device_memory:Q.deviceMemory??null,max_touch_points:navigator.maxTouchPoints??0,screen_width:screen.width,screen_height:screen.height,screen_avail_width:screen.availWidth,screen_avail_height:screen.availHeight,color_depth:screen.colorDepth,pixel_ratio:window.devicePixelRatio??1,...this.getWebGLInfo(),plugins_count:navigator.plugins?.length??0,mime_types_count:navigator.mimeTypes?.length??0,timezone:this.getTimezone(),timezone_offset:new Date().getTimezoneOffset(),has_webdriver:Q.webdriver===!0,has_chrome_runtime:!!X.chrome?.runtime,has_chrome_app:!!X.chrome?.app,has_notification_api:"Notification"in window,has_permissions_api:"permissions"in navigator,outer_dimensions:{width:window.outerWidth,height:window.outerHeight},inner_dimensions:{width:window.innerWidth,height:window.innerHeight},notification_permission:this.getNotificationPermission()},this.cachedSignal}getWebGLInfo(){try{let Q=document.createElement("canvas"),X=Q.getContext("webgl")||Q.getContext("experimental-webgl");if(!X||!(X instanceof WebGLRenderingContext))return{webgl_vendor:null,webgl_renderer:null};let Y=X.getExtension("WEBGL_debug_renderer_info");if(!Y)return{webgl_vendor:null,webgl_renderer:null};return{webgl_vendor:X.getParameter(Y.UNMASKED_VENDOR_WEBGL),webgl_renderer:X.getParameter(Y.UNMASKED_RENDERER_WEBGL)}}catch{return{webgl_vendor:null,webgl_renderer:null}}}getTimezone(){try{return Intl.DateTimeFormat().resolvedOptions().timeZone}catch{return null}}getNotificationPermission(){if("Notification"in window)return Notification.permission;return null}getSignal(){return this.collect()}reset(){this.cachedSignal=null}}class b{cachedFingerprint=null;async generate(){if(this.cachedFingerprint)return this.cachedFingerprint;let[Q,X,Y,Z,$]=await Promise.all([this.getCanvasHash(),this.getWebGLData(),this.getAudioHash(),this.getFontData(),this.getScreenHash()]),J={hash:"",canvas_hash:Q,webgl_hash:X.hash,audio_hash:Y,font_hash:Z.hash,screen_hash:$,webgl_vendor:X.vendor,webgl_renderer:X.renderer,timezone:this.getTimezone(),language:this.getLanguage(),platform:this.getPlatform(),font_count:Z.count};return J.hash=await this.generateMainHash(J),this.cachedFingerprint=J,J}getFingerprint(){return this.cachedFingerprint}reset(){this.cachedFingerprint=null}async getCanvasHash(){try{let Q=document.createElement("canvas");Q.width=200,Q.height=50;let X=Q.getContext("2d");if(!X)return null;X.textBaseline="top",X.font="14px 'Arial'",X.fillStyle="#f60",X.fillRect(125,1,62,20),X.fillStyle="#069",X.fillText("BotSigged,\uD83C\uDFA8",2,15),X.fillStyle="rgba(102, 204, 0, 0.7)",X.fillText("BotSigged,\uD83C\uDFA8",4,17);let Y=Q.toDataURL();return this.hashString(Y)}catch{return null}}async getWebGLData(){try{let Q=document.createElement("canvas"),X=Q.getContext("webgl")||Q.getContext("experimental-webgl");if(!X||!(X instanceof WebGLRenderingContext))return{hash:null,vendor:null,renderer:null};let Y=[],Z=[X.ALIASED_LINE_WIDTH_RANGE,X.ALIASED_POINT_SIZE_RANGE,X.ALPHA_BITS,X.BLUE_BITS,X.DEPTH_BITS,X.GREEN_BITS,X.MAX_COMBINED_TEXTURE_IMAGE_UNITS,X.MAX_CUBE_MAP_TEXTURE_SIZE,X.MAX_FRAGMENT_UNIFORM_VECTORS,X.MAX_RENDERBUFFER_SIZE,X.MAX_TEXTURE_IMAGE_UNITS,X.MAX_TEXTURE_SIZE,X.MAX_VARYING_VECTORS,X.MAX_VERTEX_ATTRIBS,X.MAX_VERTEX_TEXTURE_IMAGE_UNITS,X.MAX_VERTEX_UNIFORM_VECTORS,X.MAX_VIEWPORT_DIMS,X.RED_BITS,X.RENDERER,X.SHADING_LANGUAGE_VERSION,X.STENCIL_BITS,X.VENDOR,X.VERSION];for(let V of Z)try{let R=X.getParameter(V);Y.push(String(R))}catch{Y.push("")}let $=X.getSupportedExtensions();if($)Y.push($.sort().join(","));let J=null,z=null,W=X.getExtension("WEBGL_debug_renderer_info");if(W)J=X.getParameter(W.UNMASKED_VENDOR_WEBGL),z=X.getParameter(W.UNMASKED_RENDERER_WEBGL);return{hash:this.hashString(Y.join("|")),vendor:J,renderer:z}}catch{return{hash:null,vendor:null,renderer:null}}}async getAudioHash(){try{let Q=window.OfflineAudioContext||window.webkitOfflineAudioContext;if(!Q)return null;let X=new Q(1,4500,44100),Y=X.createOscillator(),Z=X.createDynamicsCompressor();Y.type="triangle",Y.frequency.setValueAtTime(1e4,X.currentTime),Z.threshold.setValueAtTime(-50,X.currentTime),Z.knee.setValueAtTime(40,X.currentTime),Z.ratio.setValueAtTime(12,X.currentTime),Z.attack.setValueAtTime(0,X.currentTime),Z.release.setValueAtTime(0.25,X.currentTime),Y.connect(Z),Z.connect(X.destination),Y.start(0);let J=(await X.startRendering()).getChannelData(0),z=[];for(let W=0;W<J.length;W+=100)z.push(J[W]);return this.hashString(z.join(","))}catch{return null}}async getFontData(){let Q=["Arial","Arial Black","Arial Narrow","Calibri","Cambria","Cambria Math","Comic Sans MS","Consolas","Courier","Courier New","Georgia","Helvetica","Impact","Lucida Console","Lucida Sans Unicode","Microsoft Sans Serif","MS Gothic","MS PGothic","MS Sans Serif","MS Serif","Palatino Linotype","Segoe Print","Segoe Script","Segoe UI","Symbol","Tahoma","Times","Times New Roman","Trebuchet MS","Verdana","Wingdings"],X=["monospace","sans-serif","serif"],Y="mmmmmmmmmmlli",Z="72px",$=document.createElement("span");$.style.position="absolute",$.style.left="-9999px",$.style.fontSize="72px",$.style.lineHeight="normal",$.innerHTML="mmmmmmmmmmlli",document.body.appendChild($);let J={};for(let B of X)$.style.fontFamily=B,J[B]=$.offsetWidth;let z=[];for(let B of Q){let V=!1;for(let R of X)if($.style.fontFamily=`'${B}', ${R}`,$.offsetWidth!==J[R]){V=!0;break}if(V)z.push(B)}return document.body.removeChild($),{hash:this.hashString(z.join(",")),count:z.length}}async getScreenHash(){let Q=[String(screen.width),String(screen.height),String(screen.availWidth),String(screen.availHeight),String(screen.colorDepth),String(screen.pixelDepth),String(window.devicePixelRatio||1)];return this.hashString(Q.join("|"))}getTimezone(){try{return Intl.DateTimeFormat().resolvedOptions().timeZone}catch{return null}}getLanguage(){return navigator.language||null}getPlatform(){return navigator.platform||null}generateMainHash(Q){let X=[Q.canvas_hash||"",Q.webgl_hash||"",Q.audio_hash||"",Q.font_hash||"",Q.screen_hash||"",Q.timezone||"",Q.language||"",Q.platform||""];return this.hashString(X.join("|"))}hashString(Q){return v(Q)}}class A{ws=null;endpoint;apiKey;heartbeatInterval;reconnectAttempts;reconnectDelay;debug;state="disconnected";channelState="closed";refCounter=0;joinRef=null;heartbeatTimer=null;reconnectTimer=null;reconnectCount=0;pendingReplies=new Map;onConnectionChange;onError;channelCallbacks={};topic=null;constructor(Q){this.endpoint=Q.endpoint,this.apiKey=Q.apiKey,this.heartbeatInterval=Q.heartbeatInterval??30000,this.reconnectAttempts=Q.reconnectAttempts??10,this.reconnectDelay=Q.reconnectDelay??((X)=>Math.min(1000*Math.pow(2,X),30000)),this.debug=Q.debug??!1,this.onConnectionChange=Q.onConnectionChange,this.onError=Q.onError}connect(){return new Promise((Q,X)=>{if(this.ws&&this.state==="connected"){Q();return}this.setState("connecting");let Y=this.buildUrl();this.log("Connecting to",Y);try{this.ws=new WebSocket(Y),this.ws.onopen=()=>{this.log("WebSocket connected"),this.setState("connected"),this.reconnectCount=0,this.startHeartbeat(),Q()},this.ws.onclose=(Z)=>{this.log("WebSocket closed",Z.code,Z.reason),this.handleClose()},this.ws.onerror=(Z)=>{this.log("WebSocket error",Z);let $=Error("WebSocket connection error");this.handleError($),X($)},this.ws.onmessage=(Z)=>{this.handleMessage(Z.data)}}catch(Z){let $=Z instanceof Error?Z:Error(String(Z));this.handleError($),X($)}})}disconnect(){if(this.stopHeartbeat(),this.stopReconnect(),this.ws)this.ws.close(1000,"Client disconnect"),this.ws=null;this.setState("disconnected"),this.setChannelState("closed")}joinChannel(Q,X,Y,Z,$={},J){return this.channelCallbacks=$,this.topic=`detection:${Q}`,new Promise((z,W)=>{if(this.state!=="connected"){W(Error("WebSocket not connected"));return}this.setChannelState("joining"),this.joinRef=this.makeRef();let B={session_id:Q,api_key:this.apiKey,fingerprint:X,session:Y,browser:Z};if(J)B.account_id=J;this.push("phx_join",B,this.joinRef).then((V)=>{this.log("Channel joined",V),this.setChannelState("joined"),this.channelCallbacks.onJoin?.(),z(V)}).catch((V)=>{this.log("Channel join failed",V),this.setChannelState("error"),this.channelCallbacks.onError?.(V),W(V)})})}leaveChannel(){return new Promise((Q,X)=>{if(this.channelState!=="joined"){Q();return}this.setChannelState("leaving"),this.push("phx_leave",{}).then(()=>{this.log("Channel left"),this.setChannelState("closed"),this.joinRef=null,this.topic=null,this.channelCallbacks.onLeave?.(),Q()}).catch((Y)=>{this.setChannelState("error"),X(Y)})})}sendSignal(Q){if(this.channelState!=="joined")return Promise.reject(Error("Channel not joined"));return this.push("signal",Q)}sendFormStatus(Q){if(this.channelState!=="joined")return Promise.reject(Error("Channel not joined"));return this.push("form_status",{status:Q})}sendEvent(Q,X){if(this.channelState!=="joined")return Promise.reject(Error("Channel not joined"));return this.push(Q,X)}getState(){return this.state}getChannelState(){return this.channelState}isReady(){return this.state==="connected"&&this.channelState==="joined"}buildUrl(){let Q=new URL(this.endpoint);return Q.searchParams.set("vsn","2.0.0"),Q.searchParams.set("api_key",this.apiKey),Q.toString()}makeRef(){return this.refCounter++,String(this.refCounter)}push(Q,X,Y){return new Promise((Z,$)=>{if(!this.ws||this.ws.readyState!==WebSocket.OPEN){$(Error("WebSocket not open"));return}if(!this.topic){$(Error("Channel topic not set"));return}let J=Y??this.makeRef(),z=[this.joinRef,J,this.topic,Q,X],W=setTimeout(()=>{this.pendingReplies.delete(J),$(Error(`Timeout waiting for reply to ${Q}`))},1e4);this.pendingReplies.set(J,{resolve:Z,reject:$,timeout:W}),this.log("Sending",Q,X),this.ws.send(JSON.stringify(z))})}handleMessage(Q){try{let[X,Y,Z,$,J]=JSON.parse(Q);if(this.log("Received",$,J),$==="phx_reply"&&Y){let z=this.pendingReplies.get(Y);if(z){clearTimeout(z.timeout),this.pendingReplies.delete(Y);let W=J;if(W.status==="ok")z.resolve(W.response??{});else if(W.response&&typeof W.response==="object"&&"code"in W.response)z.reject(W.response);else{let B=this.buildErrorMessage(W.status,W.response);z.reject(Error(B))}}return}if($==="phx_error"){let z=Error("Channel error");this.setChannelState("error"),this.channelCallbacks.onError?.(z);return}if($==="phx_close"){this.setChannelState("closed"),this.channelCallbacks.onLeave?.();return}if($==="score_update"){this.channelCallbacks.onScoreUpdate?.(J);return}if($==="action"){this.channelCallbacks.onAction?.(J);return}this.channelCallbacks.onMessage?.($,J)}catch(X){this.log("Error parsing message",X)}}handleClose(){this.stopHeartbeat(),this.setState("disconnected"),this.setChannelState("closed");for(let[Q,X]of this.pendingReplies)clearTimeout(X.timeout),X.reject(Error("Connection closed"));this.pendingReplies.clear(),this.scheduleReconnect()}handleError(Q){this.setState("error"),this.onError?.(Q)}startHeartbeat(){this.stopHeartbeat(),this.heartbeatTimer=setInterval(()=>{if(this.ws&&this.ws.readyState===WebSocket.OPEN){let Q=[null,this.makeRef(),"phoenix","heartbeat",{}];if(this.ws.send(JSON.stringify(Q)),this.channelState==="joined")this.push("heartbeat",{}).then((X)=>{if(X.bot_score!==void 0)this.channelCallbacks.onScoreUpdate?.({bot_score:X.bot_score,classification:X.classification,triggered_rules:[],event_count:0})}).catch(()=>{})}},this.heartbeatInterval)}stopHeartbeat(){if(this.heartbeatTimer)clearInterval(this.heartbeatTimer),this.heartbeatTimer=null}scheduleReconnect(){if(this.reconnectCount>=this.reconnectAttempts){this.log("Max reconnect attempts reached");return}let Q=this.reconnectDelay(this.reconnectCount);this.reconnectCount++,this.log(`Scheduling reconnect attempt ${this.reconnectCount} in ${Q}ms`),this.reconnectTimer=setTimeout(()=>{this.connect().catch((X)=>{this.log("Reconnect failed",X)})},Q)}stopReconnect(){if(this.reconnectTimer)clearTimeout(this.reconnectTimer),this.reconnectTimer=null;this.reconnectCount=0}setState(Q){if(this.state!==Q)this.state=Q,this.onConnectionChange?.(Q)}setChannelState(Q){this.channelState=Q}buildErrorMessage(Q,X){if(X){if(typeof X.reason==="string")return`Channel error: ${X.reason}`;if(Object.keys(X).length>0)return`Channel error (${Q??"error"}): ${JSON.stringify(X)}`}return Q??"Unknown error"}log(...Q){if(this.debug);}}class D{config;isReady=!1;hasScore=!1;hasFormScore=!1;currentScore=null;pendingSubmissions=[];pendingRequests=[];protectedForms=new Set;releasingForms=new Set;loadingOverlay=null;formObserver=null;startTime;originalFetch=null;originalXHROpen=null;originalXHRSend=null;constructor(Q={}){if(this.startTime=performance.now(),this.config={mode:Q.mode??"none",minTimeBeforeSubmit:Q.minTimeBeforeSubmit??500,maxHoldTime:Q.maxHoldTime??5000,showLoadingUI:Q.showLoadingUI??!0,loadingMessage:Q.loadingMessage??"Please wait...",onHold:Q.onHold,onRelease:Q.onRelease,onBlock:Q.onBlock,flushAndWaitForScore:Q.flushAndWaitForScore},this.config.mode!=="none")this.setup()}setup(){if(this.config.mode==="auto")this.interceptFetch(),this.interceptXHR();let Q=()=>{document.querySelectorAll("form").forEach((X)=>{this.protectForm(X)}),this.formObserver=new MutationObserver((X)=>{X.forEach((Y)=>{Y.addedNodes.forEach((Z)=>{if(Z instanceof HTMLFormElement)this.protectForm(Z);if(Z instanceof HTMLElement)Z.querySelectorAll("form").forEach(($)=>{this.protectForm($)})})})}),this.formObserver.observe(document.body,{childList:!0,subtree:!0})};if(document.body)Q();else document.addEventListener("DOMContentLoaded",Q,{once:!0})}isFormLikeRequest(Q,X){if((X?.method?.toUpperCase()||"GET")!=="POST")return!1;try{if((typeof Q==="string"?new URL(Q,window.location.origin):Q instanceof URL?Q:new URL(Q.url)).origin!==window.location.origin)return!1}catch{return!1}let Z=X?.headers instanceof Headers?X.headers.get("content-type"):typeof X?.headers==="object"&&X.headers!==null?X.headers["content-type"]||X.headers["Content-Type"]:null;if(Z){let $=Z.toLowerCase();if($.includes("application/x-www-form-urlencoded")||$.includes("multipart/form-data")||$.includes("application/json"))return!0;return!1}if(X?.body)return!0;return!1}interceptFetch(){this.originalFetch=window.fetch.bind(window);let Q=this;window.fetch=async function(X,Y){if(!Q.isFormLikeRequest(X,Y))return Q.originalFetch(X,Y);if(Q.hasScore)return Q.originalFetch(X,Y);return new Promise((Z,$)=>{let J={resolve:Z,reject:$,execute:()=>Q.originalFetch(X,Y),timestamp:performance.now()};if(Q.pendingRequests.push(J),Q.config.showLoadingUI&&Q.pendingRequests.length===1)Q.showLoading(document.createElement("form"));if(setTimeout(()=>{if(Q.pendingRequests.includes(J))Q.releaseRequest(J)},Q.config.maxHoldTime),Q.hasScore)Q.releaseRequest(J)})}}interceptXHR(){this.originalXHROpen=XMLHttpRequest.prototype.open,this.originalXHRSend=XMLHttpRequest.prototype.send;let Q=this;XMLHttpRequest.prototype.open=function(X,Y,Z=!0,$,J){let z=this;return z._bsMethod=X.toUpperCase(),z._bsUrl=Y.toString(),Q.originalXHROpen.call(this,X,Y,Z,$,J)},XMLHttpRequest.prototype.send=function(X){let Y=this,Z=Y._bsMethod||"GET",$=Y._bsUrl||"";if(Z!=="POST")return Q.originalXHRSend.call(this,X);try{if(new URL($,window.location.origin).origin!==window.location.origin)return Q.originalXHRSend.call(this,X)}catch{return Q.originalXHRSend.call(this,X)}if(Q.hasScore)return Q.originalXHRSend.call(this,X);let J=performance.now(),z=()=>{if(Q.hasScore){if(Q.config.showLoadingUI)Q.hideLoading();Q.originalXHRSend.call(Y,X)}else if(performance.now()-J>=Q.config.maxHoldTime){if(Q.config.showLoadingUI)Q.hideLoading();Q.originalXHRSend.call(Y,X)}else setTimeout(z,50)};if(Q.config.showLoadingUI)Q.showLoading(document.createElement("form"));z()}}releaseRequest(Q){let X=this.pendingRequests.indexOf(Q);if(X===-1)return;if(this.pendingRequests.splice(X,1),this.pendingRequests.length===0&&this.config.showLoadingUI)this.hideLoading();Q.execute().then(Q.resolve).catch(Q.reject)}protectForm(Q){if(this.protectedForms.has(Q))return;this.protectedForms.add(Q),Q.addEventListener("submit",(X)=>this.handleSubmit(X,Q),{capture:!0})}handleSubmit(Q,X){if(this.releasingForms.has(X)){this.releasingForms.delete(X);return}let Z=performance.now()-this.startTime;switch(N().markFirstSubmitAttempt(this.hasScore),this.config.mode){case"holdUntilReady":if(!this.hasScore)Q.preventDefault(),Q.stopPropagation(),this.holdSubmission(X,Q);break;case"holdUntilFormScored":Q.preventDefault(),Q.stopPropagation(),this.holdAndScoreSubmission(X,Q);break;case"blockInstant":if(Z<this.config.minTimeBeforeSubmit)Q.preventDefault(),Q.stopPropagation(),this.config.onBlock?.(X,"instant_submission");break;case"challengeFirst":if(!this.hasScore)Q.preventDefault(),Q.stopPropagation(),this.holdSubmission(X,Q);break;case"none":default:break}}holdSubmission(Q,X){if(this.config.onHold?.(Q),this.config.showLoadingUI)this.showLoading(Q);let Y={form:Q,event:X,timestamp:performance.now(),resolver:()=>{},rejecter:()=>{}},Z=new Promise(($,J)=>{Y.resolver=$,Y.rejecter=J});if(this.pendingSubmissions.push(Y),setTimeout(()=>{if(this.pendingSubmissions.includes(Y))this.releaseSubmission(Y,!1)},this.config.maxHoldTime),this.hasScore)this.releaseSubmission(Y,!1);Z.catch(()=>{})}async holdAndScoreSubmission(Q,X){if(this.config.onHold?.(Q),this.config.showLoadingUI)this.showLoading(Q);let Y=performance.now();try{if(!this.config.flushAndWaitForScore){this.submitForm(Q);return}let Z=this.config.flushAndWaitForScore(),$=new Promise((W)=>{setTimeout(()=>W(null),this.config.maxHoldTime)}),J=await Promise.race([Z,$]),z=performance.now()-Y;if(J===null);else this.currentScore=J,this.hasFormScore=!0;if(this.config.showLoadingUI)this.hideLoading();this.config.onRelease?.(Q,!1),this.submitForm(Q)}catch(Z){if(this.config.showLoadingUI)this.hideLoading();this.config.onRelease?.(Q,!1),this.submitForm(Q)}}submitForm(Q){if(this.releasingForms.add(Q),Q.requestSubmit)Q.requestSubmit();else Q.submit()}releaseSubmission(Q,X){let Y=this.pendingSubmissions.indexOf(Q);if(Y===-1)return;if(this.pendingSubmissions.splice(Y,1),this.config.showLoadingUI)this.hideLoading();if(this.config.onRelease?.(Q.form,X),!X)if(Q.resolver(),Q.form.requestSubmit)Q.form.requestSubmit();else Q.form.submit();else Q.rejecter("blocked")}showLoading(Q){if(this.loadingOverlay)return;this.loadingOverlay=document.createElement("div"),this.loadingOverlay.innerHTML=`
2
+ <div style="
3
+ position: fixed;
4
+ top: 0;
5
+ left: 0;
6
+ right: 0;
7
+ bottom: 0;
8
+ background: rgba(0, 0, 0, 0.5);
9
+ display: flex;
10
+ align-items: center;
11
+ justify-content: center;
12
+ z-index: 999999;
13
+ ">
14
+ <div style="
15
+ background: white;
16
+ padding: 24px 48px;
17
+ border-radius: 8px;
18
+ text-align: center;
19
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
20
+ ">
21
+ <div style="
22
+ width: 32px;
23
+ height: 32px;
24
+ border: 3px solid #e5e7eb;
25
+ border-top-color: #3b82f6;
26
+ border-radius: 50%;
27
+ margin: 0 auto 16px;
28
+ animation: bs-spin 0.8s linear infinite;
29
+ "></div>
30
+ <div style="color: #374151; font-size: 14px;">
31
+ ${this.config.loadingMessage}
32
+ </div>
33
+ </div>
34
+ </div>
35
+ <style>
36
+ @keyframes bs-spin {
37
+ to { transform: rotate(360deg); }
38
+ }
39
+ </style>
40
+ `,document.body.appendChild(this.loadingOverlay)}hideLoading(){if(this.loadingOverlay)this.loadingOverlay.remove(),this.loadingOverlay=null}notifyReady(Q){this.isReady=!0,this.hasScore=!0,this.currentScore=Q,[...this.pendingSubmissions].forEach((Z)=>{this.releaseSubmission(Z,!1)}),[...this.pendingRequests].forEach((Z)=>{this.releaseRequest(Z)}),this.hideLoading()}blockAllPending(Q){[...this.pendingSubmissions].forEach((Y)=>{this.config.onBlock?.(Y.form,Q),this.releaseSubmission(Y,!0)})}getStatus(){return{mode:this.config.mode,isReady:this.isReady,hasScore:this.hasScore,pendingCount:this.pendingSubmissions.length,protectedFormCount:this.protectedForms.size}}waitUntilReady(){if(this.hasScore)return Promise.resolve({score:this.currentScore,timedOut:!1});return new Promise((Q)=>{let X=performance.now(),Y=()=>{if(this.hasScore){Q({score:this.currentScore,timedOut:!1});return}if(performance.now()-X>=this.config.maxHoldTime){Q({score:null,timedOut:!0});return}setTimeout(Y,50)};Y()})}withProtection(Q){return async(...X)=>{let Y=performance.now()-this.startTime;if(N().markFirstSubmitAttempt(this.hasScore),this.config.mode==="blockInstant"&&Y<this.config.minTimeBeforeSubmit)throw this.config.onBlock?.(document.createElement("form"),"instant_submission"),Error("Submission blocked: too fast");if(this.config.mode==="holdUntilReady"&&!this.hasScore){if(this.config.showLoadingUI)this.showLoading(document.createElement("form"));let{timedOut:Z}=await this.waitUntilReady();if(this.config.showLoadingUI)this.hideLoading()}return Q(...X)}}protectedFetch(){return this.withProtection(async(Q,X)=>{return fetch(Q,X)})}setMode(Q){if(this.config.mode=Q,Q==="none")[...this.pendingSubmissions].forEach((Y)=>this.releaseSubmission(Y,!1))}setMaxHoldTime(Q){this.config.maxHoldTime=Q}canSubmit(){let Q=performance.now()-this.startTime;if(this.config.mode==="blockInstant"&&Q<this.config.minTimeBeforeSubmit)return{allowed:!1,reason:"too_fast",score:this.currentScore};if(this.config.mode==="holdUntilReady"&&!this.hasScore)return{allowed:!1,reason:"waiting_for_score",score:null};return{allowed:!0,score:this.currentScore}}destroy(){if(this.formObserver)this.formObserver.disconnect(),this.formObserver=null;if(this.originalFetch)window.fetch=this.originalFetch,this.originalFetch=null;if(this.originalXHROpen)XMLHttpRequest.prototype.open=this.originalXHROpen,this.originalXHROpen=null;if(this.originalXHRSend)XMLHttpRequest.prototype.send=this.originalXHRSend,this.originalXHRSend=null;this.hideLoading(),this.pendingSubmissions=[],this.pendingRequests=[],this.protectedForms.clear()}}var u={suspicious:40,bot:70},H={name:"_bsid",riskName:"_bsrisk",path:"/",sameSite:"Strict"};function d(Q){if(!Q)return null;if(Q===!0)return{...H};return{...H,...Q}}function a(Q){if(Q>=u.bot)return"bot";if(Q>=u.suspicious)return"suspicious";return"human"}class M{config;sessionIdGetter;sessionCookieSet=!1;currentRiskTier=null;constructor(Q,X){this.config={...H,...Q},this.sessionIdGetter=X}buildCookieString(Q,X){let Y=this.config.path||H.path,Z=this.config.sameSite||H.sameSite,$=this.config.secure??location.protocol==="https:",J=[`${encodeURIComponent(Q)}=${encodeURIComponent(X)}`,`Path=${Y}`,`SameSite=${Z}`];if($||Z==="None")J.push("Secure");return J.join("; ")}deleteCookie(Q){let X=this.config.path||H.path;document.cookie=`${encodeURIComponent(Q)}=; Path=${X}; Max-Age=0`}setSessionCookie(){if(this.sessionCookieSet)return;let Q=this.sessionIdGetter();if(!Q)return;let X=this.config.name||H.name;document.cookie=this.buildCookieString(X,Q),this.sessionCookieSet=!0}updateRiskTier(Q){let X=a(Q);if(X===this.currentRiskTier)return!1;let Y=this.config.riskName||H.riskName;document.cookie=this.buildCookieString(Y,X);let Z=this.currentRiskTier;return this.currentRiskTier=X,!0}removeCookies(){let Q=this.config.name||H.name,X=this.config.riskName||H.riskName;if(this.sessionCookieSet)this.deleteCookie(Q),this.sessionCookieSet=!1;if(this.currentRiskTier!==null)this.deleteCookie(X),this.currentRiskTier=null}setCookie(){this.setSessionCookie()}removeCookie(){this.removeCookies()}isSessionCookieSet(){return this.sessionCookieSet}getCurrentRiskTier(){return this.currentRiskTier}getSessionCookieName(){return this.config.name||H.name}getRiskCookieName(){return this.config.riskName||H.riskName}}var P={name:"X-BotSigged-ID"};function m(Q){if(!Q)return null;if(Q===!0)return{...P};return{...P,...Q}}class E{config;sessionIdGetter;started=!1;originalFetch=null;originalXHROpen=null;originalXHRSend=null;originalXHRSetRequestHeader=null;xhrInjectionMap=new WeakMap;constructor(Q,X){this.config={...P,...Q},this.sessionIdGetter=X}start(){if(this.started)return;this.started=!0,this.patchFetch(),this.patchXHR()}stop(){if(!this.started)return;if(this.originalFetch)window.fetch=this.originalFetch,this.originalFetch=null;if(this.originalXHROpen)XMLHttpRequest.prototype.open=this.originalXHROpen,this.originalXHROpen=null;if(this.originalXHRSend)XMLHttpRequest.prototype.send=this.originalXHRSend,this.originalXHRSend=null;if(this.originalXHRSetRequestHeader)XMLHttpRequest.prototype.setRequestHeader=this.originalXHRSetRequestHeader,this.originalXHRSetRequestHeader=null;this.started=!1}isSameOrigin(Q){try{let X;if(Q instanceof Request)X=new URL(Q.url,window.location.origin);else if(Q instanceof URL)X=Q;else X=new URL(Q,window.location.origin);return X.origin===window.location.origin}catch{return!0}}patchFetch(){this.originalFetch=window.fetch.bind(window);let Q=this,X=this.config.name||P.name;window.fetch=function(Y,Z){if(!Q.isSameOrigin(Y))return Q.originalFetch(Y,Z);let $=Q.sessionIdGetter();if(!$)return Q.originalFetch(Y,Z);let J=new Headers(Z?.headers);if(!J.has(X))J.set(X,$);return Q.originalFetch(Y,{...Z,headers:J})}}patchXHR(){this.originalXHROpen=XMLHttpRequest.prototype.open,this.originalXHRSend=XMLHttpRequest.prototype.send,this.originalXHRSetRequestHeader=XMLHttpRequest.prototype.setRequestHeader;let Q=this,X=this.config.name||P.name;XMLHttpRequest.prototype.open=function(Y,Z,$=!0,J,z){let W=Q.isSameOrigin(Z);return Q.xhrInjectionMap.set(this,W),Q.originalXHROpen.call(this,Y,Z,$,J,z)},XMLHttpRequest.prototype.send=function(Y){if(Q.xhrInjectionMap.get(this)){let Z=Q.sessionIdGetter();if(Z)try{Q.originalXHRSetRequestHeader.call(this,X,Z)}catch{}}return Q.originalXHRSend.call(this,Y)}}getHeaderName(){return this.config.name||P.name}isStarted(){return this.started}}var _={selector:"form",inputName:"_bsid"};function p(Q){if(!Q)return null;if(Q===!0)return{..._};return{..._,...Q}}class I{config;sessionIdGetter;observer=null;started=!1;constructor(Q,X){this.config={..._,...Q},this.sessionIdGetter=X}start(){if(this.started)return;this.started=!0;let Q=()=>{this.setupExistingForms(),this.setupObserver()};if(document.readyState==="loading")document.addEventListener("DOMContentLoaded",Q,{once:!0});else Q()}stop(){if(!this.started)return;if(this.observer)this.observer.disconnect(),this.observer=null;let Q=this.config.selector||_.selector,X=this.config.inputName||_.inputName;document.querySelectorAll(`${Q}[data-bs-inject-setup]`).forEach((Y)=>{if(Y instanceof HTMLFormElement)Y.removeEventListener("submit",this.handleSubmit,{capture:!0});Y.removeAttribute("data-bs-inject-setup");let Z=Y.querySelector(`input[name="${X}"][data-bs-injected]`);if(Z)Z.remove()}),this.started=!1}setupExistingForms(){let Q=this.config.selector||_.selector;document.querySelectorAll(Q).forEach((X)=>{if(X instanceof HTMLFormElement)this.setupForm(X)})}setupObserver(){if(!document.body)return;let Q=this.config.selector||_.selector;this.observer=new MutationObserver((X)=>{X.forEach((Y)=>{Y.addedNodes.forEach((Z)=>{if(Z instanceof HTMLFormElement&&Z.matches(Q))this.setupForm(Z);if(Z instanceof HTMLElement)Z.querySelectorAll(Q).forEach(($)=>{if($ instanceof HTMLFormElement)this.setupForm($)})})})}),this.observer.observe(document.body,{childList:!0,subtree:!0})}setupForm(Q){if(Q.hasAttribute("data-bs-inject-setup"))return;Q.setAttribute("data-bs-inject-setup","true"),Q.addEventListener("submit",this.handleSubmit,{capture:!0})}handleSubmit=(Q)=>{let X=Q.currentTarget;this.injectInput(X)};injectInput(Q){let X=this.config.inputName||_.inputName,Y=Q.querySelector(`input[name="${X}"]`);if(Y){if(Y.hasAttribute("data-bs-injected"))Y.value=this.sessionIdGetter();return}let Z=document.createElement("input");Z.type="hidden",Z.name=X,Z.value=this.sessionIdGetter(),Z.setAttribute("data-bs-injected","true"),Q.appendChild(Z)}getConfig(){return{...this.config}}isStarted(){return this.started}}async function kQ(){return await import("./hash-q46pgar4.js")}class S{config;mouseCollector;scrollCollector;formCollector;browserCollector;fingerprintGenerator;socket=null;sessionId;sequenceNumber=0;isRunning=!1;sendTimer=null;fingerprint=null;browserSignal=null;lastScore=null;hasSentInitial=!1;boundBeforeUnload=null;boundVisibilityChange=null;hashModule=null;formBlocked=!1;formObserver=null;highScoreTriggeredLevels=new Set;challengeManager=null;challengeManagerPromise=null;formProtectionManager=null;formSubmissionStatus="no_submission";cookieManager=null;headerInjector=null;formInjector=null;serverConfig=null;connectionState="disconnected";reconnectTimer=null;readyPromise;readyResolver=null;constructor(Q){if(K.markConstructorStart(),!Q.apiKey)throw Error("BotSigged: apiKey is required");if(this.config=h(Q),this.sessionId=this.generateSessionId(),this.readyPromise=new Promise(($)=>{this.readyResolver=$}),this.mouseCollector=new k({sampleRate:this.config.mouseSampleRate,maxBufferSize:this.config.maxBufferSize}),this.scrollCollector=new x({maxBufferSize:Math.floor(this.config.maxBufferSize/3)}),this.formCollector=new C({maxKeyEvents:this.config.maxBufferSize,onSubmit:()=>this.handleFormSubmit()}),this.browserCollector=new L,this.fingerprintGenerator=new b,this.config.hashVerification.enabled)this.initializeHashModule();if(this.config.action==="challenge"||this.config.challenge.enabled)this.challengeManagerPromise=this.initializeChallengeManager();if(this.config.formProtection.mode!=="none")this.formProtectionManager=new D({mode:this.config.formProtection.mode,minTimeBeforeSubmit:this.config.formProtection.minTimeBeforeSubmit,maxHoldTime:this.config.formProtection.maxHoldTime,showLoadingUI:this.config.formProtection.showLoadingUI,loadingMessage:this.config.formProtection.loadingMessage,onHold:($)=>{this.updateFormStatus("challenged"),this.config.formProtection.onHold?.($)},onRelease:($,J)=>{if(!J)this.updateFormStatus("completed");this.config.formProtection.onRelease?.($,J)},onBlock:($,J)=>{this.updateFormStatus("blocked"),this.config.formProtection.onBlock?.($,J)},flushAndWaitForScore:()=>this.sendSignalAndGetScore()}),this.log("Form protection enabled:",this.config.formProtection.mode);else this.log("Form protection disabled (mode='none')");let X=d(this.config.cookie);if(X)this.cookieManager=new M(X,()=>this.sessionId),this.log("Cookie manager enabled:",X.name);let Y=m(this.config.headers);if(Y)this.headerInjector=new E(Y,()=>this.sessionId),this.headerInjector.start(),this.log("Header injector enabled:",Y.name);let Z=p(this.config.formInject);if(Z)this.formInjector=new I(Z,()=>this.sessionId),this.formInjector.start(),this.log("Form injector enabled:",Z.inputName);if(this.config.autoStart)if(document.readyState==="loading")document.addEventListener("DOMContentLoaded",()=>this.start());else this.start();K.markConstructorEnd(),this.log("Constructor completed in",(K.getTimings().constructorEnd??0)-(K.getTimings().constructorStart??0),"ms")}async initializeHashModule(){try{let{initHashModule:Q}=await import("./hash-q46pgar4.js");this.hashModule=await Q({preferWasm:this.config.hashVerification.preferWasm,onWasmLoaded:()=>{this.log("WASM hash module loaded"),this.config.hashVerification.onWasmLoaded?.()},onFallback:(X)=>{this.log("Using JS hash fallback:",X),this.config.hashVerification.onWasmFallback?.(X)}})}catch(Q){this.log("Failed to initialize hash module",Q)}}async initializeChallengeManager(){try{let{ChallengeManager:Q}=await import("./challenge-8yg1wp51.js");this.challengeManager=new Q(this.config.challenge,this.config.debug),this.log("Challenge manager loaded")}catch(Q){this.log("Failed to initialize challenge manager",Q)}}async start(){if(this.isRunning){this.log("Already running");return}K.markStartCalled(),this.log("Starting BotSigged SDK"),this.isRunning=!0,this.connectionState="connecting";try{this.browserSignal=this.browserCollector.collect(),K.markFormCollectorStart(),this.mouseCollector.start(),this.scrollCollector.start(),this.formCollector.start(),K.markFormCollectorReady(),this.log("Collectors started in",(K.getTimings().formCollectorReady??0)-(K.getTimings().formCollectorStart??0),"ms"),K.markFingerprintStart(),K.markWsConnectStart();let[Q]=await Promise.all([this.fingerprintGenerator.generate(),this.connectWithRetry()]);this.fingerprint=Q,K.markFingerprintEnd(),this.log("Fingerprint generated in",(K.getTimings().fingerprintEnd??0)-(K.getTimings().fingerprintStart??0),"ms"),await this.joinChannel(),this.connectionState="connected",this.readyResolver?.(),K.markSdkReady(),this.startSendInterval(),this.registerBeforeUnload();let X=K.getSummary();if(this.log("SDK started successfully"),this.log("Total startup time:",X.totalStartupMs,"ms"),this.log("Time to first score:",X.timeToFirstScoreMs,"ms"),this.log("Vulnerability window:",X.vulnerabilityWindowMs,"ms"),this.config.debug)K.logSummary()}catch(Q){let X=Q instanceof Error?Q:Error(String(Q));this.log("Failed to start",X),this.handleConnectionFailure(X)}}async stop(){if(!this.isRunning)return;if(this.log("Stopping BotSigged SDK"),this.formProtectionManager)this.formProtectionManager.destroy(),this.formProtectionManager=null;if(this.cookieManager)this.cookieManager.removeCookies(),this.cookieManager=null;if(this.headerInjector)this.headerInjector.stop(),this.headerInjector=null;if(this.formInjector)this.formInjector.stop(),this.formInjector=null;if(this.formObserver)this.formObserver.disconnect(),this.formObserver=null;this.unregisterBeforeUnload(),this.mouseCollector.stop(),this.scrollCollector.stop(),this.formCollector.stop(),this.stopSendInterval(),await this.sendSignal(),await this.disconnect(),this.isRunning=!1,this.log("SDK stopped")}async sendSignal(){if(!this.socket?.isReady()){this.log("Cannot send signal: not connected");return}let Q=this.buildPayload(),X=Q.seq;this.log("Sending signal seq:",X),K.markSignalSent(X);try{let Y=await this.socket.sendSignal(Q);K.markSignalResponseReceived(X);let Z=K.getTimings().signalRoundtrips||[],$=Z[Z.length-1];if($)this.log("Signal roundtrip:",$.roundtripMs,"ms");if(Y.bot_score!==void 0){let J={bot_score:Y.bot_score,classification:Y.classification||"unknown",triggered_rules:Y.triggered_rules||[]};this.lastScore=J,this.config.onScoreUpdate?.(J),this.handleScoreUpdate(J)}this.mouseCollector.flush(),this.scrollCollector.flush(),this.formCollector.flush(),this.hasSentInitial=!0}catch(Y){let Z=Y instanceof Error?Y:Error(String(Y));this.log("Failed to send signal",Z),this.config.onError?.(Z)}}async sendSignalAndGetScore(){if(!this.socket?.isReady())return this.log("Cannot send signal: not connected"),null;let Q=this.buildPayload(),X=Q.seq;this.log("Sending signal for form scoring, seq:",X);try{let Y=await this.socket.sendSignal(Q);if(Y.bot_score!==void 0){let Z={bot_score:Y.bot_score,classification:Y.classification||"unknown",triggered_rules:Y.triggered_rules||[]};return this.lastScore=Z,this.config.onScoreUpdate?.(Z),this.handleScoreUpdate(Z),this.mouseCollector.flush(),this.scrollCollector.flush(),this.formCollector.flush(),this.hasSentInitial=!0,Z.bot_score}return this.mouseCollector.flush(),this.scrollCollector.flush(),this.formCollector.flush(),this.hasSentInitial=!0,null}catch(Y){let Z=Y instanceof Error?Y:Error(String(Y));return this.log("Failed to send signal for form scoring",Z),this.config.onError?.(Z),null}}getSessionId(){return this.sessionId}getFingerprint(){return this.fingerprint}getFormSubmissionStatus(){return this.formSubmissionStatus}getLastScore(){return this.lastScore}isConnected(){return this.socket?.isReady()??!1}whenReady(){if(this.connectionState==="connected")return Promise.resolve();return this.readyPromise}getConnectionState(){return this.connectionState}getServerConfig(){return this.serverConfig}async identify(Q){let{accountId:X}=Q;if(!X||typeof X!=="string")throw Error("BotSigged: accountId is required and must be a string");if(X.length>255)throw Error("BotSigged: accountId must be 255 characters or less");this.log("Identifying account:",X),await this.whenReady();try{let Y=await this.socket.sendEvent("identify",{account_id:X,timestamp:Date.now()});if(Y.identified)this.log("Account identified successfully");else throw Error(Y.reason?.toString()||"Failed to identify account")}catch(Y){let Z=Y instanceof Error?Y:Error(String(Y));throw this.log("Failed to identify account:",Z),this.config.onError?.(Z),Z}}isDegraded(){return this.connectionState==="degraded"||this.connectionState==="failed"}getCurrentSignals(){return{mouse:this.mouseCollector.getSignal(),scroll:this.scrollCollector.getSignal(),form:this.formCollector.getSignal(),browser:this.browserSignal}}getBufferSizes(){return{mouse:this.mouseCollector.getBufferSize(),scroll:this.scrollCollector.getBufferSize(),form:this.formCollector.getBufferSize()}}resetSignals(){this.mouseCollector.reset(),this.scrollCollector.reset(),this.formCollector.reset(),this.browserCollector.reset(),this.sequenceNumber=0,this.hasSentInitial=!1}async connectSocket(){this.socket=new A({endpoint:this.config.endpoint,apiKey:this.config.apiKey,debug:this.config.debug,onConnectionChange:(Q)=>{this.config.onConnectionChange?.(Q==="connected")},onError:(Q)=>{this.config.onError?.(Q)}}),await this.socket.connect(),K.markWsConnectEnd(),this.log("WebSocket connected in",(K.getTimings().wsConnectEnd??0)-(K.getTimings().wsConnectStart??0),"ms")}async connectWithRetry(){let X=[1000,2000,4000];for(let Y=0;Y<3;Y++)try{await this.connectSocket();return}catch(Z){if(this.log(`Connection attempt ${Y+1} failed:`,Z),Y<2)await this.sleep(X[Y]);else throw Z}}sleep(Q){return new Promise((X)=>setTimeout(X,Q))}handleConnectionFailure(Q){this.connectionState="failed";let X=this.config.fallbackMode||"degraded";switch(this.log("Connection failed, applying fallback mode:",X),X){case"open":if(this.connectionState="degraded",this.formProtectionManager)this.formProtectionManager.setMode("none"),this.formProtectionManager.notifyReady(0);break;case"closed":this.blockFormsUntilConnected(),this.scheduleReconnect();break;case"cached":let Y=this.loadCachedConfig();if(Y)this.applyServerConfig(Y),this.connectionState="degraded";else this.applyFallbackConfig();this.scheduleReconnect();break;case"degraded":default:this.applyFallbackConfig(),this.connectionState="degraded",this.scheduleReconnect();break}this.config.onError?.(Q),this.config.onConnectionChange?.(!1)}applyFallbackConfig(){if(this.log("Applying fallback config"),this.serverConfig=F,this.formProtectionManager&&this.serverConfig.form_protection_mode)this.formProtectionManager.setMode(this.serverConfig.form_protection_mode);this.config.onServerConfig?.(this.serverConfig,"fallback")}blockFormsUntilConnected(){if(this.formProtectionManager)this.formProtectionManager.setMode("holdUntilReady"),this.formProtectionManager.setMaxHoldTime(30000)}scheduleReconnect(){if(this.reconnectTimer)clearTimeout(this.reconnectTimer);this.reconnectTimer=setTimeout(()=>{this.attemptReconnect()},5000)}async attemptReconnect(){this.log("Attempting reconnection..."),this.connectionState="connecting";try{if(await this.connectWithRetry(),!this.fingerprint)this.fingerprint=await this.fingerprintGenerator.generate();if(await this.joinChannel(),this.connectionState="connected",this.readyResolver?.(),this.log("Reconnection successful"),!this.sendTimer)this.startSendInterval()}catch(Q){this.log("Reconnection failed:",Q),this.connectionState="failed"}}cacheServerConfig(Q){try{localStorage.setItem(`botsigged_config_${this.config.apiKey}`,JSON.stringify({config:Q,timestamp:Date.now()}))}catch{}}loadCachedConfig(){try{let Q=localStorage.getItem(`botsigged_config_${this.config.apiKey}`);if(!Q)return null;let{config:X,timestamp:Y}=JSON.parse(Q);if(Date.now()-Y>86400000)return localStorage.removeItem(`botsigged_config_${this.config.apiKey}`),null;return X}catch{return null}}applyServerConfig(Q){if(this.log("Applying server config:",Q),this.serverConfig=Q,this.formProtectionManager&&Q.form_protection_mode)this.formProtectionManager.setMode(Q.form_protection_mode);if(Q.action&&Q.action!=="none")this.applyServerAction(Q.action,Q.challenge);this.cacheServerConfig(Q),this.config.onServerConfig?.(Q,"server")}async applyServerAction(Q,X){switch(this.log("Applying server action:",Q),Q){case"block":if(!this.formBlocked)this.blockForms();break;case"challenge":if(!this.challengeManager&&!this.challengeManagerPromise)this.log("Lazily loading challenge manager for server-requested challenge"),this.challengeManagerPromise=this.initializeChallengeManager();if(this.challengeManagerPromise)await this.challengeManagerPromise;if(this.challengeManager){let Y=X?.difficulty?.bot??16,Z=Y>=18?"critical":Y>=16?"high":"medium";this.challengeManager.blockFormsUntilSolved(Z)}else this.log("Challenge requested but challenge manager failed to load");break;case"flag":this.log("Session flagged by server");break;case"none":default:break}}handleServerAction(Q){this.log("Received server action:",Q),this.config.onServerAction?.(Q);let X=Q.challenge?{difficulty:{suspicious:Q.challenge.difficulty,bot:Q.challenge.difficulty},timeout_ms:Q.challenge.timeout_ms}:void 0;this.applyServerAction(Q.type,X)}async joinChannel(){if(!this.socket)throw Error("WebSocket not initialized");K.markChannelJoinStart();let Q;try{Q=await this.socket.joinChannel(this.sessionId,this.fingerprint,this.getSessionData(),this.browserSignal,{onScoreUpdate:(X)=>{this.lastScore=X,this.config.onScoreUpdate?.(X),this.handleScoreUpdate(X)},onError:(X)=>{this.config.onError?.(X)},onAction:(X)=>{this.handleServerAction(X)}},this.config.accountId)}catch(X){if(T(X)){if(this.log("Usage limit exceeded:",X),this.config.onUsageLimitExceeded)this.config.onUsageLimitExceeded(X);else this.config.onError?.(Error(`Usage limit exceeded: ${X.current_usage}/${X.limit} verifications (${X.plan_name} plan). Please upgrade your plan.`));return}throw X}if(K.markChannelJoinEnd(),this.log("Channel joined in",(K.getTimings().channelJoinEnd??0)-(K.getTimings().channelJoinStart??0),"ms"),Q.config){let X=Q.config;this.applyServerConfig(X)}if(Q.initial_score!==void 0){K.markInitialScoreReceived();let X={bot_score:Q.initial_score,classification:Q.classification||"unknown",triggered_rules:Q.triggered_rules||[]};if(this.lastScore=X,this.config.onScoreUpdate?.(X),this.handleScoreUpdate(X),this.formProtectionManager)this.formProtectionManager.notifyReady(X.bot_score);if(this.cookieManager)this.cookieManager.setCookie();this.log("Initial score received:",X.bot_score,"in",(K.getTimings().initialScoreReceived??0)-(K.getTimings().startCalled??0),"ms from start")}}handleScoreUpdate(Q){if(this.cookieManager)this.cookieManager.updateRiskTier(Q.bot_score);let X=this.getBotScoreLevel(Q.bot_score),Y=Q.bot_score>=this.config.actionThreshold;if(this.shouldTriggerAlert(X)){let Z={score:Q.bot_score,level:X,scoreUpdate:Q,sessionId:this.sessionId,fingerprintHash:this.fingerprint?.hash};if(Y&&!this.highScoreTriggeredLevels.has(X))this.executeAction(Z);this.config.onHighBotScore?.(Z),this.highScoreTriggeredLevels.add(X)}}getBotScoreLevel(Q){let X=this.config.botScoreThresholds;if(Q>=X.critical)return"critical";if(Q>=X.high)return"high";if(Q>=X.medium)return"medium";return"low"}shouldTriggerAlert(Q){if(this.highScoreTriggeredLevels.has(Q))return!1;let X=["low","medium","high","critical"],Y=this.config.minAlertLevel,Z=X.indexOf(Q),$=X.indexOf(Y);return Z>=$}async executeAction(Q){let X=this.config.action;switch(this.log(`Executing action '${X}' for score ${Q.score}`),X){case"challenge":if(this.challengeManagerPromise)await this.challengeManagerPromise;if(this.challengeManager)this.challengeManager.blockFormsUntilSolved(Q.level);break;case"block":if(!this.formBlocked)this.blockForms();break;case"none":default:break}}blockForms(){if(this.formBlocked)return;this.formBlocked=!0,document.querySelectorAll("form").forEach((Q)=>{Q.addEventListener("submit",this.blockFormSubmit,!0)}),this.formObserver=new MutationObserver((Q)=>{Q.forEach((X)=>{X.addedNodes.forEach((Y)=>{if(Y instanceof HTMLFormElement)Y.addEventListener("submit",this.blockFormSubmit,!0);if(Y instanceof HTMLElement)Y.querySelectorAll("form").forEach((Z)=>{Z.addEventListener("submit",this.blockFormSubmit,!0)})})})}),this.formObserver.observe(document.body,{childList:!0,subtree:!0}),this.log("Forms blocked due to high bot score")}blockFormSubmit=(Q)=>{Q.preventDefault(),Q.stopPropagation(),this.log("Form submission blocked due to high bot score");return};isFormsBlocked(){return this.formBlocked}unblockForms(){if(!this.formBlocked)return;if(this.formObserver)this.formObserver.disconnect(),this.formObserver=null;document.querySelectorAll("form").forEach((Q)=>{Q.removeEventListener("submit",this.blockFormSubmit,!0)}),this.formBlocked=!1,this.log("Forms unblocked")}getHashModule(){return this.hashModule}createSignature(Q){let X=this.config.hashVerification.secret;if(!X)return this.log("Cannot create signature: no secret configured"),null;return createSignature(Q,X)}verifySignature(Q,X){let Y=this.config.hashVerification.secret;if(!Y)return this.log("Cannot verify signature: no secret configured"),!1;return verifySignature(Q,X,Y)}isChallengeSolving(){return this.challengeManager?.isSolving()??!1}isChallengeSolved(){return this.challengeManager?.isSolved()??!1}getPerformanceSummary(){return K.getSummary()}logPerformance(){K.logSummary()}getPerformanceReport(){return K.getReport()}async waitUntilReady(){if(this.lastScore)return{score:this.lastScore.bot_score,timedOut:!1};if(this.formProtectionManager)return this.formProtectionManager.waitUntilReady();return new Promise((Q)=>{let X=performance.now(),Y=5000,Z=()=>{if(this.lastScore){Q({score:this.lastScore.bot_score,timedOut:!1});return}if(performance.now()-X>=5000){Q({score:null,timedOut:!0});return}setTimeout(Z,50)};Z()})}withProtection(Q,X={}){let Y=X.blockThreshold??this.config.actionThreshold;return async(...Z)=>{let{score:$,timedOut:J}=await this.waitUntilReady();if(K.markFirstSubmitAttempt($!==null),$!==null&&$>=Y)throw this.log(`Blocking submission: score ${$} >= threshold ${Y}`),Error(`Submission blocked: bot score ${$} exceeds threshold`);if(J)this.log("Warning: submitting without detection score (timed out)");return Q(...Z)}}protectedFetch(Q={}){return this.withProtection(async(X,Y)=>{return fetch(X,Y)},Q)}canSubmit(){if(!this.lastScore)return{allowed:!1,reason:"waiting_for_score",score:null};if(this.lastScore.bot_score>=this.config.actionThreshold)return{allowed:!1,reason:"high_bot_score",score:this.lastScore.bot_score};return{allowed:!0,score:this.lastScore.bot_score}}async triggerChallenge(Q="high"){if(this.challengeManagerPromise)await this.challengeManagerPromise;if(!this.challengeManager){this.log("Challenge not enabled");return}this.challengeManager.blockFormsUntilSolved(Q)}async disconnect(){if(this.socket)await this.socket.leaveChannel(),this.socket.disconnect(),this.socket=null}startSendInterval(){this.stopSendInterval(),this.sendTimer=setInterval(()=>{this.sendSignal()},this.config.sendInterval)}stopSendInterval(){if(this.sendTimer)clearInterval(this.sendTimer),this.sendTimer=null}registerBeforeUnload(){this.boundBeforeUnload=()=>{this.handleBeforeUnload()},this.boundVisibilityChange=()=>{if(document.visibilityState==="hidden")this.handleBeforeUnload()},window.addEventListener("beforeunload",this.boundBeforeUnload),document.addEventListener("visibilitychange",this.boundVisibilityChange)}unregisterBeforeUnload(){if(this.boundBeforeUnload)window.removeEventListener("beforeunload",this.boundBeforeUnload),this.boundBeforeUnload=null;if(this.boundVisibilityChange)document.removeEventListener("visibilitychange",this.boundVisibilityChange),this.boundVisibilityChange=null}handleBeforeUnload(){if(!this.isRunning||!this.socket)return;try{let Q=this.buildPayload();if(this.socket.isReady())this.socket.sendSignal(Q).catch(()=>{})}catch{}}handleFormSubmit(){if(!this.isRunning)return;if(K.markFirstSubmitAttempt(this.lastScore!==null),this.log("Form submitted, flushing signals via beacon"),this.log("Had score before submit:",this.lastScore!==null),this.updateFormStatus("completed"),!this.sessionId){this.log("No session ID yet, cannot send beacon");return}let Q=this.buildPayload();if(!this.sendViaBeacon(Q))this.sendSignal().catch((Y)=>{this.log("Failed to flush signals on form submit",Y)});else this.mouseCollector.flush(),this.scrollCollector.flush(),this.formCollector.flush()}sendViaBeacon(Q){if(!navigator.sendBeacon)return this.log("sendBeacon not available"),!1;try{let X=new URL(this.config.endpoint),Y=`${X.protocol==="wss:"?"https:":"http:"}//${X.host}/api/signal`,Z=JSON.stringify({session_id:this.sessionId,api_key:this.config.apiKey,payload:Q,form_status:this.formSubmissionStatus}),$=new Blob([Z],{type:"application/json"}),J=navigator.sendBeacon(Y,$);return this.log("Beacon sent:",J),J}catch(X){return this.log("Beacon send failed:",X),!1}}buildPayload(){this.sequenceNumber++;let Q={session_id:this.sessionId,seq:this.sequenceNumber,mouse:this.mouseCollector.getSignal(),scroll:this.scrollCollector.getSignal(),form:this.formCollector.getSignal(),timestamp:Date.now()};if(!this.hasSentInitial)Q.session=this.getSessionData(),Q.fingerprint=this.fingerprint,Q.browser=this.browserSignal;return Q}getSessionData(){let Q=new URL(window.location.href),X={};Q.searchParams.forEach((Z,$)=>{X[$]=Z});let Y=null;if(document.referrer)try{Y=new URL(document.referrer).hostname}catch{}return{url_path:Q.pathname,url_params:X,referrer_url:document.referrer||null,referrer_domain:Y,user_agent:navigator.userAgent}}generateSessionId(){if(crypto.randomUUID)return crypto.randomUUID();return"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,(Q)=>{let X=Math.random()*16|0;return(Q==="x"?X:X&3|8).toString(16)})}updateFormStatus(Q){if(this.formSubmissionStatus==="blocked"||this.formSubmissionStatus==="completed"){this.log(`Form status already terminal (${this.formSubmissionStatus}), ignoring ${Q}`);return}if(this.formSubmissionStatus==="challenged"&&Q!=="completed"){this.log(`Form status is challenged, can only become completed, ignoring ${Q}`);return}if(this.formSubmissionStatus=Q,this.log(`Form status updated to: ${Q}`),this.socket?.isReady())this.socket.sendFormStatus(Q).catch((X)=>{this.log("Failed to send form status:",X)})}log(...Q){if(this.config.debug);}}var O=null;function xQ(Q){if(O)return O;return O=new S(Q),O}function CQ(){return O}async function LQ(){if(O)await O.stop(),O=null}var AQ=S;export{f as logPerformanceSummary,kQ as loadHashModule,T as isUsageLimitError,xQ as init,l as getPerformanceSummary,N as getPerformanceMetrics,CQ as getInstance,LQ as destroy,AQ as default,q as DEFAULT_CONFIG,S as BotSigged};
41
+
42
+ //# debugId=7176A7404A75914864756E2164756E21
package/package.json ADDED
@@ -0,0 +1,51 @@
1
+ {
2
+ "name": "@botsigged/sdk",
3
+ "version": "1.0.0",
4
+ "description": "BotSigged SDK - Real-time bot detection via WebSocket",
5
+ "main": "./dist/index.js",
6
+ "module": "./dist/index.js",
7
+ "type": "module",
8
+ "exports": {
9
+ ".": {
10
+ "import": "./dist/index.js"
11
+ },
12
+ "./browser": "./dist/botsigged.js"
13
+ },
14
+ "files": [
15
+ "dist"
16
+ ],
17
+ "sideEffects": false,
18
+ "scripts": {
19
+ "build": "bun run build:all",
20
+ "build:all": "bun run build:wasm && bun run build:esm && bun run build:iife",
21
+ "build:wasm": "bun run scripts/build-wasm.ts",
22
+ "build:esm": "bun build ./src/index.ts --outdir ./dist --target browser --format esm --sourcemap=external --splitting --minify --drop=console --drop=debugger",
23
+ "build:iife": "bun build ./src/browser.ts --outfile ./dist/botsigged.js --target browser --format iife --minify --drop=console --drop=debugger",
24
+ "build:iife:dev": "bun build ./src/browser.ts --outfile ./dist/botsigged.js --target browser --format iife --minify",
25
+ "build:ts": "bun run build:esm && bun run build:iife",
26
+ "build:watch": "bun build ./src/index.ts --outdir ./dist --target browser --format esm --sourcemap=external --watch",
27
+ "watch": "bun run build:watch",
28
+ "deploy": "bun run build:wasm && bun run build:iife:dev && mkdir -p ../web/priv/static/js && cp ./dist/botsigged.js ../web/priv/static/js/botsigged.js && echo 'Deployed to Phoenix!'",
29
+ "dev": "bun run deploy && bun run watch:deploy",
30
+ "watch:deploy": "echo 'Watching for changes...' && while true; do inotifywait -q -e modify ./dist/index.js && cp ./dist/index.js ../web/priv/static/assets/js/botsigged.js && echo 'SDK updated!'; done",
31
+ "test": "bun test",
32
+ "test:watch": "bun test --watch",
33
+ "serve": "bunx serve -l 3000",
34
+ "prepublishOnly": "rm -f dist/*.map"
35
+ },
36
+ "keywords": [
37
+ "bot-detection",
38
+ "fingerprinting",
39
+ "websocket",
40
+ "security",
41
+ "hash-verification",
42
+ "wasm"
43
+ ],
44
+ "author": "BotSigged",
45
+ "license": "MIT",
46
+ "homepage": "https://botsigged.com",
47
+ "devDependencies": {
48
+ "assemblyscript": "^0.28.9",
49
+ "bun-types": "latest"
50
+ }
51
+ }