@xsolla/metrika
Version:
A lightweight integration library for Xsolla Metrics (XMTS) that simplifies user tracking and analytics setup.
515 lines (507 loc) • 180 kB
JavaScript
/*!
* @xsolla/metrika v2.11.0
* (c) 2026 Xsolla
* Released under the MIT License
*/
var XsollaAnalytics = (function () {
'use strict';
const e$1=2592e5,t$1="thumbmark",n$1="https://api.thumbmarkjs.com",o$1={exclude:[],include:[],stabilize:["private","iframe"],logging:true,timeout:5e3,cache_api_call:true,cache_lifetime_in_ms:0,performance:false,experimental:false,property_name_factory:e=>`${t$1}_${e}`};const a$1={private:[{exclude:["canvas"],browsers:["firefox","safari>=17","brave"]},{exclude:["audio"],browsers:["samsungbrowser","safari"]},{exclude:["fonts"],browsers:["firefox"]},{exclude:["audio.sampleHash","hardware.deviceMemory","header.acceptLanguage.q","system.hardwareConcurrency","plugins"],browsers:["brave"]},{exclude:["tls.extensions"],browsers:["firefox","chrome","safari"]},{exclude:["header.acceptLanguage"],browsers:["edge","chrome"]}],iframe:[{exclude:["system.applePayVersion","system.cookieEnabled"],browsers:["safari"]},{exclude:["permissions"]}],vpn:[{exclude:["ip"]}],always:[{exclude:["speech"],browsers:["brave","firefox"]}]},s$1="undefined"!=typeof window?window.OfflineAudioContext||window.webkitOfflineAudioContext:null;function c$1(e){let t=0;for(let n=0;n<e.length;++n)t+=Math.abs(e[n]);return t}function u$1(e,t,n){let o=[];for(let t=0;t<e[0].data.length;t++){let n=[];for(let o=0;o<e.length;o++)n.push(e[o].data[t]);o.push(l$1(n));}const r=new Uint8ClampedArray(o);return new ImageData(r,t,n)}function l$1(e){if(0===e.length)return 0;const t={};for(const n of e)t[n]=(t[n]||0)+1;let n=e[0];for(const e in t)t[e]>t[n]&&(n=parseInt(e,10));return n}function d(e){return e^=e>>>16,e=Math.imul(e,2246822507),e^=e>>>13,e=Math.imul(e,3266489909),(e^=e>>>16)>>>0}const m$1=new Uint32Array([597399067,2869860233,951274213,2716044179]);function p$1(e,t){return e<<t|e>>>32-t}function f$1(e,t=0){if(t=t?0|t:0,"string"==typeof e&&(e=function(e){if("undefined"!=typeof TextEncoder)return (new TextEncoder).encode(e).buffer;const t=[];for(let n=0;n<e.length;n++){let o=e.charCodeAt(n);o<128?t.push(o):o<2048?t.push(192|o>>6,128|63&o):o<55296||o>=57344?t.push(224|o>>12,128|o>>6&63,128|63&o):(n++,o=65536+((1023&o)<<10|1023&e.charCodeAt(n)),t.push(240|o>>18,128|o>>12&63,128|o>>6&63,128|63&o));}return new Uint8Array(t).buffer}(e)),!(e instanceof ArrayBuffer))throw new TypeError("Expected key to be ArrayBuffer or string");const n=new Uint32Array([t,t,t,t]);!function(e,t){const n=e.byteLength/16|0,o=new Uint32Array(e,0,4*n);for(let e=0;e<n;e++){const n=o.subarray(4*e,4*(e+1));n[0]=Math.imul(n[0],m$1[0]),n[0]=p$1(n[0],15),n[0]=Math.imul(n[0],m$1[1]),t[0]=t[0]^n[0],t[0]=p$1(t[0],19),t[0]=t[0]+t[1],t[0]=Math.imul(t[0],5)+1444728091,n[1]=Math.imul(n[1],m$1[1]),n[1]=p$1(n[1],16),n[1]=Math.imul(n[1],m$1[2]),t[1]=t[1]^n[1],t[1]=p$1(t[1],17),t[1]=t[1]+t[2],t[1]=Math.imul(t[1],5)+197830471,n[2]=Math.imul(n[2],m$1[2]),n[2]=p$1(n[2],17),n[2]=Math.imul(n[2],m$1[3]),t[2]=t[2]^n[2],t[2]=p$1(t[2],15),t[2]=t[2]+t[3],t[2]=Math.imul(t[2],5)+2530024501,n[3]=Math.imul(n[3],m$1[3]),n[3]=p$1(n[3],18),n[3]=Math.imul(n[3],m$1[0]),t[3]=t[3]^n[3],t[3]=p$1(t[3],13),t[3]=t[3]+t[0],t[3]=Math.imul(t[3],5)+850148119;}}(e,n),function(e,t){const n=e.byteLength/16|0,o=e.byteLength%16,r=new Uint32Array(4),i=new Uint8Array(e,16*n,o);switch(o){case 15:r[3]=r[3]^i[14]<<16;case 14:r[3]=r[3]^i[13]<<8;case 13:r[3]=r[3]^i[12],r[3]=Math.imul(r[3],m$1[3]),r[3]=p$1(r[3],18),r[3]=Math.imul(r[3],m$1[0]),t[3]=t[3]^r[3];case 12:r[2]=r[2]^i[11]<<24;case 11:r[2]=r[2]^i[10]<<16;case 10:r[2]=r[2]^i[9]<<8;case 9:r[2]=r[2]^i[8],r[2]=Math.imul(r[2],m$1[2]),r[2]=p$1(r[2],17),r[2]=Math.imul(r[2],m$1[3]),t[2]=t[2]^r[2];case 8:r[1]=r[1]^i[7]<<24;case 7:r[1]=r[1]^i[6]<<16;case 6:r[1]=r[1]^i[5]<<8;case 5:r[1]=r[1]^i[4],r[1]=Math.imul(r[1],m$1[1]),r[1]=p$1(r[1],16),r[1]=Math.imul(r[1],m$1[2]),t[1]=t[1]^r[1];case 4:r[0]=r[0]^i[3]<<24;case 3:r[0]=r[0]^i[2]<<16;case 2:r[0]=r[0]^i[1]<<8;case 1:r[0]=r[0]^i[0],r[0]=Math.imul(r[0],m$1[0]),r[0]=p$1(r[0],15),r[0]=Math.imul(r[0],m$1[1]),t[0]=t[0]^r[0];}}(e,n),function(e,t){t[0]=t[0]^e.byteLength,t[1]=t[1]^e.byteLength,t[2]=t[2]^e.byteLength,t[3]=t[3]^e.byteLength,t[0]=t[0]+t[1]|0,t[0]=t[0]+t[2]|0,t[0]=t[0]+t[3]|0,t[1]=t[1]+t[0]|0,t[2]=t[2]+t[0]|0,t[3]=t[3]+t[0]|0,t[0]=d(t[0]),t[1]=d(t[1]),t[2]=d(t[2]),t[3]=d(t[3]),t[0]=t[0]+t[1]|0,t[0]=t[0]+t[2]|0,t[0]=t[0]+t[3]|0,t[1]=t[1]+t[0]|0,t[2]=t[2]+t[0]|0,t[3]=t[3]+t[0]|0;}(e,n);const o=new Uint8Array(n.buffer);return Array.from(o).map((e=>e.toString(16).padStart(2,"0"))).join("")}const h$1=280;async function g$1(e){for(var t;!document.body;)await w(50);const n=document.createElement("iframe");n.setAttribute("frameBorder","0");const o=n.style;o.setProperty("position","fixed"),o.setProperty("display","block","important"),o.setProperty("visibility","visible"),o.setProperty("border","0"),o.setProperty("opacity","0"),n.src="about:blank",document.body.appendChild(n);const r=n.contentDocument||(null===(t=n.contentWindow)||void 0===t?void 0:t.document);if(!r)throw new Error("Iframe document is not accessible");e({iframe:r}),setTimeout((()=>{document.body.removeChild(n);}),0);}function w(e,t){return new Promise((n=>setTimeout(n,e,t)))}const v$1=["Arial","Arial Black","Arial Narrow","Arial Rounded MT","Arimo","Archivo","Barlow","Bebas Neue","Bitter","Bookman","Calibri","Cabin","Candara","Century","Century Gothic","Comic Sans MS","Constantia","Courier","Courier New","Crimson Text","DM Mono","DM Sans","DM Serif Display","DM Serif Text","Dosis","Droid Sans","Exo","Fira Code","Fira Sans","Franklin Gothic Medium","Garamond","Geneva","Georgia","Gill Sans","Helvetica","Impact","Inconsolata","Indie Flower","Inter","Josefin Sans","Karla","Lato","Lexend","Lucida Bright","Lucida Console","Lucida Sans Unicode","Manrope","Merriweather","Merriweather Sans","Montserrat","Myriad","Noto Sans","Nunito","Nunito Sans","Open Sans","Optima","Orbitron","Oswald","Pacifico","Palatino","Perpetua","PT Sans","PT Serif","Poppins","Prompt","Public Sans","Quicksand","Rajdhani","Recursive","Roboto","Roboto Condensed","Rockwell","Rubik","Segoe Print","Segoe Script","Segoe UI","Sora","Source Sans Pro","Space Mono","Tahoma","Taviraj","Times","Times New Roman","Titillium Web","Trebuchet MS","Ubuntu","Varela Round","Verdana","Work Sans"],y=["monospace","sans-serif","serif"];function S(e,t){return e.font=`72px ${t}`,e.measureText("WwMmLli0Oo").width}function b(){var e;const t=document.createElement("canvas"),n=null!==(e=t.getContext("webgl"))&&void 0!==e?e:t.getContext("experimental-webgl");if(n&&"getParameter"in n)try{const e=(n.getParameter(n.VENDOR)||"").toString(),t=(n.getParameter(n.RENDERER)||"").toString();let o={vendor:e,renderer:t,version:(n.getParameter(n.VERSION)||"").toString(),shadingLanguageVersion:(n.getParameter(n.SHADING_LANGUAGE_VERSION)||"").toString()};if(!t.length||!e.length){const e=n.getExtension("WEBGL_debug_renderer_info");if(e){const t=(n.getParameter(e.UNMASKED_VENDOR_WEBGL)||"").toString(),r=(n.getParameter(e.UNMASKED_RENDERER_WEBGL)||"").toString();t&&(o.vendorUnmasked=t),r&&(o.rendererUnmasked=r);}}return o}catch(e){}return "undefined"}function E(){const e=new Float32Array(1),t=new Uint8Array(e.buffer);return e[0]=1/0,e[0]=e[0]-e[0],t[3]}const M=(e,t,n,o)=>{const r=(n-t)/o;let i=0;for(let n=0;n<o;n++){i+=e(t+(n+.5)*r);}return i*r};function P(e,t){const n={};return t.forEach((t=>{const o=function(e){if(0===e.length)return null;const t={};e.forEach((e=>{const n=String(e);t[n]=(t[n]||0)+1;}));let n=e[0],o=1;return Object.keys(t).forEach((e=>{t[e]>o&&(n=e,o=t[e]);})),n}(e.map((e=>t in e?e[t]:void 0)).filter((e=>void 0!==e)));o&&(n[t]=o);})),n}const x$1=["accelerometer","accessibility","accessibility-events","ambient-light-sensor","background-fetch","background-sync","bluetooth","camera","clipboard-read","clipboard-write","device-info","display-capture","gyroscope","geolocation","local-fonts","magnetometer","microphone","midi","nfc","notifications","payment-handler","persistent-storage","push","speaker","storage-access","top-level-storage-access","window-management","query"];function C(){if("undefined"==typeof navigator)return {name:"unknown",version:"unknown"};const e=[{name:"Brave",detect:()=>!!navigator.brave}];for(const t of e)if(t.detect()){const e=A$1(navigator.userAgent);return {name:t.name,version:e.version}}return A$1(navigator.userAgent)}function A$1(e){var t,n,o,r,i,a;const s=[/(?<name>SamsungBrowser)\/(?<version>\d+(?:\.\d+)+)/,/(?<name>EdgA|EdgiOS|Edg)\/(?<version>\d+(?:\.\d+)+)/,/(?<name>OPR|OPX)\/(?<version>\d+(?:\.\d+)+)/,/Opera[\s\/](?<version>\d+(?:\.\d+)+)/,/Opera Mini\/(?<version>\d+(?:\.\d+)+)/,/Opera Mobi\/(?<version>\d+(?:\.\d+)+)/,/(?<name>Vivaldi)\/(?<version>\d+(?:\.\d+)+)/,/(?<name>CriOS)\/(?<version>\d+(?:\.\d+)+)/,/(?<name>FxiOS)\/(?<version>\d+(?:\.\d+)+)/,/(?<name>Chrome|Chromium)\/(?<version>\d+(?:\.\d+)+)/,/(?<name>Firefox|Waterfox|Iceweasel|IceCat)\/(?<version>\d+(?:\.\d+)+)/,/Version\/(?<version1>[\d.]+).*Safari\/[\d.]+|(?<name>Safari)\/(?<version2>[\d.]+)/,/(?<name>MSIE|Trident|IEMobile).+?(?<version>\d+(?:\.\d+)+)/,/(?<name>[A-Za-z]+)\/(?<version>\d+(?:\.\d+)+)/],c={edg:"Edge",edga:"Edge",edgios:"Edge",opr:"Opera",opx:"Opera",crios:"Chrome",fxios:"Firefox",samsung:"SamsungBrowser",vivaldi:"Vivaldi"};for(const u of s){const s=e.match(u);if(s){let e=null===(t=s.groups)||void 0===t?void 0:t.name,l=(null===(n=s.groups)||void 0===n?void 0:n.version)||(null===(o=s.groups)||void 0===o?void 0:o.version1)||(null===(r=s.groups)||void 0===r?void 0:r.version2);if(e||!(null===(i=s.groups)||void 0===i?void 0:i.version1)&&!(null===(a=s.groups)||void 0===a?void 0:a.version2)||(e="Safari"),!e&&u.source.includes("Opera Mini")&&(e="Opera Mini"),!e&&u.source.includes("Opera Mobi")&&(e="Opera Mobi"),!e&&u.source.includes("Opera")&&(e="Opera"),!e&&s[1]&&(e=s[1]),!l&&s[2]&&(l=s[2]),e){return {name:c[e.toLowerCase()]||e,version:l||"unknown"}}}}return {name:"unknown",version:"unknown"}}function _(){if("undefined"==typeof navigator||!navigator.userAgent)return false;const e=navigator.userAgent;return /Mobi|Android|iPhone|iPod|IEMobile|Opera Mini|Opera Mobi|webOS|BlackBerry|Windows Phone/i.test(e)&&!/iPad/i.test(e)}function I(){let e=[];const t={"prefers-contrast":["high","more","low","less","forced","no-preference"],"any-hover":["hover","none"],"any-pointer":["none","coarse","fine"],pointer:["none","coarse","fine"],hover:["hover","none"],update:["fast","slow"],"inverted-colors":["inverted","none"],"prefers-reduced-motion":["reduce","no-preference"],"prefers-reduced-transparency":["reduce","no-preference"],scripting:["none","initial-only","enabled"],"forced-colors":["active","none"]};return Object.keys(t).forEach((n=>{t[n].forEach((t=>{matchMedia(`(${n}: ${t})`).matches&&e.push(`${n}: ${t}`);}));})),e}function T(){if("https:"===window.location.protocol&&"function"==typeof window.ApplePaySession)try{const e=window.ApplePaySession.supportsVersion;for(let t=15;t>0;t--)if(e(t))return t}catch(e){return 0}return 0}const R="SamsungBrowser"!==C().name?1:3;let k,O=null;function L(e){const t=[];return function e(n){if(n&&n.toJSON&&"function"==typeof n.toJSON&&(n=n.toJSON()),void 0===n)return;if("number"==typeof n)return isFinite(n)?""+n:"null";if("object"!=typeof n)return JSON.stringify(n);let o,r;if(Array.isArray(n)){for(r="[",o=0;o<n.length;o++)o&&(r+=","),r+=e(n[o])||"null";return r+"]"}if(null===n)return "null";if(-1!==t.indexOf(n))throw new TypeError("Converting circular structure to JSON");const i=t.push(n)-1,a=Object.keys(n).sort();for(r="",o=0;o<a.length;o++){const t=a[o],i=e(n[t]);i&&(r&&(r+=","),r+=JSON.stringify(t)+":"+i);}return t.splice(i,1),"{"+r+"}"}(e)||""}const N$1=["𝔄","𝔅","ℭ","𝔇","𝔈","𝔉","𝔸","𝔹","ℂ","𝔻","𝔼","𝔽"],B=["β","ψ","λ","ε","ζ","α","ξ","μ","ρ","φ","κ","τ","η","σ","ι","ω","γ","ν","χ","δ","θ","π","υ","ο"];function D(e,t){return `<math><mrow>${t}</mrow></math>`}function $(){let e="<mo>∏</mo>";return N$1.forEach(((t,n)=>{const o=2*n,r=B.slice(o,o+2);2===r.length&&(e+=`<mmultiscripts><mi>${t}</mi><none/><mi>${r[1]}</mi><mprescripts></mprescripts><mi>${r[0]}</mi><none/></mmultiscripts>`);})),D(0,`<munderover><mmultiscripts>${e}</mmultiscripts></munderover>`)}function F(){const e=[];return N$1.forEach(((t,n)=>{const o=2*n,r=B.slice(o,o+2);2===r.length&&e.push(D(0,`<mmultiscripts><mi>${t}</mi><none/><mi>${r[1]}</mi><mprescripts></mprescripts><mi>${r[0]}</mi><none/></mmultiscripts>`));})),e}const V={audio:async function(){return s$1?async function(){return new Promise(((e,t)=>{try{const t=new s$1(1,5e3,44100),n=t.createBufferSource(),o=t.createOscillator();o.frequency.value=1e3;const r=t.createDynamicsCompressor();let i;r.threshold.value=-50,r.knee.value=40,r.ratio.value=12,r.attack.value=0,r.release.value=.2,o.connect(r),r.connect(t.destination),o.start(),t.oncomplete=o=>{i=o.renderedBuffer.getChannelData(0),e({sampleHash:c$1(i),maxChannels:t.destination.maxChannelCount,channelCountMode:n.channelCountMode});},t.startRendering();}catch(e){console.error("Error creating audio fingerprint:",e),t(e);}}))}():null},canvas:async function(){return new Promise((e=>{const t=Array.from({length:3},(()=>function(){const e=document.createElement("canvas"),t=e.getContext("2d");if(!t)return null;e.width=h$1,e.height=20;const n=t.createLinearGradient(0,0,e.width,e.height);n.addColorStop(0,"red"),n.addColorStop(1/6,"orange"),n.addColorStop(2/6,"yellow"),n.addColorStop(.5,"green"),n.addColorStop(4/6,"blue"),n.addColorStop(5/6,"indigo"),n.addColorStop(1,"violet"),t.fillStyle=n,t.fillRect(0,0,e.width,e.height);const o="Random Text WMwmil10Oo";t.font="23.123px Arial",t.fillStyle="black",t.fillText(o,-5,15),t.fillStyle="rgba(0, 0, 255, 0.5)",t.fillText(o,-3.3,17.7),t.beginPath(),t.moveTo(0,0),t.lineTo(2*e.width/7,e.height),t.strokeStyle="white",t.lineWidth=2,t.stroke();const r=t.getImageData(0,0,e.width,e.height);return r}())).filter((e=>null!==e));0!==t.length?e({commonPixelsHash:f$1(u$1(t,h$1,20).data.toString()).toString()}):e(null);}))},fonts:async function(e){return new Promise((e=>{try{g$1((async({iframe:t})=>{const n=t.createElement("canvas").getContext("2d");if(!n)return void e(null);const o=y.map((e=>S(n,e)));let r={};v$1.forEach((e=>{const t=S(n,e);o.includes(t)||(r[e]=t);})),e(r);}));}catch(t){e(null);}}))},hardware:function(){return new Promise(((e,t)=>{const n=void 0!==navigator.deviceMemory?navigator.deviceMemory:0,o=window.performance&&window.performance.memory?window.performance.memory:0;e({videocard:b(),architecture:E(),deviceMemory:n.toString()||"undefined",jsHeapSizeLimit:o.jsHeapSizeLimit||0});}))},locales:function(){return new Promise((e=>{e({languages:navigator.language,timezone:Intl.DateTimeFormat().resolvedOptions().timeZone});}))},math:function(){return new Promise((e=>{e({acos:Math.acos(.5),asin:M(Math.asin,-1,1,97),cos:M(Math.cos,0,Math.PI,97),largeCos:Math.cos(1e20),largeSin:Math.sin(1e20),largeTan:Math.tan(1e20),sin:M(Math.sin,-Math.PI,Math.PI,97),tan:M(Math.tan,0,2*Math.PI,97)});}))},permissions:async function(e){const t=(null==e?void 0:e.permissions_to_check)||x$1;return P(await Promise.all(Array.from({length:3},(()=>async function(e){const t={};for(const n of e)try{const e=await navigator.permissions.query({name:n});t[n]=e.state.toString();}catch(e){}return t}(t)))),t)},plugins:async function(){const e=[];if(navigator.plugins)for(let t=0;t<navigator.plugins.length;t++){const n=navigator.plugins[t];e.push([n.name,n.filename,n.description].join("|"));}return new Promise((t=>{t({plugins:e});}))},screen:function(){return new Promise((e=>{if("undefined"==typeof matchMedia||"undefined"==typeof screen)return void e(null);const t={is_touchscreen:navigator.maxTouchPoints>0,maxTouchPoints:navigator.maxTouchPoints,colorDepth:screen.colorDepth,mediaMatches:I()};_()&&navigator.maxTouchPoints>0&&(t.resolution=function(){const e=window.screen.width,t=window.screen.height,n=Math.max(e,t).toString(),o=Math.min(e,t).toString();return `${n}x${o}`}()),e(t);}))},system:function(){return new Promise((e=>{const t=C();e({platform:window.navigator.platform,productSub:navigator.productSub,product:navigator.product,useragent:navigator.userAgent,hardwareConcurrency:navigator.hardwareConcurrency,browser:{name:t.name,version:t.version},mobile:_(),applePayVersion:T(),cookieEnabled:window.navigator.cookieEnabled});}))},webgl:async function(){"undefined"!=typeof document&&(k=document.createElement("canvas"),k.width=200,k.height=100,O=k.getContext("webgl"));try{if(!O)throw new Error("WebGL not supported");const e=Array.from({length:R},(()=>function(){try{if(!O)throw new Error("WebGL not supported");const e="\n attribute vec2 position;\n void main() {\n gl_Position = vec4(position, 0.0, 1.0);\n }\n ",t="\n precision mediump float;\n void main() {\n gl_FragColor = vec4(0.812, 0.195, 0.553, 0.921); // Set line color\n }\n ",n=O.createShader(O.VERTEX_SHADER),o=O.createShader(O.FRAGMENT_SHADER);if(!n||!o)throw new Error("Failed to create shaders");if(O.shaderSource(n,e),O.shaderSource(o,t),O.compileShader(n),!O.getShaderParameter(n,O.COMPILE_STATUS))throw new Error("Vertex shader compilation failed: "+O.getShaderInfoLog(n));if(O.compileShader(o),!O.getShaderParameter(o,O.COMPILE_STATUS))throw new Error("Fragment shader compilation failed: "+O.getShaderInfoLog(o));const r=O.createProgram();if(!r)throw new Error("Failed to create shader program");if(O.attachShader(r,n),O.attachShader(r,o),O.linkProgram(r),!O.getProgramParameter(r,O.LINK_STATUS))throw new Error("Shader program linking failed: "+O.getProgramInfoLog(r));O.useProgram(r);const i=137,a=new Float32Array(4*i),s=2*Math.PI/i;for(let e=0;e<i;e++){const t=e*s;a[4*e]=0,a[4*e+1]=0,a[4*e+2]=Math.cos(t)*(k.width/2),a[4*e+3]=Math.sin(t)*(k.height/2);}const c=O.createBuffer();O.bindBuffer(O.ARRAY_BUFFER,c),O.bufferData(O.ARRAY_BUFFER,a,O.STATIC_DRAW);const u=O.getAttribLocation(r,"position");O.enableVertexAttribArray(u),O.vertexAttribPointer(u,2,O.FLOAT,!1,0,0),O.viewport(0,0,k.width,k.height),O.clearColor(0,0,0,1),O.clear(O.COLOR_BUFFER_BIT),O.drawArrays(O.LINES,0,2*i);const l=new Uint8ClampedArray(k.width*k.height*4);O.readPixels(0,0,k.width,k.height,O.RGBA,O.UNSIGNED_BYTE,l);return new ImageData(l,k.width,k.height)}catch(e){return new ImageData(1,1)}finally{O&&(O.bindBuffer(O.ARRAY_BUFFER,null),O.useProgram(null),O.viewport(0,0,O.drawingBufferWidth,O.drawingBufferHeight),O.clearColor(0,0,0,0));}}()));return {commonPixelsHash:f$1(u$1(e,k.width,k.height).data.toString()).toString()}}catch(e){return {webgl:"unsupported"}}},webrtc:async function(e){return new Promise((t=>{try{const n=window.RTCPeerConnection||window.webkitRTCPeerConnection||window.mozRTCPeerConnection;if(!n)return void t({supported:!1,error:"WebRTC not supported"});const o=new n({iceCandidatePoolSize:1,iceServers:[]});o.createDataChannel("");(async()=>{try{const n={offerToReceiveAudio:!0,offerToReceiveVideo:!0},r=await o.createOffer(n);await o.setLocalDescription(r);const i=r.sdp||"",a=[...new Set((i.match(/extmap:\d+ [^\n\r]+/g)||[]).map((e=>e.replace(/extmap:\d+ /,""))))].sort(),s=e=>{const t=i.match(new RegExp(`m=${e} [^\\s]+ [^\\s]+ ([^\\n\\r]+)`));return t?t[1].split(" "):[]},c=(e,t)=>t.map((t=>{const n=new RegExp(`(rtpmap|fmtp|rtcp-fb):${t} (.+)`,"g"),o=[...i.matchAll(n)];if(!o.length)return null;const r={};return o.forEach((t=>{const[n,o,i]=t,a=i.split("/");"rtpmap"===o?(r.mimeType=`${e}/${a[0]}`,r.clockRate=+a[1],"audio"===e&&(r.channels=+a[2]||1)):"rtcp-fb"===o?(r.feedbackSupport=r.feedbackSupport||[],r.feedbackSupport.push(i)):"fmtp"===o&&(r.sdpFmtpLine=i);})),r})).filter(Boolean),u=c("audio",s("audio")),l=c("video",s("video")),d={audio:{count:u.length,hash:f$1(L(u))},video:{count:l.length,hash:f$1(L(l))},extensionsHash:f$1(L(a))},m=(null==e?void 0:e.timeout)||5e3,p=Math.floor(.9*m),h=await new Promise((e=>{const t=setTimeout((()=>{o.removeEventListener("icecandidate",n),o.close(),e({supported:!0,...d,timeout:!0});}),p),n=r=>{const i=r.candidate;i&&i.candidate&&(clearTimeout(t),o.removeEventListener("icecandidate",n),o.close(),e({supported:!0,...d,candidateType:i.type||""}));};o.addEventListener("icecandidate",n);}));t({details:h,hash:f$1(L(h))});}catch(e){o.close(),t({supported:!0,error:`WebRTC offer failed: ${e.message}`});}})();}catch(e){t({supported:false,error:`WebRTC error: ${e.message}`});}}))},speech:async function(){return new Promise((e=>{try{if("undefined"==typeof window||!window.speechSynthesis||"function"!=typeof window.speechSynthesis.getVoices)return void e({supported:!1,error:"Speech Synthesis API not supported"});let t=!1,n=null;const o=o=>{if(!t){t=!0,n&&clearTimeout(n);try{const t=o.map((e=>{const t=e=>e.replace(/\\/g,"\\\\").replace(/,/g,"\\,");return [t(e.voiceURI||""),t(e.name||""),t(e.lang||""),e.localService?"1":"0",e.default?"1":"0"].join(",")}));t.sort();const n={voiceCount:o.length,voicesHash:f$1(L(t))};e({details:n,hash:f$1(L(n))});}catch(t){e({supported:!0,error:`Voice processing failed: ${t.message}`});}}},r=window.speechSynthesis.getVoices();if(r.length>0)return void o(r);n=setTimeout((()=>{const e=window.speechSynthesis.getVoices();o(e);}),800);const i=()=>{window.speechSynthesis.removeEventListener("voiceschanged",i);const e=window.speechSynthesis.getVoices();o(e);};window.speechSynthesis.addEventListener("voiceschanged",i);}catch(t){e({supported:false,error:`Speech Synthesis error: ${t.message}`});}}))}},U={mathml:async function(){return new Promise((e=>{try{g$1((async({iframe:t})=>{try{if(!function(e){try{const t=e.createElement("math");t.innerHTML="<mrow><mi>x</mi></mrow>",t.style.position="absolute",t.style.visibility="hidden",e.body.appendChild(t);const n=t.getBoundingClientRect();return e.body.removeChild(t),n.width>0&&n.height>0}catch(e){return !1}}(t))return void e({supported:!1,error:"MathML not supported"});const n=[D("integral","<msubsup><mo>∫</mo><mi>a</mi><mi>b</mi></msubsup><mfrac><mrow><mi>f</mi><mo>(</mo><mi>x</mi><mo>)</mo></mrow><mrow><mi>g</mi><mo>(</mo><mi>x</mi><mo>)</mo></mrow></mfrac><mi>dx</mi>"),D("fraction","<mfrac><mrow><mi>π</mi><mo>×</mo><msup><mi>r</mi><mn>2</mn></msup></mrow><mrow><mn>2</mn><mi>σ</mi></mrow></mfrac>"),D("matrix","<mo>[</mo><mtable><mtr><mtd><mi>α</mi></mtd><mtd><mi>β</mi></mtd></mtr><mtr><mtd><mi>γ</mi></mtd><mtd><mi>δ</mi></mtd></mtr></mtable><mo>]</mo>"),$(),...F()],o=[];let r="";n.forEach(((e,n)=>{const i=function(e,t){try{const n=t.createElement("math");n.innerHTML=e.replace(/<\/?math>/g,""),n.style.whiteSpace="nowrap",n.style.position="absolute",n.style.visibility="hidden",n.style.top="-9999px",t.body.appendChild(n);const o=n.getBoundingClientRect(),r=(t.defaultView||window).getComputedStyle(n),i={dimensions:{width:o.width,height:o.height},fontInfo:{fontFamily:r.fontFamily,fontSize:r.fontSize,fontWeight:r.fontWeight,fontStyle:r.fontStyle,lineHeight:r.lineHeight,fontVariant:r.fontVariant||"normal",fontStretch:r.fontStretch||"normal",fontSizeAdjust:r.fontSizeAdjust||"none",textRendering:r.textRendering||"auto",fontFeatureSettings:r.fontFeatureSettings||"normal",fontVariantNumeric:r.fontVariantNumeric||"normal",fontKerning:r.fontKerning||"auto"}};return t.body.removeChild(n),i}catch(e){return {error:e.message}}}(e,t);o.push({width:i.dimensions.width,height:i.dimensions.height}),0===n&&i.fontInfo&&(r=f$1(L(i.fontInfo)));}));const i={fontStyleHash:r,dimensions:o};e({details:i,hash:f$1(L(i))});}catch(t){e({supported:!1,error:`MathML error: ${t.message}`});}}));}catch(t){e({supported:false,error:`MathML error: ${t.message}`});}}))}},j={},W={timeout:"true"},H=(e,t,n)=>{j[e]=t;};function z(e,t){var n,o;let r=C();if("unknown"===r.name&&t){const e=null===(n=t.system)||void 0===n?void 0:n.browser;(null==e?void 0:e.name)&&(r={name:String(e.name),version:String(e.version||"unknown")});}const i=r.name.toLowerCase(),s=parseInt(r.version.split(".")[0]||"0",10),c=[...(null==e?void 0:e.exclude)||[]],u=[...new Set([...(null==e?void 0:e.stabilize)||[],"always"])];for(const e of u){const t=a$1[e];if(t)for(const e of t)"browsers"in e&&!(null===(o=e.browsers)||void 0===o?void 0:o.some((e=>{const t=e.match(/(.+?)(>=)(\d+)/);return t?i===t[1]&&s>=+t[3]:i===e})))||c.push(...e.exclude);}return c}function J(e,t){const n=z(t,e),o=(null==t?void 0:t.include)||[];return function e(t,r=""){const i={};for(const[a,s]of Object.entries(t)){const t=r?`${r}.${a}`:a;if("object"!=typeof s||Array.isArray(s)||null===s){const e=n.some((e=>t.startsWith(e))),r=o.some((e=>t.startsWith(e)));e&&!r||(i[a]=s);}else {const n=e(s,t);Object.keys(n).length>0&&(i[a]=n);}}return i}(e)}const q$1="visitor_id";function K(e){return e.storage_property_name?e.storage_property_name:e.property_name_factory(q$1)}const Y=`${t$1}_${q$1}`;function X(e,t){try{localStorage.setItem(K(t),e);}catch(e){}}const Z="cache";function Q(e){try{const t=localStorage.getItem(e.property_name_factory(Z)),n=JSON.parse(t);return n||{}}catch(e){}return {}}function ee(t){return t.cache_lifetime_in_ms>e$1?Date.now()+e$1:Date.now()+t.cache_lifetime_in_ms}let te=null,ne=null;const oe=(e,t)=>{if(e.cache_api_call){if(ne)return Promise.resolve(ne);const t=function(e){const t=Q(e);if(t&&t.apiResponse&&t.apiResponseExpiry&&Date.now()<=t.apiResponseExpiry)return t.apiResponse;return}(e);if(t)return Promise.resolve(t);if(te)return te}const o=`${e.api_endpoint||n$1}/thumbmark`,r=function(e){try{const t=K(e);let n=localStorage.getItem(t);return n||t===Y||(n=localStorage.getItem(Y),n&&X(n,e)),n}catch(e){return null}}(e),i={components:t,options:e,clientHash:f$1(L(t)),version:"1.7.4"};if(r&&(i.visitorId=r),e.metadata){const t="function"==typeof e.metadata?e.metadata():e.metadata;if(t){("string"==typeof t?t.length:JSON.stringify(t).length)>1e3?console.error("ThumbmarkJS: Metadata exceeds 1000 characters. Skipping metadata."):i.metadata=t;}}const a=fetch(o,{method:"POST",headers:{"x-api-key":e.api_key,Authorization:"custom-authorized","Content-Type":"application/json"},body:JSON.stringify(i)}).then((e=>{if(!e.ok){if(403===e.status)throw new Error("INVALID_API_KEY");throw new Error(`HTTP error! status: ${e.status}`)}return e.json()})).then((t=>(t.visitorId&&t.visitorId!==r&&X(t.visitorId,e),ne=t,function(e,t){if(!e.cache_api_call||!e.cache_lifetime_in_ms)return;!function(e,t){const n={...Q(e),...t};try{localStorage.setItem(e.property_name_factory(Z),JSON.stringify(n));}catch(e){}}(e,{apiResponseExpiry:ee(e),apiResponse:t});}(e,t),te=null,t))).catch((e=>{throw te=null,e})),s=e.timeout||5e3,c=new Promise((t=>{setTimeout((()=>{const n=Q(e);n&&n.apiResponse?t(n.apiResponse):t({info:{timed_out:true},...r&&{visitorId:r}});}),s);}));return te=Promise.race([a,c]),te};async function re(e){var t,r;if("undefined"==typeof document||"undefined"==typeof window)return {thumbmark:"",components:{},info:{},version:"1.7.4",error:[{type:"fatal",message:"Browser environment required"}]};try{const i={...o$1,...e},a=[],s=i.logging&&!sessionStorage.getItem("_tmjs_l")&&Math.random()<1e-4,c={...V,...j},{elapsed:u,resolvedComponents:l,errors:d}=await ie(c,i);a.push(...d);let m={},p={};if(s||i.experimental){const{elapsed:e,resolvedComponents:t,errors:n}=await ie(U,i);m=t,p=e,a.push(...n);}const h=i.api_key?oe(i,l):null;let g=null;if(h)try{g=await h;}catch(e){if(e instanceof Error&&"INVALID_API_KEY"===e.message)return {error:[{type:"api_unauthorized",message:"Invalid API key or quota exceeded"}],components:{},info:{},version:"1.7.4",thumbmark:""};a.push({type:"api_error",message:e instanceof Error?e.message:String(e)});}(null===(t=null==g?void 0:g.info)||void 0===t?void 0:t.timed_out)&&a.push({type:"api_timeout",message:"API request timed out"});const w={...u,...p},v=i.performance?{elapsed:w}:{},y=J((null==g?void 0:g.components)||{},i),S={...l,...y},b=(null==g?void 0:g.info)||{uniqueness:{score:"api only"}},E=null!==(r=null==g?void 0:g.thumbmark)&&void 0!==r?r:f$1(L(S)),M="1.7.4";s&&async function(e,t,o,r={},i=[]){var a;const s=`${n$1}/log`,c={thumbmark:e,components:t,experimental:r,version:"1.7.4",options:o,path:null===(a=null===window||void 0===window?void 0:window.location)||void 0===a?void 0:a.pathname,...i.length>0&&{errors:i}};sessionStorage.setItem("_tmjs_l","1");try{await fetch(s,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(c)});}catch(e){}}(E,S,i,m,a).catch((()=>{}));return {...(null==g?void 0:g.visitorId)&&{visitorId:g.visitorId},thumbmark:E,components:S,info:b,version:M,...v,...a.length>0&&{error:a},...Object.keys(m).length>0&&i.experimental&&{experimental:m},...(null==g?void 0:g.requestId)&&{requestId:g.requestId},...(null==g?void 0:g.metadata)&&{metadata:g.metadata}}}catch(e){return {thumbmark:"",components:{},info:{},version:"1.7.4",error:[{type:"fatal",message:e instanceof Error?e.message:String(e)}]}}}async function ie(e,t){const n={...o$1,...t},r=z(n).filter((e=>!e.includes("."))),i=Object.entries(e).filter((([e])=>{var t;return !(null===(t=null==n?void 0:n.exclude)||void 0===t?void 0:t.includes(e))})).filter((([e])=>!r.includes(e))).filter((([e])=>{var t,o,r,i;return (null===(t=null==n?void 0:n.include)||void 0===t?void 0:t.some((e=>e.includes("."))))?null===(o=null==n?void 0:n.include)||void 0===o?void 0:o.some((t=>t.startsWith(e))):0===(null===(r=null==n?void 0:n.include)||void 0===r?void 0:r.length)||(null===(i=null==n?void 0:n.include)||void 0===i?void 0:i.includes(e))})),a=i.map((([e])=>e)),s=i.map((([e,n])=>n(t))),c=await function(e,t,n){return Promise.all(e.map((e=>{const o=performance.now();return Promise.race([e.then((e=>({value:e,elapsed:performance.now()-o}))).catch((e=>({value:n,elapsed:performance.now()-o,error:e instanceof Error?e.message:String(e)}))),(r=t,i=n,new Promise((e=>{setTimeout((()=>e(i)),r);}))).then((e=>({value:e,elapsed:performance.now()-o,error:"timeout"})))]);var r,i;})))}(s,(null==n?void 0:n.timeout)||5e3,W),u={},l={},d=[];c.forEach(((e,t)=>{var n;const o=a[t];u[o]=null!==(n=e.elapsed)&&void 0!==n?n:0,"timeout"===e.error?d.push({type:"component_timeout",message:`Component '${o}' timed out`,component:o}):e.error&&d.push({type:"component_error",message:e.error,component:o}),null!=e.value&&(l[o]=e.value);}));const m=J(l,n);return {elapsed:u,resolvedComponents:m,errors:d}}class ue{constructor(e){this.options={...o$1,...e};}async get(e){return re({...this.options,...e})}getVersion(){return "1.7.4"}includeComponent(e,t){H(e,t);}}
var EVENT_TYPE;
(function (EVENT_TYPE) {
EVENT_TYPE[EVENT_TYPE["HIT"] = 1] = "HIT";
EVENT_TYPE[EVENT_TYPE["EXTERNAL_LINK"] = 2] = "EXTERNAL_LINK";
EVENT_TYPE[EVENT_TYPE["ELEMENT_CLICK"] = 3] = "ELEMENT_CLICK";
EVENT_TYPE[EVENT_TYPE["FORM_DATA"] = 4] = "FORM_DATA";
EVENT_TYPE[EVENT_TYPE["CUSTOM_EVENT"] = 5] = "CUSTOM_EVENT";
EVENT_TYPE[EVENT_TYPE["LCP"] = 6] = "LCP";
EVENT_TYPE[EVENT_TYPE["SCROLL_TOP"] = 10] = "SCROLL_TOP";
EVENT_TYPE[EVENT_TYPE["SCROLL_MIDDLE"] = 11] = "SCROLL_MIDDLE";
EVENT_TYPE[EVENT_TYPE["SCROLL_BOTTOM"] = 12] = "SCROLL_BOTTOM";
})(EVENT_TYPE || (EVENT_TYPE = {}));
const utmKeys = [
'utm_source',
'utm_medium',
'utm_campaign',
'utm_content',
'utm_term',
];
const openstatKeys = [
'openstat_service',
'openstat_campaign',
'openstat_ad',
'openstat_source',
];
const adClickParams = [
'gclid',
'gbraid',
'wbraid',
'dclid',
'fbclid',
'yclid',
'msclkid',
'ttclid',
'twclid',
'li_fat_id',
'epik',
'sccid',
'irclickid',
'_kx',
'_openstat',
];
const DEFAULT_SERVER = 'https://minimetrika.xsolla.com';
const DEFAULT_HIT_ENDPOINT = 'hit';
class BaseTracker {
constructor(analytics) {
Object.defineProperty(this, "analytics", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
this.analytics = analytics;
}
}
const prepareName = (name, counterId) => `_mm_${name}_${counterId}`;
const calculatePageLoadTime = () => {
// PerformanceNavigationTiming (Navigation Timing Level 2)
// Baseline Widely Available since Oct 2021: Chrome 57+, Firefox 58+, Safari 15+, Edge 79+.
// Safari 13.1-14.x and iOS Safari 13.4-14.x do NOT support this.
const navEntry = performance.getEntriesByType('navigation')[0];
if (navEntry && navEntry.loadEventEnd > 0) {
return navEntry.loadEventEnd - navEntry.startTime;
}
// Fallback: performance.now() returns milliseconds since timeOrigin (navigation start).
// When called after the load event (guaranteed by PageLoadTracker), this approximates
// the total page load time. Available in all target browsers.
return performance.now();
};
const isInternal = (url, domains) => {
if (!url)
return false;
try {
const parsedUrl = new URL(url, window.location.origin);
const host = parsedUrl.host;
return domains.includes(host);
}
catch {
return false;
}
};
const formDataToObject = (formData) => {
const object = {};
formData.forEach((value, key) => {
// Reflect.has in favor of: object.hasOwnProperty(key)
if (!Reflect.has(object, key)) {
object[key] = value;
return;
}
if (!Array.isArray(object[key])) {
object[key] = [object[key]];
}
object[key].push(value);
});
return object;
};
const getElementIdentifier = (element) => {
const text = element.textContent?.trim() || '';
const shortText = text.length > 50 ? text.slice(0, 47) + '…' : text;
const firstClass = element.classList.item(0) || '';
const getDataAttribute = () => {
const dataAttrs = ['data-testid', 'data-qa', 'data-cy', 'data-id', 'data-name'];
for (const attr of dataAttrs) {
const value = element.getAttribute(attr);
if (value)
return value;
}
return '';
};
return (getDataAttribute() ||
element.id ||
element.getAttribute('name') ||
element.getAttribute('aria-label') ||
firstClass ||
shortText ||
element.tagName.toLowerCase());
};
const getSeconds = () => Math.round(+new Date() / 1e3);
const getRandomNumber = (a = 0, b = 1073741824) => {
return Math.floor(Math.random() * (b - a)) + a;
};
class ClickTracker extends BaseTracker {
constructor() {
super(...arguments);
Object.defineProperty(this, "selector", {
enumerable: true,
configurable: true,
writable: true,
value: '[data-analytics="true"]'
});
Object.defineProperty(this, "listenerOptions", {
enumerable: true,
configurable: true,
writable: true,
value: { capture: true, passive: true }
});
Object.defineProperty(this, "handleClick", {
enumerable: true,
configurable: true,
writable: true,
value: (event) => {
const target = event.target;
if (!target)
return;
const trackedElement = target.closest(this.selector);
if (!trackedElement)
return;
const url = this.extractUrl(trackedElement);
const referer = url ? location.href : undefined;
const eventData = {
type: EVENT_TYPE.ELEMENT_CLICK,
data: {
en: getElementIdentifier(trackedElement),
url,
referer,
},
useBeacon: true,
};
this.analytics.sendEvent(eventData);
}
});
}
init() {
if (typeof document === 'undefined')
return;
document.addEventListener('click', this.handleClick, this.listenerOptions);
}
destroy() {
if (typeof document === 'undefined')
return;
document.removeEventListener('click', this.handleClick, this.listenerOptions);
}
extractUrl(element) {
if (element instanceof HTMLAnchorElement && element.href) {
return element.href;
}
const hrefAttr = element.getAttribute('href');
return hrefAttr && !hrefAttr.startsWith('javascript:') ? hrefAttr : undefined;
}
}
const CROSS_DOMAIN_PARAMS = ['_xm', '_xsollauid', '_xmvid'];
class CrossDomainTracker extends BaseTracker {
constructor() {
super(...arguments);
Object.defineProperty(this, "allowedDomains", {
enumerable: true,
configurable: true,
writable: true,
value: new Set()
});
Object.defineProperty(this, "listenerOptions", {
enumerable: true,
configurable: true,
writable: true,
value: { capture: true, passive: true }
});
Object.defineProperty(this, "handleMouseDown", {
enumerable: true,
configurable: true,
writable: true,
value: (event) => {
const ids = this.getIds();
if (!ids)
return;
const link = event.target.closest('a');
if (!link)
return;
if (!this.allowedDomains.has(link.host))
return;
this.decorateUrl(link, ids.xsollauid, ids.visitorId);
}
});
Object.defineProperty(this, "handleKeyUp", {
enumerable: true,
configurable: true,
writable: true,
value: (event) => {
if (event.key !== 'Enter')
return;
const ids = this.getIds();
if (!ids)
return;
const link = event.target.closest('a');
if (!link)
return;
if (!this.allowedDomains.has(link.host))
return;
this.decorateUrl(link, ids.xsollauid, ids.visitorId);
}
});
Object.defineProperty(this, "handleSubmit", {
enumerable: true,
configurable: true,
writable: true,
value: (event) => {
const ids = this.getIds();
if (!ids)
return;
const form = event.target;
if (!form.action)
return;
try {
const actionUrl = new URL(form.action, window.location.origin);
if (!this.allowedDomains.has(actionUrl.host))
return;
if (form.method.toUpperCase() === 'GET') {
// GET forms: add hidden input (values become query params on submit)
this.addHiddenInput(form, '_xm', ids.xsollauid);
if (ids.visitorId) {
this.addHiddenInput(form, '_xmvid', ids.visitorId);
}
}
else {
// POST forms: decorate action URL (params must be in URL, not body)
this.decorateFormAction(form, actionUrl, ids.xsollauid, ids.visitorId);
}
}
catch {
// Ignore invalid action URLs
}
}
});
}
init() {
const { siteDomains } = this.analytics['config'];
siteDomains.forEach((d) => this.allowedDomains.add(d));
// mousedown fires before navigation for any mouse button (left, middle, right)
document.addEventListener('mousedown', this.handleMouseDown, this.listenerOptions);
// keyup catches Enter key on focused links (keyboard navigation)
document.addEventListener('keyup', this.handleKeyUp, this.listenerOptions);
// submit catches form submissions to cross-domain targets
document.addEventListener('submit', this.handleSubmit, this.listenerOptions);
}
destroy() {
if (typeof document === 'undefined')
return;
document.removeEventListener('mousedown', this.handleMouseDown, this.listenerOptions);
document.removeEventListener('keyup', this.handleKeyUp, this.listenerOptions);
document.removeEventListener('submit', this.handleSubmit, this.listenerOptions);
}
getIds() {
const { xsollauid, visitorId } = this.analytics['config'];
return xsollauid ? { xsollauid, visitorId } : null;
}
decorateUrl(link, uid, visitorId) {
try {
const url = new URL(link.href, window.location.origin);
if (url.searchParams.get('_xm') === uid || url.searchParams.get('_xsollauid') === uid)
return;
if (url.searchParams.has('_xsollauid')) {
url.searchParams.set('_xsollauid', uid);
}
else {
url.searchParams.set('_xm', uid);
}
if (visitorId && !url.searchParams.has('_xmvid')) {
url.searchParams.set('_xmvid', visitorId);
}
link.href = url.toString();
}
catch {
// Ignore errors when creating URL
}
}
decorateFormAction(form, actionUrl, uid, visitorId) {
if (actionUrl.searchParams.has('_xsollauid')) {
actionUrl.searchParams.set('_xsollauid', uid);
}
else {
actionUrl.searchParams.set('_xm', uid);
}
if (visitorId && !actionUrl.searchParams.has('_xmvid')) {
actionUrl.searchParams.set('_xmvid', visitorId);
}
form.action = actionUrl.toString();
}
addHiddenInput(form, name, value) {
// Reuse existing hidden input if present, otherwise create new
let input = form.querySelector(`input[type="hidden"][name="${name}"]`);
if (input) {
input.value = value;
}
else {
input = document.createElement('input');
input.type = 'hidden';
input.name = name;
input.value = value;
form.appendChild(input);
}
}
/**
* Removes cross-domain tracking parameters from the current URL.
* Should be called after the SDK has read the parameters.
*/
static cleanUrl() {
try {
const url = new URL(window.location.href);
let changed = false;
for (const param of CROSS_DOMAIN_PARAMS) {
if (url.searchParams.has(param)) {
url.searchParams.delete(param);
changed = true;
}
}
if (changed) {
// replaceState (not pushState) to avoid creating a back-button entry
history.replaceState(history.state, '', url.toString());
}
}
catch {
// Ignore errors
}
}
}
class ExternalLinkTracker extends BaseTracker {
constructor() {
super(...arguments);
Object.defineProperty(this, "selector", {
enumerable: true,
configurable: true,
writable: true,
value: 'a'
});
Object.defineProperty(this, "allowedDomains", {
enumerable: true,
configurable: true,
writable: true,
value: []
});
Object.defineProperty(this, "listenerOptions", {
enumerable: true,
configurable: true,
writable: true,
value: { capture: true, passive: true }
});
Object.defineProperty(this, "handleClick", {
enumerable: true,
configurable: true,
writable: true,
value: (event) => {
const target = event.target;
if (!target)
return;
const link = target.closest(this.selector);
if (!link)
return;
const linkHost = link.host;
if (this.allowedDomains.includes(linkHost))
return;
const eventData = {
type: EVENT_TYPE.EXTERNAL_LINK,
data: {
url: link.href,
referer: location.href,
},
useBeacon: true,
};
this.analytics.sendEvent(eventData);
}
});
}
init() {
const config = this.analytics['config'];
document.addEventListener('click', this.handleClick, this.listenerOptions);
this.allowedDomains = config.siteDomains;
}
destroy() {
if (typeof document === 'undefined')
return;
document.removeEventListener('click', this.handleClick, this.listenerOptions);
}
}
const listeners = new Set();
const listenerOptions = { passive: true };
let isListening = false;
let lastUrl = typeof location !== 'undefined' ? location.href : '';
// --- Shared dispatcher ---
const runListeners = (url, referer) => {
listeners.forEach((listener) => {
try {
listener(url, referer);
}
catch (error) {
console.error('[XsollaAnalytics] Navigation listener error', error);
}
});
};
const handleNavigation = () => {
if (typeof location === 'undefined')
return;
const currentUrl = location.href;
if (currentUrl === lastUrl)
return;
const referer = lastUrl;
lastUrl = currentUrl;
runListeners(currentUrl, referer);
};
// --- Navigation API path (Chrome 102+, Firefox 147+, Safari 26.2+) ---
let navigateHandler;
const setupNavigationAPI = () => {
navigateHandler = () => {
handleNavigation();
};
window.navigation.addEventListener('navigate', navigateHandler);
};
const teardownNavigationAPI = () => {
if (navigateHandler) {
window.navigation.removeEventListener('navigate', navigateHandler);
navigateHandler = undefined;
}
};
// --- History API monkey-patch path (fallback) ---
// Save from PROTOTYPE, not instance — avoids capturing another library's wrapper
const nativePushState = typeof History !== 'undefined' ? History.prototype.pushState : undefined;
const nativeReplaceState = typeof History !== 'undefined' ? History.prototype.replaceState : undefined;
let wrappedPushState;
let wrappedReplaceState;
const setupHistoryMonkeyPatch = () => {
if (typeof history === 'undefined')
return;
if (nativePushState) {
wrappedPushState = function (...args) {
const result = nativePushState.apply(this, args);
handleNavigation();
return result;
};
history.pushState = wrappedPushState;
}
if (nativeReplaceState) {
wrappedReplaceState = function (...args) {
const result = nativeReplaceState.apply(this, args);
handleNavigation();
return result;
};
history.replaceState = wrappedReplaceState;
}
window.addEventListener('popstate', handleNavigation, listenerOptions);
window.addEventListener('hashchange', handleNavigation, listenerOptions);
};
const teardownHistoryMonkeyPatch = () => {
if (typeof history === 'undefined' || typeof window === 'undefined')
return;
window.removeEventListener('popstate', handleNavigation, listenerOptions);
window.removeEventListener('hashchange', handleNavigation, listenerOptions);
// Identity-check before restore: don't clobber patches from other libraries
if (wrappedPushState && history.pushState === wrappedPushState) {
history.pushState = nativePushState;
}
if (wrappedReplaceState && history.replaceState === wrappedReplaceState) {
history.replaceState = nativeReplaceState;
}
wrappedPushState = undefined;
wrappedReplaceState = undefined;
};
// --- Public API (signature UNCHANGED) ---
const setup = () => {
if (isListening)
return;
if (typeof windo