UNPKG

@tinytapanalytics/sdk

Version:

Behavioral psychology platform that detects visitor frustration, predicts abandonment, and helps you save at-risk conversions in real-time

1 lines 75.5 kB
class t{constructor(t,e){this.queue=[],this.isProcessing=!1,this.processingInterval=null,this.persistenceKey="tinytapanalytics_event_queue",this.maxQueueSize=1e3,this.maxRetries=3,this.retentionHours=24,this.config=t,this.networkManager=e,this.loadPersistedEvents(),this.startProcessing(),this.setupUnloadHandler()}async enqueue(t,e="normal"){const n={id:this.generateEventId(),payload:t,queuedAt:Date.now(),attempts:0,priority:e};if("high"===e&&this.networkManager.canSendData()&&0===this.queue.length)try{return void(this.config.useFallbackStrategy?await this.networkManager.sendWithFallback(t):await this.networkManager.sendEvent(t))}catch(i){}this.queue.push(n),this.sortQueue(),this.queue.length>this.maxQueueSize&&(this.queue=this.queue.filter((t,e)=>"low"!==t.priority||e>=this.queue.length-this.maxQueueSize+100).slice(-this.maxQueueSize)),this.persistQueue(),"high"!==e||this.isProcessing||this.processQueue()}async flush(){if(0===this.queue.length)return;const t=[...this.queue];this.queue=[];try{const e=this.config.batchSize||10,n=this.chunkArray(t.map(t=>t.payload),e);for(const t of n)1===t.length?await this.networkManager.sendEvent(t[0]):await this.networkManager.sendBatch(t);this.clearPersistedQueue()}catch(e){throw this.queue=t.concat(this.queue),this.sortQueue(),e}}getStats(){return{queueSize:this.queue.length,isProcessing:this.isProcessing,highPriorityCount:this.queue.filter(t=>"high"===t.priority).length,failedEventCount:this.queue.filter(t=>t.attempts>=this.maxRetries).length}}startProcessing(){const t=this.config.flushInterval||5e3;this.processingInterval=window.setInterval(()=>{!this.isProcessing&&this.queue.length>0&&this.processQueue()},t)}async processQueue(){if(!this.isProcessing&&0!==this.queue.length&&this.networkManager.canSendData()){this.isProcessing=!0;try{const e=this.config.batchSize||10,n=this.queue.splice(0,e);if(0===n.length)return;const i=n.filter(t=>0===t.attempts),s=n.filter(t=>t.attempts>0);if(i.length>0)try{if(this.config.useFallbackStrategy)for(const e of i)try{await this.networkManager.sendWithFallback(e.payload)}catch(t){this.handleFailedEvent(e,t)}else 1===i.length?await this.networkManager.sendEvent(i[0].payload):await this.networkManager.sendBatch(i.map(t=>t.payload))}catch(t){this.config.useFallbackStrategy||this.handleFailedEvents(i,t)}for(const o of s)try{this.config.useFallbackStrategy?await this.networkManager.sendWithFallback(o.payload):await this.networkManager.sendEvent(o.payload)}catch(t){this.handleFailedEvent(o,t)}this.persistQueue()}finally{this.isProcessing=!1}this.queue.length>0&&setTimeout(()=>this.processQueue(),1e3)}}handleFailedEvents(t,e){t.forEach(t=>this.handleFailedEvent(t,e))}handleFailedEvent(t,e){if(t.attempts++,t.attempts<this.maxRetries){const e=Math.min(1e3*Math.pow(2,t.attempts)+1e3*Math.random(),3e4);t.nextRetry=Date.now()+e,this.queue.push(t),this.sortQueue()}else this.config.debug}sortQueue(){this.queue.sort((t,e)=>{const n={high:3,normal:2,low:1},i=n[e.priority]-n[t.priority];if(0!==i)return i;const s=!t.nextRetry||Date.now()>=t.nextRetry,o=!e.nextRetry||Date.now()>=e.nextRetry;return s&&!o?-1:!s&&o?1:t.queuedAt-e.queuedAt})}loadPersistedEvents(){try{const t=localStorage.getItem(this.persistenceKey);if(t){const e=JSON.parse(t);if(Array.isArray(e.events)){const t=Date.now()-60*this.retentionHours*60*1e3;this.queue=e.events.filter(e=>e.queuedAt>t),this.sortQueue(),this.config.debug&&this.queue.length}}}catch(t){this.config.debug}}persistQueue(){try{const t={timestamp:Date.now(),events:this.queue};localStorage.setItem(this.persistenceKey,JSON.stringify(t))}catch(t){this.config.debug}}clearPersistedQueue(){try{localStorage.removeItem(this.persistenceKey)}catch(t){}}setupUnloadHandler(){const t=()=>{if(this.queue.length>0){this.queue.filter(t=>"high"===t.priority).slice(0,5).map(t=>t.payload).forEach(t=>{this.networkManager.sendBeacon(t)}),this.persistQueue()}};window.addEventListener("beforeunload",t),window.addEventListener("visibilitychange",()=>{"hidden"===document.visibilityState&&t()})}chunkArray(t,e){const n=[];for(let i=0;i<t.length;i+=e)n.push(t.slice(i,i+e));return n}generateEventId(){return"evt_"+Date.now().toString(36)+"_"+Math.random().toString(36).substring(2,11)}destroy(){this.processingInterval&&(clearInterval(this.processingInterval),this.processingInterval=null),this.queue.length>0&&this.persistQueue(),this.queue=[],this.isProcessing=!1}}class e{constructor(t,e){this.config=t,this.errorHandler=e}async request(t){const e=t.retry?.maxAttempts||this.config.retry?.maxAttempts||3,n=t.retry?.baseDelay||this.config.retry?.baseDelay||1e3,i=t.retry?.maxDelay||this.config.retry?.maxDelay||3e4;let s=null;for(let r=1;r<=e;r++)try{const e=await this.makeRequest(t);return this.config.debug,e}catch(o){if(s=o,this.config.debug,o instanceof Error&&"status"in o){const t=o.status;if(400===t||401===t||403===t||404===t)throw o}if(r<e){const t=Math.min(n*Math.pow(2,r-1)+1e3*Math.random(),i);await this.sleep(t)}}if(s)throw this.errorHandler.handle(s,"network_request"),s;throw new Error("Request failed after all retry attempts")}async sendBatch(t){const e={url:`${this.config.endpoint}/api/v1/events/batch`,method:"POST",headers:{"Content-Type":"application/json","X-TinyTapAnalytics-SDK":"3.3.0","X-TinyTapAnalytics-User-Agent":navigator.userAgent},body:JSON.stringify(t),timeout:this.config.timeout||5e3};await this.request(e)}async sendEvent(t){const e={url:`${this.config.endpoint}/api/v1/events`,method:"POST",headers:{"Content-Type":"application/json","X-TinyTapAnalytics-SDK":"3.3.0","X-TinyTapAnalytics-User-Agent":navigator.userAgent},body:JSON.stringify(t),timeout:this.config.timeout||5e3};await this.request(e)}async ping(){try{const t={url:`${this.config.endpoint}/api/v1/ping`,method:"GET",headers:{Authorization:`Bearer ${this.config.apiKey}`},timeout:3e3,retry:{maxAttempts:1,baseDelay:0,maxDelay:0}};return await this.request(t),!0}catch(t){return!1}}async makeRequest(t){return new Promise((e,n)=>{const i=new XMLHttpRequest,s=t.timeout||this.config.timeout||5e3,o=setTimeout(()=>{i.abort(),n(new Error(`Request timeout after ${s}ms`))},s);i.onreadystatechange=()=>{if(i.readyState===XMLHttpRequest.DONE){clearTimeout(o);const s={status:i.status,statusText:i.statusText,data:this.parseResponse(i.responseText),headers:this.parseHeaders(i.getAllResponseHeaders()),request:t};if(i.status>=200&&i.status<300)e(s);else{const t=new Error(`Request failed with status ${i.status}: ${i.statusText}`);t.status=i.status,t.response=s,n(t)}}},i.onerror=()=>{clearTimeout(o),n(new Error("Network error occurred"))},i.onabort=()=>{clearTimeout(o),n(new Error("Request was aborted"))},i.open(t.method,t.url,!0),t.headers&&Object.entries(t.headers).forEach(([t,e])=>{try{i.setRequestHeader(t,e)}catch(n){this.config.debug}}),i.send(t.body||null)})}parseResponse(t){if(!t)return null;try{return JSON.parse(t)}catch(e){return t}}parseHeaders(t){const e={};return t?(t.split("\r\n").forEach(t=>{const n=t.indexOf(":");if(n>0){const i=t.substring(0,n).trim().toLowerCase(),s=t.substring(n+1).trim();e[i]=s}}),e):e}sleep(t){return new Promise(e=>setTimeout(e,t))}canSendData(){if(!navigator.onLine)return!1;const t=navigator.connection||navigator.mozConnection||navigator.webkitConnection;if(t){if("slow-2g"===t.effectiveType)return!1;if(t.saveData)return!1}return!0}sendBeacon(t){if("function"!=typeof navigator.sendBeacon)return!1;const e=`${this.config.endpoint}/api/v1/events`,n=new Blob([JSON.stringify(t)],{type:"application/json"});try{return navigator.sendBeacon(e,n)}catch(i){return this.config.debug,!1}}sendImageBeacon(t){return new Promise(e=>{const n=new Image,i=new URL(`${this.config.endpoint}/api/v1/events/pixel`),s=this.compressEventForBeacon(t);i.searchParams.append("d",btoa(JSON.stringify(s))),i.searchParams.append("t",Date.now().toString()),n.onload=()=>{this.config.debug,e(!0)},n.onerror=()=>{this.config.debug,e(!1)},n.src=i.toString()})}async sendWithFallback(t){try{return await this.sendEvent(t),!0}catch(e){if(this.config.debug,"function"==typeof navigator.sendBeacon){if(this.sendBeacon(t))return this.config.debug,!0}return this.config.debug,await this.sendImageBeacon(t)}}compressEventForBeacon(t){return{e:t.event_type,w:t.website_id,s:t.session_id,u:t.user_id,t:t.timestamp,p:t.page_url,m:this.compressMetadata(t.metadata)}}compressMetadata(t){if(!t)return{};const e={device_type:t.device_type,viewport_width:t.viewport_width,viewport_height:t.viewport_height,language:t.language},n={...t};delete n.device_type,delete n.viewport_width,delete n.viewport_height,delete n.screen_width,delete n.screen_height,delete n.timezone,delete n.language,delete n.user_context,delete n.sdk_version;return JSON.stringify(n).length<500&&(e.custom=n),e}async requestWithCredentials(t){return new Promise((e,n)=>{const i=new XMLHttpRequest;this.config.withCredentials&&(i.withCredentials=!0);const s=t.timeout||this.config.timeout||5e3,o=setTimeout(()=>{i.abort(),n(new Error(`Request timeout after ${s}ms`))},s);i.onreadystatechange=()=>{if(i.readyState===XMLHttpRequest.DONE){clearTimeout(o);const s={status:i.status,statusText:i.statusText,data:this.parseResponse(i.responseText),headers:this.parseHeaders(i.getAllResponseHeaders()),request:t};if(i.status>=200&&i.status<300)e(s);else{const t=new Error(`Request failed with status ${i.status}: ${i.statusText}`);t.status=i.status,t.response=s,n(t)}}},i.onerror=()=>{clearTimeout(o),n(new Error("Network error occurred (possibly CORS)"))},i.onabort=()=>{clearTimeout(o),n(new Error("Request was aborted"))},i.open(t.method,t.url,!0),t.headers&&Object.entries(t.headers).forEach(([t,e])=>{try{i.setRequestHeader(t,e)}catch(n){this.config.debug}}),i.send(t.body||null)})}}class n{constructor(){this.styleSheet=null,this.components=new Map,this.componentCounter=0,this.shadowHost=this.createShadowHost(),this.shadowRoot=this.shadowHost.attachShadow({mode:"closed"}),this.initializeStyles()}createShadowHost(){const t=document.createElement("div");return t.id="tinytapanalytics-shadow-host",t.style.cssText="\n position: fixed;\n top: -9999px;\n left: -9999px;\n width: 0;\n height: 0;\n pointer-events: none;\n z-index: 2147483647;\n ",document.body.appendChild(t),t}initializeStyles(){if("adoptedStyleSheets"in this.shadowRoot)try{return this.styleSheet=new CSSStyleSheet,this.styleSheet.replaceSync(this.getBaseStyles()),void(this.shadowRoot.adoptedStyleSheets=[this.styleSheet])}catch(e){}const t=document.createElement("style");t.textContent=this.getBaseStyles(),this.shadowRoot.appendChild(t)}getBaseStyles(){return'\n /* Reset and base styles */\n *, *::before, *::after {\n box-sizing: border-box;\n margin: 0;\n padding: 0;\n }\n\n /* Base typography */\n .ciq-component {\n font-family: -apple-system, BlinkMacSystemFont, \'Segoe UI\', Roboto, Helvetica, Arial, sans-serif;\n font-size: 14px;\n line-height: 1.5;\n color: #374151;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n }\n\n /* Modal styles */\n .ciq-modal-overlay {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.5);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: 10000;\n opacity: 0;\n transition: opacity 0.2s ease-in-out;\n pointer-events: auto;\n }\n\n .ciq-modal-overlay.ciq-show {\n opacity: 1;\n }\n\n .ciq-modal {\n background: white;\n border-radius: 8px;\n box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);\n max-width: 500px;\n max-height: 90vh;\n width: 90%;\n overflow: hidden;\n transform: scale(0.95);\n transition: transform 0.2s ease-in-out;\n }\n\n .ciq-modal-overlay.ciq-show .ciq-modal {\n transform: scale(1);\n }\n\n .ciq-modal-header {\n padding: 20px 24px 0;\n border-bottom: 1px solid #e5e7eb;\n }\n\n .ciq-modal-title {\n font-size: 18px;\n font-weight: 600;\n color: #111827;\n margin-bottom: 8px;\n }\n\n .ciq-modal-body {\n padding: 20px 24px;\n max-height: 60vh;\n overflow-y: auto;\n }\n\n .ciq-modal-footer {\n padding: 20px 24px;\n border-top: 1px solid #e5e7eb;\n display: flex;\n gap: 12px;\n justify-content: flex-end;\n }\n\n /* Consent modal specific styles */\n .consent-modal .ciq-modal {\n max-width: 600px;\n }\n\n .ciq-consent-content h3 {\n font-size: 20px;\n font-weight: 600;\n color: #111827;\n margin-bottom: 16px;\n }\n\n .ciq-consent-content p {\n color: #6b7280;\n margin-bottom: 24px;\n line-height: 1.6;\n }\n\n .ciq-consent-options {\n space-y: 16px;\n margin-bottom: 24px;\n }\n\n .ciq-consent-option {\n margin-bottom: 16px;\n }\n\n .ciq-checkbox-label {\n display: flex;\n align-items: flex-start;\n gap: 12px;\n cursor: pointer;\n padding: 16px;\n border: 1px solid #e5e7eb;\n border-radius: 6px;\n transition: border-color 0.2s, background-color 0.2s;\n }\n\n .ciq-checkbox-label:hover {\n border-color: #d1d5db;\n background-color: #f9fafb;\n }\n\n .ciq-checkbox-label input[type="checkbox"] {\n position: absolute;\n opacity: 0;\n cursor: pointer;\n }\n\n .ciq-checkmark {\n position: relative;\n height: 20px;\n width: 20px;\n background-color: #fff;\n border: 2px solid #d1d5db;\n border-radius: 4px;\n flex-shrink: 0;\n transition: all 0.2s;\n }\n\n .ciq-checkbox-label input:checked ~ .ciq-checkmark {\n background-color: #3b82f6;\n border-color: #3b82f6;\n }\n\n .ciq-checkbox-label input:disabled ~ .ciq-checkmark {\n background-color: #f3f4f6;\n border-color: #e5e7eb;\n }\n\n .ciq-checkmark:after {\n content: "";\n position: absolute;\n display: none;\n left: 6px;\n top: 2px;\n width: 6px;\n height: 10px;\n border: solid white;\n border-width: 0 2px 2px 0;\n transform: rotate(45deg);\n }\n\n .ciq-checkbox-label input:checked ~ .ciq-checkmark:after {\n display: block;\n }\n\n .ciq-option-details {\n flex: 1;\n }\n\n .ciq-option-details strong {\n display: block;\n font-weight: 600;\n color: #111827;\n margin-bottom: 4px;\n }\n\n .ciq-option-details p {\n color: #6b7280;\n font-size: 13px;\n margin: 0;\n }\n\n .ciq-consent-actions {\n display: flex;\n gap: 12px;\n flex-wrap: wrap;\n justify-content: flex-end;\n margin-bottom: 16px;\n }\n\n .ciq-consent-footer p {\n font-size: 12px;\n color: #9ca3af;\n margin: 0;\n text-align: center;\n }\n\n /* Button styles */\n .ciq-btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n padding: 8px 16px;\n border: 1px solid transparent;\n border-radius: 6px;\n font-size: 14px;\n font-weight: 500;\n text-decoration: none;\n cursor: pointer;\n transition: all 0.2s;\n min-width: 80px;\n }\n\n .ciq-btn-primary {\n background-color: #3b82f6;\n color: white;\n border-color: #3b82f6;\n }\n\n .ciq-btn-primary:hover {\n background-color: #2563eb;\n border-color: #2563eb;\n }\n\n .ciq-btn-secondary {\n background-color: #f3f4f6;\n color: #374151;\n border-color: #d1d5db;\n }\n\n .ciq-btn-secondary:hover {\n background-color: #e5e7eb;\n border-color: #9ca3af;\n }\n\n /* Notification styles */\n .ciq-notification {\n position: fixed;\n top: 20px;\n right: 20px;\n background: white;\n border-radius: 8px;\n box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);\n padding: 16px;\n max-width: 400px;\n border-left: 4px solid #3b82f6;\n transform: translateX(100%);\n transition: transform 0.3s ease-in-out;\n z-index: 10001;\n pointer-events: auto;\n }\n\n .ciq-notification.ciq-show {\n transform: translateX(0);\n }\n\n .ciq-notification.ciq-success {\n border-left-color: #10b981;\n }\n\n .ciq-notification.ciq-warning {\n border-left-color: #f59e0b;\n }\n\n .ciq-notification.ciq-error {\n border-left-color: #ef4444;\n }\n\n .ciq-notification-message {\n font-size: 14px;\n color: #374151;\n line-height: 1.5;\n }\n\n /* Loading spinner */\n .ciq-spinner {\n width: 20px;\n height: 20px;\n border: 2px solid #f3f4f6;\n border-top: 2px solid #3b82f6;\n border-radius: 50%;\n animation: ciq-spin 1s linear infinite;\n }\n\n @keyframes ciq-spin {\n 0% { transform: rotate(0deg); }\n 100% { transform: rotate(360deg); }\n }\n\n /* Responsive design */\n @media (max-width: 640px) {\n .ciq-modal {\n width: 95%;\n margin: 20px;\n }\n\n .ciq-modal-body {\n max-height: 50vh;\n }\n\n .ciq-consent-actions {\n flex-direction: column;\n }\n\n .ciq-btn {\n width: 100%;\n }\n\n .ciq-notification {\n left: 20px;\n right: 20px;\n max-width: none;\n }\n }\n\n /* Dark mode support */\n @media (prefers-color-scheme: dark) {\n .ciq-modal {\n background: #1f2937;\n color: #f9fafb;\n }\n\n .ciq-modal-header {\n border-bottom-color: #374151;\n }\n\n .ciq-modal-footer {\n border-top-color: #374151;\n }\n\n .ciq-modal-title {\n color: #f9fafb;\n }\n\n .ciq-checkbox-label {\n border-color: #374151;\n background-color: #1f2937;\n }\n\n .ciq-checkbox-label:hover {\n border-color: #4b5563;\n background-color: #111827;\n }\n\n .ciq-checkmark {\n background-color: #374151;\n border-color: #4b5563;\n }\n\n .ciq-option-details strong {\n color: #f9fafb;\n }\n\n .ciq-btn-secondary {\n background-color: #374151;\n color: #f9fafb;\n border-color: #4b5563;\n }\n\n .ciq-btn-secondary:hover {\n background-color: #4b5563;\n border-color: #6b7280;\n }\n\n .ciq-notification {\n background: #1f2937;\n color: #f9fafb;\n }\n }\n\n /* High contrast mode support */\n @media (prefers-contrast: high) {\n .ciq-modal {\n border: 2px solid currentColor;\n }\n\n .ciq-btn {\n border-width: 2px;\n }\n\n .ciq-checkmark {\n border-width: 3px;\n }\n }\n\n /* Reduced motion support */\n @media (prefers-reduced-motion: reduce) {\n *, *::before, *::after {\n animation-duration: 0.01ms !important;\n animation-iteration-count: 1 !important;\n transition-duration: 0.01ms !important;\n }\n }\n\n /* Consent Banner Styles */\n .ciq-consent-banner {\n position: fixed;\n bottom: 0;\n left: 0;\n right: 0;\n background: white;\n border-top: 1px solid #e5e7eb;\n box-shadow: 0 -4px 6px -1px rgba(0, 0, 0, 0.1), 0 -2px 4px -1px rgba(0, 0, 0, 0.06);\n padding: 16px 24px;\n z-index: 10000;\n transform: translateY(100%);\n transition: transform 0.3s ease-in-out;\n pointer-events: auto;\n }\n\n .ciq-consent-banner.ciq-show {\n transform: translateY(0);\n }\n\n .ciq-consent-banner-content {\n max-width: 1200px;\n margin: 0 auto;\n display: flex;\n align-items: center;\n gap: 24px;\n }\n\n .ciq-consent-banner-text {\n flex: 1;\n min-width: 0;\n }\n\n .ciq-consent-banner-text h4 {\n font-size: 15px;\n font-weight: 600;\n color: #111827;\n margin: 0 0 4px 0;\n }\n\n .ciq-consent-banner-text p {\n font-size: 13px;\n color: #6b7280;\n margin: 0;\n line-height: 1.4;\n }\n\n .ciq-consent-banner-actions {\n display: flex;\n gap: 12px;\n align-items: center;\n flex-shrink: 0;\n }\n\n .ciq-consent-banner-close {\n position: absolute;\n top: 12px;\n right: 12px;\n width: 24px;\n height: 24px;\n border: none;\n background: transparent;\n color: #9ca3af;\n cursor: pointer;\n padding: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 4px;\n transition: all 0.2s;\n }\n\n .ciq-consent-banner-close:hover {\n background: #f3f4f6;\n color: #374151;\n }\n\n .ciq-consent-banner-close svg {\n width: 16px;\n height: 16px;\n }\n\n .ciq-btn-link {\n background: transparent;\n color: #3b82f6;\n border: none;\n padding: 8px 12px;\n font-size: 14px;\n font-weight: 500;\n cursor: pointer;\n text-decoration: underline;\n transition: color 0.2s;\n }\n\n .ciq-btn-link:hover {\n color: #2563eb;\n }\n\n .ciq-btn-small {\n padding: 6px 12px;\n font-size: 13px;\n min-width: 70px;\n }\n\n /* Mobile responsiveness for banner */\n @media (max-width: 768px) {\n .ciq-consent-banner {\n padding: 16px;\n }\n\n .ciq-consent-banner-content {\n flex-direction: column;\n align-items: stretch;\n gap: 16px;\n }\n\n .ciq-consent-banner-actions {\n flex-direction: column;\n width: 100%;\n }\n\n .ciq-consent-banner-actions .ciq-btn {\n width: 100%;\n }\n }\n\n /* Dark mode for banner */\n @media (prefers-color-scheme: dark) {\n .ciq-consent-banner {\n background: #1f2937;\n border-top-color: #374151;\n }\n\n .ciq-consent-banner-text h4 {\n color: #f9fafb;\n }\n\n .ciq-consent-banner-text p {\n color: #d1d5db;\n }\n\n .ciq-consent-banner-close {\n color: #9ca3af;\n }\n\n .ciq-consent-banner-close:hover {\n background: #374151;\n color: #f9fafb;\n }\n }\n '}sanitizeText(t){const e=document.createElement("div");return e.textContent=t,e.innerHTML}createModal(t){const e="modal_"+Date.now()+"_"+ ++this.componentCounter,n=document.createElement("div");n.className="ciq-modal-overlay ciq-component",t.className&&n.classList.add(t.className);const i=document.createElement("div");if(i.className="ciq-modal",t.width&&(i.style.width=t.width),t.height&&(i.style.height=t.height),t.title){const e=document.createElement("div");e.className="ciq-modal-header";const n=document.createElement("h2");n.className="ciq-modal-title",n.textContent=t.title,e.appendChild(n),i.appendChild(e)}const s=document.createElement("div");if(s.className="ciq-modal-body",t.allowHTML?s.innerHTML=t.content:s.textContent=t.content,i.appendChild(s),n.appendChild(i),!t.persistent){n.addEventListener("click",t=>{t.target===n&&this.hide(e)});const t=n=>{"Escape"===n.key&&(this.hide(e),document.removeEventListener("keydown",t))};document.addEventListener("keydown",t)}return this.components.set(e,n),this.shadowRoot.appendChild(n),n}createNotification(t){const e="notification_"+Date.now()+"_"+ ++this.componentCounter,n=document.createElement("div");n.className=`ciq-notification ciq-component ciq-${t.type||"info"}`;const i=document.createElement("div");return i.className="ciq-notification-message",i.textContent=t.message,n.appendChild(i),this.components.set(e,n),this.shadowRoot.appendChild(n),0!==t.duration&&setTimeout(()=>{this.hide(e)},t.duration||4e3),n}createBanner(t){const e="banner_"+Date.now()+"_"+ ++this.componentCounter,n=document.createElement("div");return n.className="ciq-consent-banner ciq-component",t.className&&n.classList.add(t.className),t.allowHTML?n.innerHTML=t.content:n.textContent=t.content,this.components.set(e,n),this.shadowRoot.appendChild(n),n}show(t){this.shadowHost.style.cssText="\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n pointer-events: none;\n z-index: 2147483647;\n ",requestAnimationFrame(()=>{t.classList.add("ciq-show")})}hide(t){let e,n;if("string"==typeof t)n=t,e=this.components.get(n);else{e=t;for(const[t,i]of this.components.entries())if(i===e){n=t;break}}e&&n&&(e.classList.remove("ciq-show"),setTimeout(()=>{e&&this.shadowRoot.contains(e)&&this.shadowRoot.removeChild(e),n&&this.components.delete(n),0===this.components.size&&(this.shadowHost.style.cssText="\n position: fixed;\n top: -9999px;\n left: -9999px;\n width: 0;\n height: 0;\n pointer-events: none;\n z-index: 2147483647;\n ")},200))}hideAll(){Array.from(this.components.keys()).forEach(t=>this.hide(t))}updateStyles(t){if(this.styleSheet)try{this.styleSheet.insertRule(t)}catch(e){}else{const e=this.shadowRoot.querySelector("style");e&&(e.textContent+="\n"+t)}}hasVisibleComponents(){return this.components.size>0}getComponentCount(){return this.components.size}destroy(){this.hideAll(),setTimeout(()=>{this.shadowHost&&this.shadowHost.parentNode&&this.shadowHost.parentNode.removeChild(this.shadowHost),this.components.clear(),this.styleSheet&&(this.styleSheet=null)},300)}}class i{constructor(t){this.consentData=null,this.STORAGE_KEY="tinytapanalytics_consent",this.CONSENT_VERSION="1.0",this.CONSENT_DURATION=33696e6,this.DEFAULT_CONSENT={essential:!0,functional:!1,analytics:!1,marketing:!1},this.config=t,this.loadConsentData()}async init(){try{this.loadConsentData(),this.needsConsent()&&await this.showConsentUI(),this.cleanupExpiredData()}catch(t){this.consentData={version:this.CONSENT_VERSION,timestamp:Date.now(),settings:{...this.DEFAULT_CONSENT},jurisdiction:"unknown",expiresAt:Date.now()+this.CONSENT_DURATION}}}canTrack(t){return this.consentData?Date.now()>this.consentData.expiresAt?(this.clearConsentData(),"essential"===t):this.consentData.settings[t]||!1:"essential"===t}updateConsent(t){this.consentData||(this.consentData={version:this.CONSENT_VERSION,timestamp:Date.now(),settings:{...this.DEFAULT_CONSENT},jurisdiction:this.detectJurisdiction(),expiresAt:Date.now()+this.CONSENT_DURATION}),this.consentData.settings={...this.consentData.settings,...t,essential:!0},this.consentData.timestamp=Date.now(),this.saveConsentData(),this.shadowDOM&&this.hideConsentUI()}getConsentStatus(){return this.consentData?.settings||{...this.DEFAULT_CONSENT}}needsConsent(){return this.consentData?(Date.now()>this.consentData.expiresAt||this.consentData.version!==this.CONSENT_VERSION)&&this.requiresConsent():this.requiresConsent()}requiresConsent(){const t=this.detectJurisdiction();return["AT","BE","BG","HR","CY","CZ","DK","EE","FI","FR","DE","GR","HU","IE","IT","LV","LT","LU","MT","NL","PL","PT","RO","SK","SI","ES","SE","IS","LI","NO","GB"].includes(t)||"EU"===t||["CA","US-CA"].includes(t)||!0===this.config.enablePrivacyMode}detectJurisdiction(){try{const t=Intl.DateTimeFormat().resolvedOptions().timeZone;if(t.startsWith("Europe/")){const e=t.split("/")[1];return{London:"GB",Berlin:"DE",Paris:"FR",Rome:"IT",Madrid:"ES",Amsterdam:"NL",Vienna:"AT",Brussels:"BE",Prague:"CZ",Warsaw:"PL",Stockholm:"SE",Oslo:"NO"}[e]||"EU"}if(t.includes("Los_Angeles")||t.includes("San_Francisco"))return"US-CA";if(t.startsWith("America/"))return"US"}catch(e){}const t=navigator.language||navigator.languages?.[0]||"";return t.startsWith("en-GB")||t.startsWith("en-EU")?"EU":t.startsWith("en-US")?"US":"unknown"}async showConsentUI(){this.shadowDOM||(this.shadowDOM=new n);const t=this.detectJurisdiction(),e=t.startsWith("EU")||"GB"===t,i=this.shadowDOM.createBanner({content:this.createConsentBannerContent(e),allowHTML:!0});this.attachBannerHandlers(i,e),this.shadowDOM.show(i)}showConsentModal(){this.shadowDOM||(this.shadowDOM=new n);const t=this.detectJurisdiction(),e=t.startsWith("EU")||"GB"===t,i="US-CA"===t,s=this.shadowDOM.createModal({title:e?"Cookie Preferences":"Privacy Preferences",content:this.createConsentContent(e,i),persistent:!1,className:"consent-modal",allowHTML:!0});this.attachConsentHandlers(s,e,i),this.shadowDOM.show(s)}createConsentBannerContent(t){return`\n <button class="ciq-consent-banner-close" id="banner-close" aria-label="Close banner">\n <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">\n <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />\n </svg>\n </button>\n <div class="ciq-consent-banner-content">\n <div class="ciq-consent-banner-text">\n <h4>Cookie Notice</h4>\n <p>${t?"We use cookies to enhance your browsing experience and analyze our traffic.":"We use cookies and similar technologies to improve your experience."}</p>\n </div>\n <div class="ciq-consent-banner-actions">\n ${t?'<button id="banner-reject" class="ciq-btn ciq-btn-secondary ciq-btn-small">Reject All</button>':""}\n <button id="banner-manage" class="ciq-btn-link">Manage Preferences</button>\n <button id="banner-accept" class="ciq-btn ciq-btn-primary ciq-btn-small">Accept All</button>\n </div>\n </div>\n `}attachBannerHandlers(t,e){const n=t.getRootNode(),i=n.getElementById("banner-close");i?.addEventListener("click",()=>{this.updateConsent({essential:!0,functional:!1,analytics:!1,marketing:!1})});const s=n.getElementById("banner-accept");if(s?.addEventListener("click",()=>{this.updateConsent({essential:!0,functional:!0,analytics:!0,marketing:!0})}),e){const t=n.getElementById("banner-reject");t?.addEventListener("click",()=>{this.updateConsent({essential:!0,functional:!1,analytics:!1,marketing:!1})})}const o=n.getElementById("banner-manage");o?.addEventListener("click",()=>{this.shadowDOM&&this.shadowDOM.hide(t),this.showConsentModal()})}createConsentContent(t,e){return`\n <div class="ciq-consent-content">\n <h3>${t?"We value your privacy":"Your Privacy Choices"}</h3>\n <p>${t?"We use cookies and similar technologies to provide, protect and improve our services. You can choose which types of cookies you allow.":"We collect and use personal information to provide and improve our services. You can control how we use this information."}</p>\n \n <div class="ciq-consent-options">\n <div class="ciq-consent-option">\n <label class="ciq-checkbox-label">\n <input type="checkbox" id="essential" checked disabled>\n <span class="ciq-checkmark"></span>\n <div class="ciq-option-details">\n <strong>Essential</strong>\n <p>Required for basic website functionality. Always active.</p>\n </div>\n </label>\n </div>\n \n <div class="ciq-consent-option">\n <label class="ciq-checkbox-label">\n <input type="checkbox" id="functional">\n <span class="ciq-checkmark"></span>\n <div class="ciq-option-details">\n <strong>Functional</strong>\n <p>Enables enhanced features like click tracking and user interface improvements.</p>\n </div>\n </label>\n </div>\n \n <div class="ciq-consent-option">\n <label class="ciq-checkbox-label">\n <input type="checkbox" id="analytics">\n <span class="ciq-checkmark"></span>\n <div class="ciq-option-details">\n <strong>Analytics</strong>\n <p>Helps us understand how you use our website to improve your experience.</p>\n </div>\n </label>\n </div>\n \n <div class="ciq-consent-option">\n <label class="ciq-checkbox-label">\n <input type="checkbox" id="marketing">\n <span class="ciq-checkmark"></span>\n <div class="ciq-option-details">\n <strong>Marketing</strong>\n <p>Allows us to measure the effectiveness of our optimization recommendations.</p>\n </div>\n </label>\n </div>\n </div>\n \n <div class="ciq-consent-actions">\n ${t?'<button id="reject-all" class="ciq-btn ciq-btn-secondary">Reject All</button>':""}\n <button id="accept-selected" class="ciq-btn ciq-btn-primary">Save Preferences</button>\n <button id="accept-all" class="ciq-btn ciq-btn-primary">Accept All</button>\n </div>\n \n <div class="ciq-consent-footer">\n <p>You can change these settings at any time. For more information, see our privacy policy.</p>\n </div>\n </div>\n `}attachConsentHandlers(t,e,n){const i=t.getRootNode(),s=i.getElementById("accept-all");if(s?.addEventListener("click",()=>{this.updateConsent({essential:!0,functional:!0,analytics:!0,marketing:!0})}),e){const t=i.getElementById("reject-all");t?.addEventListener("click",()=>{this.updateConsent({essential:!0,functional:!1,analytics:!1,marketing:!1})})}const o=i.getElementById("accept-selected");o?.addEventListener("click",()=>{const t=i.getElementById("functional")?.checked||!1,e=i.getElementById("analytics")?.checked||!1,n=i.getElementById("marketing")?.checked||!1;this.updateConsent({essential:!0,functional:t,analytics:e,marketing:n})})}hideConsentUI(){this.shadowDOM&&this.shadowDOM.hideAll()}loadConsentData(){try{const t=localStorage.getItem(this.STORAGE_KEY);if(t){const e=JSON.parse(t);e.version&&e.timestamp&&e.settings&&e.expiresAt&&(this.consentData=e)}}catch(t){}}saveConsentData(){if(this.consentData)try{localStorage.setItem(this.STORAGE_KEY,JSON.stringify(this.consentData))}catch(t){}}clearConsentData(){this.consentData=null;try{localStorage.removeItem(this.STORAGE_KEY)}catch(t){}}cleanupExpiredData(){try{const t=Object.keys(localStorage),e=Date.now();t.forEach(t=>{if(t.startsWith("tinytapanalytics_")&&t.includes("_consent_"))try{const n=JSON.parse(localStorage.getItem(t)||"{}");n.expiresAt&&e>n.expiresAt&&localStorage.removeItem(t)}catch(n){localStorage.removeItem(t)}})}catch(t){}}getPrivacyCompliantUserId(){if(!this.canTrack("analytics"))return null;const t="tinytapanalytics_user_id";try{let e=localStorage.getItem(t);return e||(e="ciq_"+Date.now().toString(36)+Math.random().toString(36).substring(2),localStorage.setItem(t,e)),e}catch(e){return"ciq_session_"+Date.now().toString(36)+Math.random().toString(36).substring(2)}}destroy(){this.hideConsentUI(),this.shadowDOM&&this.shadowDOM.destroy()}}class s{constructor(){this.detectionCache=new Map,this.environmentInfo=this.detectEnvironment()}getEnvironmentInfo(){return{...this.environmentInfo}}isSPA(){return this.environmentInfo.isSPA}isSSR(){return this.environmentInfo.isSSR}getFramework(){return this.environmentInfo.framework}getPlatform(){return this.environmentInfo.platform}getBrowserInfo(){return{...this.environmentInfo.browser}}getDeviceInfo(){return{...this.environmentInfo.device}}getNetworkInfo(){return this.environmentInfo.network?{...this.environmentInfo.network}:void 0}hasTouchSupport(){return this.getCachedResult("touchSupport",()=>"ontouchstart"in window||navigator.maxTouchPoints>0||"msMaxTouchPoints"in navigator)}isMobile(){return"mobile"===this.environmentInfo.device.type}isTablet(){return"tablet"===this.environmentInfo.device.type}isDesktop(){return"desktop"===this.environmentInfo.device.type}isWebView(){return this.getCachedResult("webView",()=>{const t=navigator.userAgent.toLowerCase();return t.includes("wv")||t.includes("webview")||void 0!==window.AndroidInterface||void 0!==window.webkit?.messageHandlers||t.includes("fban")||t.includes("fbav")||t.includes("instagram")||t.includes("twitter")})}supportsModernFeatures(){return this.getCachedResult("modernFeatures",()=>"fetch"in window&&"Promise"in window&&"IntersectionObserver"in window&&"requestIdleCallback"in window)}supportsServiceWorkers(){return this.getCachedResult("serviceWorkers",()=>"serviceWorker"in navigator)}supportsLocalStorage(){return this.getCachedResult("localStorage",()=>{try{const t="tinytapanalytics_test";return localStorage.setItem(t,t),localStorage.removeItem(t),!0}catch{return!1}})}async isPrivateMode(){return new Promise(t=>{if("webkitRequestFileSystem"in window)window.webkitRequestFileSystem(0,1,()=>t(!1),()=>t(!0));else if("webkitTemporaryStorage"in navigator)navigator.webkitTemporaryStorage.queryUsageAndQuota(()=>t(!1),()=>t(!0));else{if("MozAppearance"in document.documentElement.style){const e=indexedDB.open("test");return e.onerror=()=>t(!0),void(e.onsuccess=()=>t(!1))}try{0===localStorage.length?(localStorage.setItem("private_test","1"),"1"===localStorage.getItem("private_test")?(localStorage.removeItem("private_test"),t(!1)):t(!0)):t(!1)}catch{t(!0)}}})}getViewportDimensions(){return{width:window.innerWidth||document.documentElement.clientWidth,height:window.innerHeight||document.documentElement.clientHeight}}getScreenDimensions(){return{width:screen.width,height:screen.height}}getPixelDensity(){return window.devicePixelRatio||1}detectEnvironment(){return{framework:this.detectFramework(),isSPA:this.detectSPA(),isSSR:this.detectSSR(),platform:this.detectPlatform(),browser:this.detectBrowser(),device:this.detectDevice(),network:this.detectNetwork()}}detectFramework(){return this.getCachedResult("framework",()=>window.React||document.querySelector("[data-reactroot]")||document.querySelector("[data-react-helmet]")||Array.from(document.querySelectorAll("*")).some(t=>Object.keys(t).some(t=>t.startsWith("__react")))?"react":window.Vue||document.querySelector("[data-v-]")||document.querySelector("[v-cloak]")||document.querySelector(".v-enter")||Array.from(document.querySelectorAll("*")).some(t=>Array.from(t.attributes).some(t=>t.name.startsWith("v-")))?"vue":window.ng||window.angular||document.querySelector("[ng-app]")||document.querySelector("[ng-controller]")||document.querySelector("[ng-if]")||document.querySelector("ng-component")||Array.from(document.querySelectorAll("*")).some(t=>t.tagName.includes("-")&&t.tagName.includes("APP"))?"angular":"vanilla")}detectSPA(){return this.getCachedResult("spa",()=>{const t="pushState"in history,e=window.location.hash.includes("#/"),n=!!document.querySelector('meta[name="router"]'),i="vanilla"!==this.detectFramework(),s=Array.from(document.scripts).some(t=>"module"===t.type||t.src.includes("chunk")||t.src.includes("bundle"));return t&&(e||n||i||s)})}detectSSR(){return this.getCachedResult("ssr",()=>{const t=document.querySelector('meta[name="generator"]')||document.querySelector('meta[name="rendered-by"]'),e=document.querySelector("#__next")||document.querySelector('script[src*="/_next/"]'),n=document.querySelector("#__nuxt")||document.querySelector('script[src*="/_nuxt/"]'),i=document.documentElement.innerHTML.includes("data-ssr")||document.documentElement.innerHTML.includes("server-rendered");return!!(t||e||n||i)})}detectPlatform(){return this.getCachedResult("platform",()=>{if(document.querySelector("html[amp]")||document.querySelector("html[⚡]")||document.querySelector('script[src*="ampproject.org"]'))return"amp";const t=navigator.userAgent.toLowerCase(),e=this.getScreenDimensions(),n=t.includes("mobile")||t.includes("iphone")||t.includes("ipod")||e.width<=768,i=t.includes("tablet")||t.includes("ipad")||t.includes("android")&&!t.includes("mobile");return n||i?"mobile-web":"web"})}detectBrowser(){return this.getCachedResult("browser",()=>{const t=navigator.userAgent.toLowerCase();let e="unknown",n="unknown",i="unknown";return t.includes("edg/")?(e="edge",n=this.extractVersion(t,"edg/"),i="blink"):t.includes("chrome/")?(e="chrome",n=this.extractVersion(t,"chrome/"),i="blink"):t.includes("firefox/")?(e="firefox",n=this.extractVersion(t,"firefox/"),i="gecko"):t.includes("safari/")&&!t.includes("chrome")?(e="safari",n=this.extractVersion(t,"version/"),i="webkit"):(t.includes("opera/")||t.includes("opr/"))&&(e="opera",n=this.extractVersion(t,t.includes("opr/")?"opr/":"opera/"),i="blink"),{name:e,version:n,engine:i}})}detectDevice(){return this.getCachedResult("device",()=>{const t=navigator.userAgent.toLowerCase(),e=this.getScreenDimensions();let n="desktop",i="unknown";return t.includes("tablet")||t.includes("ipad")||t.includes("android")&&!t.includes("mobile")?n="tablet":(t.includes("mobile")||t.includes("iphone")||t.includes("ipod")||e.width<=768)&&(n="mobile"),t.includes("iphone")||t.includes("ipad")||t.includes("ipod")?i="ios":t.includes("android")?i="android":t.includes("windows")?i="windows":t.includes("macintosh")||t.includes("mac os")?i="macos":t.includes("linux")&&(i="linux"),{type:n,os:i,screenSize:e}})}detectNetwork(){const t=navigator.connection||navigator.mozConnection||navigator.webkitConnection;if(t)return{effectiveType:t.effectiveType,downlink:t.downlink,rtt:t.rtt}}extractVersion(t,e){const n=t.match(new RegExp(e+"([\\d\\.]+)"));return n?n[1]:"unknown"}getCachedResult(t,e){if(this.detectionCache.has(t))return this.detectionCache.get(t);const n=e();return this.detectionCache.set(t,n),n}updateEnvironmentInfo(){this.detectionCache.clear(),this.environmentInfo=this.detectEnvironment()}getPerformanceTiming(){if(!window.performance||!window.performance.timing)return null;const t=window.performance.timing;return{navigationStart:t.navigationStart,domContentLoaded:t.domContentLoadedEventEnd-t.navigationStart,loadComplete:t.loadEventEnd-t.navigationStart,domInteractive:t.domInteractive-t.navigationStart,firstPaint:this.getFirstPaintTime(),firstContentfulPaint:this.getFirstContentfulPaintTime()}}getFirstPaintTime(){if(window.performance&&window.performance.getEntriesByType){const t=window.performance.getEntriesByType("paint").find(t=>"first-paint"===t.name);return t?t.startTime:0}return 0}getFirstContentfulPaintTime(){if(window.performance&&window.performance.getEntriesByType){const t=window.performance.getEntriesByType("paint").find(t=>"first-contentful-paint"===t.name);return t?t.startTime:0}return 0}}class o{constructor(t,e=3e4){this.errorCount=0,this.maxErrors=10,this.errorBuffer=[],this.reportingInterval=null,this.isShutdown=!1,this.config=t,this.reportingIntervalMs=e,this.setupGlobalErrorHandling(),this.startErrorReporting()}handle(t,e,n){if(!this.isShutdown)try{const i=this.createSDKError(t,e,n);if(this.config.debug,this.errorCount++,this.errorCount>this.maxErrors)return void this.shutdown();this.bufferError(i),this.handleSpecificError(i)}catch(i){this.config.debug,this.shutdown()}}warn(t,e,n){this.config.debug;const i={code:"WARNING",message:t,context:e||"general",timestamp:Date.now(),originalError:void 0,stack:(new Error).stack};this.bufferError(i)}getStats(){return{errorCount:this.errorCount,isShutdown:this.isShutdown,bufferSize:this.errorBuffer.length}}shutdown(){this.isShutdown||(this.isShutdown=!0,this.reportingInterval&&(clearInterval(this.reportingInterval),this.reportingInterval=null),this.reportErrors(),this.config.debug)}createSDKError(t,e,n){return{code:this.getErrorCode(t),message:t.message||"Unknown error",context:e||"unknown",originalError:t,timestamp:Date.now(),stack:t.stack,data:n}}getErrorCode(t){return"TypeError"===t.name?"TYPE_ERROR":"ReferenceError"===t.name?"REFERENCE_ERROR":"NetworkError"===t.name?"NETWORK_ERROR":t.message.includes("quota")?"STORAGE_QUOTA_EXCEEDED":t.message.includes("timeout")?"TIMEOUT_ERROR":t.message.includes("abort")?"REQUEST_ABORTED":t.message.includes("CORS")?"CORS_ERROR":t.message.includes("CSP")?"CSP_VIOLATION":"GENERAL_ERROR"}handleSpecificError(t){switch(t.code){case"STORAGE_QUOTA_EXCEEDED":this.handleStorageQuotaError();break;case"NETWORK_ERROR":case"TIMEOUT_ERROR":this.handleNetworkError(t);break;case"CSP_VIOLATION":this.handleCSPViolation(t);break;case"CORS_ERROR":this.handleCORSError(t)}}handleStorageQuotaError(){try{Object.keys(localStorage).forEach(t=>{t.startsWith("tinytapanalytics_")&&t.includes("_old_")&&localStorage.removeItem(t)})}catch(t){}}handleNetworkError(t){}handleCSPViolation(t){this.config.debug}handleCORSError(t){this.config.debug}bufferError(t){this.errorBuffer.push(t),this.errorBuffer.length>50&&(this.errorBuffer=this.errorBuffer.slice(-25))}setupGlobalErrorHandling(){const t=window.onerror;window.onerror=(e,n,i,s,o)=>(this.isSDKError(o,n,e)&&this.handle(o||new Error(String(e)),"global_error"),!!t&&t.call(window,e,n,i,s,o));const e=window.onunhandledrejection;window.onunhandledrejection=t=>(this.isSDKError(t.reason)&&this.handle(t.reason instanceof Error?t.reason:new Error(String(t.reason)),"unhandled_promise_rejection"),!!e&&e.call(window,t))}isSDKError(t,e,n){return!!(t&&t.stack&&(t.stack.includes("TinyTapAnalytics")||t.stack.includes("tinytapanalytics")||t.stack.includes("tracker.js")))||(!(!e||!e.includes("tinytapanalytics")&&!e.includes("tracker.js"))||!(!n||"string"!=typeof n||!n.includes("TinyTapAnalytics")))}startErrorReporting(){this.reportingInterval=window.setInterval(()=>{this.reportErrors()},this.reportingIntervalMs)}reportErrors(){if(0!==this.errorBuffer.length&&!this.isShutdown)try{const t=[...this.errorBuffer];this.errorBuffer=[];const e={sdk_version:"3.3.0",website_id:this.config.websiteId,timestamp:(new Date).toISOString(),errors:t.map(t=>({code:t.code,message:t.message,context:t.context,timestamp:t.timestamp,stack:t.stack?t.stack.substring(0,1e3):void 0,data:t.data}))};if(navigator.sendBeacon){const t=`${this.config.endpoint}/api/v1/errors`;navigator.sendBeacon(t,JSON.stringify(e))}else fetch(`${this.config.endpoint}/api/v1/errors`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)}).catch(()=>{})}catch(t){this.config.debug}}destroy(){this.shutdown()}}class r{constructor(t,e){this.isActive=!1,this.profiles={minimal:{name:"minimal",significanceThreshold:.9,maxEventsPerMinute:5,batchSize:3,batchInterval:1e4},balanced:{name:"balanced",significanceThreshold:.6,maxEventsPerMinute:10,batchSize:5,batchInterval:5e3},detailed:{name:"detailed",significanceThreshold:.3,maxEventsPerMinute:20,batchSize:10,batchInterval:3e3},performance:{name:"performance",significanceThreshold:.5,maxEventsPerMinute:8,batchSize:4,batchInterval:7e3}},this.eventQueue=[],this.interactionState={},this.eventTimestamps=[],this.stats={eventCount:0,filteredEventCount:0,rateLimitedCount:0,batchCount:0},this.listeners=new Map,this.listenerIdCounter=0,this.config=t,this.sdk=e;const n=t.microInteractionProfile||"balanced";this.currentProfile=this.profiles[n]||this.profiles.balanced,!1!==t.adaptiveSampling&&(this.performanceMonitor=new a,this.adaptiveOptimizer=new c(this.performanceMonitor))}start(){this.isActive||(this.isActive=!0,this.attachClickTracking(),this.attachDeadClickTracking(),this.attachInputTracking(),this.attachMouseTracking(),this.attachScrollTracking(),this.startBatchTimer(),this.adaptiveOptimizer&&this.adaptiveOptimizer.start(()=>{this.applyAdaptiveSettings()}),this.config.debug)}stop(){this.isActive&&(this.isActive=!1,this.batchTimer&&clearTimeout(this.batchTimer),this.adaptiveOptimizer&&this.adaptiveOptimizer.stop(),this.listeners.forEach(({target:t,event:e,handler:n,options:i})=>{t.removeEventListener(e,n,i)}),this.listeners.clear(),this.flush(),this.config.debug)}applyAdaptiveSettings(){if(!this.adaptiveOptimizer)return;const t=this.adaptiveOptimizer.getRecommendation();t.shouldThrottle?(this.currentProfile.significanceThreshold=Math.min(.95,this.currentProfile.significanceThreshold+.1),this.currentProfile.batchInterval=Math.min(15e3,this.currentProfile.batchInterval+2e3),this.config.debug):t.canIncrease&&(this.currentProfile.significanceThreshold=Math.max(.3,this.currentProfile.significanceThreshold-.05),this.currentProfile.batchInterval=Math.max(3e3,this.currentProfile.batchInterval-1e3),this.config.debug)}attachClickTracking(){this.addEventListener(document,"click",t=>{const e=t.target,n=this.getElementSelector(e),i=Date.now(),s=this.interactionState.lastClick,o=s?.element===n&&i-s.time<500&&s.count>=2,r=s?.element===n?s.count+1:1,a=this.interactionState.hoverStart?i-this.interactionState.hoverStart:void 0;this.trackEvent({type:"click",elementSelector:n,elementType:e.tagName.toLowerCase(),pageUrl:window.location.href,timestamp:i,hesitationDuration:a,isRageClick:o,clickCount:r,cursorDistance:this.interactionState.cursorDistance,isErrorState:this.isElementInErrorState(e),significanceScore:0}),this.interactionState.lastClick={element:n,time:i,count:r}},!0)}attachDeadClickTracking(){this.addEventListener(document,"click",t=>{const e=t.target;if(this.isInteractiveElement(e))return;("pointer"===window.getComputedStyle(e).cursor||null!==e.closest('[style*="cursor: pointer"]')||e.tagName.match(/^(DIV|SPAN|P|IMG)$/)&&e.textContent?.match(/^(Click|View|See|Learn|Read|More|Details|Info|Buy|Shop|Get)/i))&&(this.trackEvent({type:"dead_click",elementSelector:this.getElementSelector(e),elementType:e.tagName.t