@tracetail/js 2.3.7 → 2.3.8

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/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @tracetail/js - Enterprise Browser Fingerprinting SDK
3
- * Version: 2.3.4
3
+ * Version: 2.3.7
4
4
  *
5
5
  * Over 99.5% accuracy browser fingerprinting with server-side processing.
6
6
  * Perfect for fraud detection, user analytics, and security applications.
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,"__esModule",{value:!0});class e{constructor(e){if(this.cache=new Map,!e.apiKey)throw new Error("TraceTail: API key is required. Get yours at https://tracetail.io");this.options={apiKey:e.apiKey,endpoint:e.endpoint||"https://tracetail.io/api",timeout:e.timeout||1e4,debug:e.debug||!1,caching:!1!==e.caching,respectDNT:e.respectDNT||!1,includeIP:!1!==e.includeIP,storeFingerprints:!1!==e.storeFingerprints,enableWorkers:!1!==e.enableWorkers,batchRequests:!1!==e.batchRequests,fallbackMode:e.fallbackMode||"basic"},this.log("TraceTail SDK initialized",{version:"2.3.4",options:this.options})}async generateFingerprint(e){const t=performance.now();try{if(this.options.respectDNT&&this.isDNTEnabled())throw new Error("TraceTail: Do Not Track is enabled");const n="basic_fingerprint";if(this.options.caching&&this.cache.has(n)){const e=this.cache.get(n);if(e)return this.log("Using cached fingerprint",e),e}const r=await this.collectComponents(),i=Math.round(performance.now()-t);if(this.options.apiKey&&this.options.endpoint)try{const i=await this.sendToServer(r,null==e?void 0:e.verbose);if(i){const e={...i,processingTime:Math.round(performance.now()-t)};return this.options.caching&&this.cache.set(n,e),this.log("Server-enhanced fingerprint generated",e),e}}catch(e){this.log("Server processing failed, falling back to client-side",e)}const o=await this.generateVisitorId(r),a={visitorId:o,confidence:this.calculateConfidence(r),processingTime:i,...(null==e?void 0:e.verbose)&&{components:r}};return this.options.caching&&this.cache.set(n,a),this.log("Client-side fingerprint generated",a),a}catch(e){throw this.log("Fingerprint generation failed",e),e}}async sendToServer(e,t){try{const n=new AbortController,r=setTimeout(()=>n.abort(),this.options.timeout),i=await fetch(`${this.options.endpoint}/id`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.options.apiKey}`,"X-TraceTail-SDK":"js/2.3.4"},body:JSON.stringify({components:e,verbose:t||!1,clientCapabilities:{timestamp:Date.now(),sdkVersion:"2.3.4"}}),signal:n.signal});if(clearTimeout(r),!i.ok){if(401===i.status)throw new Error("Invalid API key");throw new Error(`Server returned ${i.status}`)}const o=await i.json();return{visitorId:o.visitorId,confidence:o.confidence,processingTime:o.processingTime||0,...t&&o.components&&{components:o.components}}}catch(e){return this.options.debug&&console.error("[TraceTail] Server error:",e),null}}static getVersion(){return"2.3.4"}static validateApiKey(e){return/^tt_(test|prod)_[a-zA-Z0-9]{32,}$/.test(e)}async collectComponents(){const e={};try{e.screen={width:screen.width,height:screen.height,colorDepth:screen.colorDepth,pixelRatio:window.devicePixelRatio||1},e.timezone=Intl.DateTimeFormat().resolvedOptions().timeZone,e.language=navigator.language,e.platform=navigator.platform,e.userAgent=navigator.userAgent,e.cookiesEnabled=navigator.cookieEnabled,e.localStorage=this.testStorage("localStorage"),e.sessionStorage=this.testStorage("sessionStorage"),e.indexedDB="indexedDB"in window,e.canvas=await this.generateCanvasFingerprint(),e.webgl=this.generateWebGLFingerprint(),e.audio=await this.generateAudioFingerprint(),e.fonts=this.detectFonts(),e.webRTC=await this.generateWebRTCFingerprint()}catch(e){this.log("Component collection error",e)}return e}async generateVisitorId(e){const t=JSON.stringify(e,Object.keys(e).sort()),n=(new TextEncoder).encode(t),r=await crypto.subtle.digest("SHA-256",n);return`fp_${Array.from(new Uint8Array(r)).map(e=>e.toString(16).padStart(2,"0")).join("").substring(0,32)}`}calculateConfidence(e){let t=0,n=0;const r={canvas:.25,webgl:.2,audio:.15,fonts:.15,screen:.1,webRTC:.15};for(const[i,o]of Object.entries(r))n+=o,e[i]&&(t+=o);return Math.min(.995,Math.max(.7,t/n))}async generateCanvasFingerprint(){try{const e=document.createElement("canvas"),t=e.getContext("2d");return t?(e.width=200,e.height=50,t.textBaseline="top",t.font="14px Arial",t.fillStyle="#f60",t.fillRect(125,1,62,20),t.fillStyle="#069",t.fillText("TraceTail 🔒",2,15),t.fillStyle="rgba(102, 204, 0, 0.2)",t.fillText("TraceTail 🔒",4,17),e.toDataURL().substring(0,100)):"unsupported"}catch(e){return"error"}}generateWebGLFingerprint(){try{const e=document.createElement("canvas"),t=e.getContext("webgl")||e.getContext("experimental-webgl");if(!t)return"unsupported";const n=t.getParameter(t.RENDERER);return`${t.getParameter(t.VENDOR)}-${n}`.substring(0,100)}catch(e){return"error"}}async generateAudioFingerprint(){try{const e=window.AudioContext||window.webkitAudioContext;if(!e)return"unsupported";const t=new e,n=t.createOscillator(),r=t.createAnalyser(),i=t.createDynamicsCompressor();n.type="triangle",n.frequency.setValueAtTime(1e4,t.currentTime),n.connect(i),i.connect(r),n.start(0),await new Promise(e=>setTimeout(e,100));const o=new Float32Array(r.frequencyBinCount);return r.getFloatFrequencyData(o),n.stop(),await t.close(),Array.from(o.slice(0,30)).map(e=>Math.abs(e)).join(",")}catch(e){return"error"}}detectFonts(){const e=["Arial","Helvetica","Times","Courier","Verdana","Georgia","Palatino","Garamond","Bookman","Comic Sans MS","Trebuchet MS","Arial Black","Impact"],t=[],n=document.createElement("div");n.style.position="absolute",n.style.left="-9999px",document.body.appendChild(n);try{for(const r of e){const e=document.createElement("span");e.style.fontSize="72px",e.style.fontFamily=r,e.textContent="mmmmmmmmmmlli",n.appendChild(e),e.offsetWidth>0&&t.push(r)}}finally{document.body.removeChild(n)}return t}async generateWebRTCFingerprint(){try{if(!window.RTCPeerConnection)return"unsupported";const e=new RTCPeerConnection({iceServers:[{urls:"stun:stun.l.google.com:19302"}]});e.createDataChannel("tracetail");const t=new Promise(t=>{const n=setTimeout(()=>t(),1e3);e.onicegatheringstatechange=()=>{"complete"===e.iceGatheringState&&(clearTimeout(n),t())}});await e.createOffer(),await e.setLocalDescription(),await t;const n=e.localDescription;e.close();return((null==n?void 0:n.sdp)||"error").split("\n").filter(e=>!e.includes("a=ice-pwd")&&!e.includes("a=ice-ufrag")).join("").substring(0,100)}catch(e){return"error"}}testStorage(e){try{const t=window[e],n="__tt_test__";return t.setItem(n,"test"),t.removeItem(n),!0}catch(e){return!1}}isDNTEnabled(){return"1"===navigator.doNotTrack||"1"===window.doNotTrack||"1"===navigator.msDoNotTrack}log(e,t){this.options.debug&&console.log(`[TraceTail] ${e}`,t)}}exports.TraceTail=e,exports.default=e;
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0});class e{constructor(e){if(this.cache=new Map,!e.apiKey)throw new Error("TraceTail: API key is required. Get yours at https://tracetail.io");this.options={apiKey:e.apiKey,endpoint:e.endpoint||"/api",timeout:e.timeout||1e4,debug:e.debug||!1,caching:!1!==e.caching,respectDNT:e.respectDNT||!1,includeIP:!1!==e.includeIP,storeFingerprints:!1!==e.storeFingerprints,enableWorkers:!1!==e.enableWorkers,batchRequests:!1!==e.batchRequests,fallbackMode:e.fallbackMode||"basic"},this.log("TraceTail SDK initialized",{version:"2.3.7",options:this.options})}async generateFingerprint(e){const t=performance.now();try{if(this.options.respectDNT&&this.isDNTEnabled())throw new Error("TraceTail: Do Not Track is enabled");const n=!0===(null==e?void 0:e.verbose),r=n?"fingerprint_verbose":"fingerprint_basic";if(this.options.caching&&this.cache.has(r)){const e=this.cache.get(r);if(e)return this.log("Using cached fingerprint",e),e}const i=await this.collectComponents(),o=Math.round(performance.now()-t);if(this.options.apiKey&&this.options.endpoint){const e={...await this.sendToServer(i,n),processingTime:Math.round(performance.now()-t)};return this.options.caching&&this.cache.set(r,e),this.log("Server-enhanced fingerprint generated",e),e}const a=await this.generateVisitorId(i),s={visitorId:a,confidence:this.calculateConfidence(i),processingTime:o,...n&&{components:i}};return this.options.caching&&this.cache.set(r,s),this.log("Client-side fingerprint generated",s),s}catch(e){throw this.log("Fingerprint generation failed",e),e}}async sendToServer(e,t){const n=new AbortController,r=setTimeout(()=>n.abort(),this.options.timeout);try{const i=await fetch(`${this.options.endpoint}/id`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.options.apiKey}`,"X-TraceTail-SDK":"js/2.3.7"},body:JSON.stringify({components:e,verbose:t||!1,clientCapabilities:{timestamp:Date.now(),sdkVersion:"2.3.7"}}),signal:n.signal});if(clearTimeout(r),!i.ok){if(401===i.status)throw new Error("Invalid API key");throw new Error(`Server returned ${i.status}`)}const o=await i.json(),a={visitorId:o.visitorId,confidence:o.confidence,processingTime:o.processingTime||0};if(t){if(!o.components)throw new Error("Server did not return components in verbose mode");a.components=o.components}return a}catch(e){throw clearTimeout(r),this.options.debug&&console.error("[TraceTail] Server error:",e),e}}static getVersion(){return"2.3.7"}static validateApiKey(e){return/^tt_(test|prod)_[a-zA-Z0-9]{32,}$/.test(e)}async collectComponents(){const e={};try{e.screen={width:screen.width,height:screen.height,colorDepth:screen.colorDepth,pixelRatio:window.devicePixelRatio||1},e.timezone=Intl.DateTimeFormat().resolvedOptions().timeZone,e.language=navigator.language,e.platform=navigator.platform,e.userAgent=navigator.userAgent,e.cookiesEnabled=navigator.cookieEnabled,e.localStorage=this.testStorage("localStorage"),e.sessionStorage=this.testStorage("sessionStorage"),e.indexedDB="indexedDB"in window,e.canvas=await this.generateCanvasFingerprint(),e.webgl=this.generateWebGLFingerprint(),e.audio=await this.generateAudioFingerprint(),e.fonts=this.detectFonts(),e.webRTC=await this.generateWebRTCFingerprint()}catch(e){this.log("Component collection error",e)}return e}async generateVisitorId(e){const t=JSON.stringify(e,Object.keys(e).sort()),n=(new TextEncoder).encode(t),r=await crypto.subtle.digest("SHA-256",n);return`fp_${Array.from(new Uint8Array(r)).map(e=>e.toString(16).padStart(2,"0")).join("").substring(0,32)}`}calculateConfidence(e){let t=0,n=0;const r={canvas:.25,webgl:.2,audio:.15,fonts:.15,screen:.1,webRTC:.15};for(const[i,o]of Object.entries(r))n+=o,e[i]&&(t+=o);return Math.min(.995,Math.max(.7,t/n))}async generateCanvasFingerprint(){try{const e=document.createElement("canvas"),t=e.getContext("2d");return t?(e.width=200,e.height=50,t.textBaseline="top",t.font="14px Arial",t.fillStyle="#f60",t.fillRect(125,1,62,20),t.fillStyle="#069",t.fillText("TraceTail 🔒",2,15),t.fillStyle="rgba(102, 204, 0, 0.2)",t.fillText("TraceTail 🔒",4,17),e.toDataURL().substring(0,100)):"unsupported"}catch(e){return"error"}}generateWebGLFingerprint(){try{const e=document.createElement("canvas"),t=e.getContext("webgl")||e.getContext("experimental-webgl");if(!t)return"unsupported";const n=t.getParameter(t.RENDERER);return`${t.getParameter(t.VENDOR)}-${n}`.substring(0,100)}catch(e){return"error"}}async generateAudioFingerprint(){try{const e=window.AudioContext||window.webkitAudioContext;if(!e)return"unsupported";const t=new e,n=t.createOscillator(),r=t.createAnalyser(),i=t.createDynamicsCompressor();n.type="triangle",n.frequency.setValueAtTime(1e4,t.currentTime),n.connect(i),i.connect(r),n.start(0),await new Promise(e=>setTimeout(e,100));const o=new Float32Array(r.frequencyBinCount);return r.getFloatFrequencyData(o),n.stop(),await t.close(),Array.from(o.slice(0,30)).map(e=>Math.abs(e)).join(",")}catch(e){return"error"}}detectFonts(){const e=["Arial","Helvetica","Times","Courier","Verdana","Georgia","Palatino","Garamond","Bookman","Comic Sans MS","Trebuchet MS","Arial Black","Impact"],t=[],n=document.createElement("div");n.style.position="absolute",n.style.left="-9999px",document.body.appendChild(n);try{for(const r of e){const e=document.createElement("span");e.style.fontSize="72px",e.style.fontFamily=r,e.textContent="mmmmmmmmmmlli",n.appendChild(e),e.offsetWidth>0&&t.push(r)}}finally{document.body.removeChild(n)}return t}async generateWebRTCFingerprint(){try{if(!window.RTCPeerConnection)return"unsupported";const e=new RTCPeerConnection({iceServers:[{urls:"stun:stun.l.google.com:19302"}]});e.createDataChannel("tracetail");const t=new Promise(t=>{const n=setTimeout(()=>t(),1e3);e.onicegatheringstatechange=()=>{"complete"===e.iceGatheringState&&(clearTimeout(n),t())}});await e.createOffer(),await e.setLocalDescription(),await t;const n=e.localDescription;e.close();return((null==n?void 0:n.sdp)||"error").split("\n").filter(e=>!e.includes("a=ice-pwd")&&!e.includes("a=ice-ufrag")).join("").substring(0,100)}catch(e){return"error"}}testStorage(e){try{const t=window[e],n="__tt_test__";return t.setItem(n,"test"),t.removeItem(n),!0}catch(e){return!1}}isDNTEnabled(){return"1"===navigator.doNotTrack||"1"===window.doNotTrack||"1"===navigator.msDoNotTrack}log(e,t){this.options.debug&&console.log(`[TraceTail] ${e}`,t)}}exports.TraceTail=e,exports.default=e;
package/dist/index.mjs CHANGED
@@ -1 +1 @@
1
- class e{constructor(e){if(this.cache=new Map,!e.apiKey)throw new Error("TraceTail: API key is required. Get yours at https://tracetail.io");this.options={apiKey:e.apiKey,endpoint:e.endpoint||"https://tracetail.io/api",timeout:e.timeout||1e4,debug:e.debug||!1,caching:!1!==e.caching,respectDNT:e.respectDNT||!1,includeIP:!1!==e.includeIP,storeFingerprints:!1!==e.storeFingerprints,enableWorkers:!1!==e.enableWorkers,batchRequests:!1!==e.batchRequests,fallbackMode:e.fallbackMode||"basic"},this.log("TraceTail SDK initialized",{version:"2.3.4",options:this.options})}async generateFingerprint(e){const t=performance.now();try{if(this.options.respectDNT&&this.isDNTEnabled())throw new Error("TraceTail: Do Not Track is enabled");const n="basic_fingerprint";if(this.options.caching&&this.cache.has(n)){const e=this.cache.get(n);if(e)return this.log("Using cached fingerprint",e),e}const r=await this.collectComponents(),i=Math.round(performance.now()-t);if(this.options.apiKey&&this.options.endpoint)try{const i=await this.sendToServer(r,null==e?void 0:e.verbose);if(i){const e={...i,processingTime:Math.round(performance.now()-t)};return this.options.caching&&this.cache.set(n,e),this.log("Server-enhanced fingerprint generated",e),e}}catch(e){this.log("Server processing failed, falling back to client-side",e)}const o=await this.generateVisitorId(r),a={visitorId:o,confidence:this.calculateConfidence(r),processingTime:i,...(null==e?void 0:e.verbose)&&{components:r}};return this.options.caching&&this.cache.set(n,a),this.log("Client-side fingerprint generated",a),a}catch(e){throw this.log("Fingerprint generation failed",e),e}}async sendToServer(e,t){try{const n=new AbortController,r=setTimeout(()=>n.abort(),this.options.timeout),i=await fetch(`${this.options.endpoint}/id`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.options.apiKey}`,"X-TraceTail-SDK":"js/2.3.4"},body:JSON.stringify({components:e,verbose:t||!1,clientCapabilities:{timestamp:Date.now(),sdkVersion:"2.3.4"}}),signal:n.signal});if(clearTimeout(r),!i.ok){if(401===i.status)throw new Error("Invalid API key");throw new Error(`Server returned ${i.status}`)}const o=await i.json();return{visitorId:o.visitorId,confidence:o.confidence,processingTime:o.processingTime||0,...t&&o.components&&{components:o.components}}}catch(e){return this.options.debug&&console.error("[TraceTail] Server error:",e),null}}static getVersion(){return"2.3.4"}static validateApiKey(e){return/^tt_(test|prod)_[a-zA-Z0-9]{32,}$/.test(e)}async collectComponents(){const e={};try{e.screen={width:screen.width,height:screen.height,colorDepth:screen.colorDepth,pixelRatio:window.devicePixelRatio||1},e.timezone=Intl.DateTimeFormat().resolvedOptions().timeZone,e.language=navigator.language,e.platform=navigator.platform,e.userAgent=navigator.userAgent,e.cookiesEnabled=navigator.cookieEnabled,e.localStorage=this.testStorage("localStorage"),e.sessionStorage=this.testStorage("sessionStorage"),e.indexedDB="indexedDB"in window,e.canvas=await this.generateCanvasFingerprint(),e.webgl=this.generateWebGLFingerprint(),e.audio=await this.generateAudioFingerprint(),e.fonts=this.detectFonts(),e.webRTC=await this.generateWebRTCFingerprint()}catch(e){this.log("Component collection error",e)}return e}async generateVisitorId(e){const t=JSON.stringify(e,Object.keys(e).sort()),n=(new TextEncoder).encode(t),r=await crypto.subtle.digest("SHA-256",n);return`fp_${Array.from(new Uint8Array(r)).map(e=>e.toString(16).padStart(2,"0")).join("").substring(0,32)}`}calculateConfidence(e){let t=0,n=0;const r={canvas:.25,webgl:.2,audio:.15,fonts:.15,screen:.1,webRTC:.15};for(const[i,o]of Object.entries(r))n+=o,e[i]&&(t+=o);return Math.min(.995,Math.max(.7,t/n))}async generateCanvasFingerprint(){try{const e=document.createElement("canvas"),t=e.getContext("2d");return t?(e.width=200,e.height=50,t.textBaseline="top",t.font="14px Arial",t.fillStyle="#f60",t.fillRect(125,1,62,20),t.fillStyle="#069",t.fillText("TraceTail 🔒",2,15),t.fillStyle="rgba(102, 204, 0, 0.2)",t.fillText("TraceTail 🔒",4,17),e.toDataURL().substring(0,100)):"unsupported"}catch(e){return"error"}}generateWebGLFingerprint(){try{const e=document.createElement("canvas"),t=e.getContext("webgl")||e.getContext("experimental-webgl");if(!t)return"unsupported";const n=t.getParameter(t.RENDERER);return`${t.getParameter(t.VENDOR)}-${n}`.substring(0,100)}catch(e){return"error"}}async generateAudioFingerprint(){try{const e=window.AudioContext||window.webkitAudioContext;if(!e)return"unsupported";const t=new e,n=t.createOscillator(),r=t.createAnalyser(),i=t.createDynamicsCompressor();n.type="triangle",n.frequency.setValueAtTime(1e4,t.currentTime),n.connect(i),i.connect(r),n.start(0),await new Promise(e=>setTimeout(e,100));const o=new Float32Array(r.frequencyBinCount);return r.getFloatFrequencyData(o),n.stop(),await t.close(),Array.from(o.slice(0,30)).map(e=>Math.abs(e)).join(",")}catch(e){return"error"}}detectFonts(){const e=["Arial","Helvetica","Times","Courier","Verdana","Georgia","Palatino","Garamond","Bookman","Comic Sans MS","Trebuchet MS","Arial Black","Impact"],t=[],n=document.createElement("div");n.style.position="absolute",n.style.left="-9999px",document.body.appendChild(n);try{for(const r of e){const e=document.createElement("span");e.style.fontSize="72px",e.style.fontFamily=r,e.textContent="mmmmmmmmmmlli",n.appendChild(e),e.offsetWidth>0&&t.push(r)}}finally{document.body.removeChild(n)}return t}async generateWebRTCFingerprint(){try{if(!window.RTCPeerConnection)return"unsupported";const e=new RTCPeerConnection({iceServers:[{urls:"stun:stun.l.google.com:19302"}]});e.createDataChannel("tracetail");const t=new Promise(t=>{const n=setTimeout(()=>t(),1e3);e.onicegatheringstatechange=()=>{"complete"===e.iceGatheringState&&(clearTimeout(n),t())}});await e.createOffer(),await e.setLocalDescription(),await t;const n=e.localDescription;e.close();return((null==n?void 0:n.sdp)||"error").split("\n").filter(e=>!e.includes("a=ice-pwd")&&!e.includes("a=ice-ufrag")).join("").substring(0,100)}catch(e){return"error"}}testStorage(e){try{const t=window[e],n="__tt_test__";return t.setItem(n,"test"),t.removeItem(n),!0}catch(e){return!1}}isDNTEnabled(){return"1"===navigator.doNotTrack||"1"===window.doNotTrack||"1"===navigator.msDoNotTrack}log(e,t){this.options.debug&&console.log(`[TraceTail] ${e}`,t)}}export{e as TraceTail,e as default};
1
+ class e{constructor(e){if(this.cache=new Map,!e.apiKey)throw new Error("TraceTail: API key is required. Get yours at https://tracetail.io");this.options={apiKey:e.apiKey,endpoint:e.endpoint||"/api",timeout:e.timeout||1e4,debug:e.debug||!1,caching:!1!==e.caching,respectDNT:e.respectDNT||!1,includeIP:!1!==e.includeIP,storeFingerprints:!1!==e.storeFingerprints,enableWorkers:!1!==e.enableWorkers,batchRequests:!1!==e.batchRequests,fallbackMode:e.fallbackMode||"basic"},this.log("TraceTail SDK initialized",{version:"2.3.7",options:this.options})}async generateFingerprint(e){const t=performance.now();try{if(this.options.respectDNT&&this.isDNTEnabled())throw new Error("TraceTail: Do Not Track is enabled");const n=!0===(null==e?void 0:e.verbose),r=n?"fingerprint_verbose":"fingerprint_basic";if(this.options.caching&&this.cache.has(r)){const e=this.cache.get(r);if(e)return this.log("Using cached fingerprint",e),e}const i=await this.collectComponents(),o=Math.round(performance.now()-t);if(this.options.apiKey&&this.options.endpoint){const e={...await this.sendToServer(i,n),processingTime:Math.round(performance.now()-t)};return this.options.caching&&this.cache.set(r,e),this.log("Server-enhanced fingerprint generated",e),e}const a=await this.generateVisitorId(i),s={visitorId:a,confidence:this.calculateConfidence(i),processingTime:o,...n&&{components:i}};return this.options.caching&&this.cache.set(r,s),this.log("Client-side fingerprint generated",s),s}catch(e){throw this.log("Fingerprint generation failed",e),e}}async sendToServer(e,t){const n=new AbortController,r=setTimeout(()=>n.abort(),this.options.timeout);try{const i=await fetch(`${this.options.endpoint}/id`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.options.apiKey}`,"X-TraceTail-SDK":"js/2.3.7"},body:JSON.stringify({components:e,verbose:t||!1,clientCapabilities:{timestamp:Date.now(),sdkVersion:"2.3.7"}}),signal:n.signal});if(clearTimeout(r),!i.ok){if(401===i.status)throw new Error("Invalid API key");throw new Error(`Server returned ${i.status}`)}const o=await i.json(),a={visitorId:o.visitorId,confidence:o.confidence,processingTime:o.processingTime||0};if(t){if(!o.components)throw new Error("Server did not return components in verbose mode");a.components=o.components}return a}catch(e){throw clearTimeout(r),this.options.debug&&console.error("[TraceTail] Server error:",e),e}}static getVersion(){return"2.3.7"}static validateApiKey(e){return/^tt_(test|prod)_[a-zA-Z0-9]{32,}$/.test(e)}async collectComponents(){const e={};try{e.screen={width:screen.width,height:screen.height,colorDepth:screen.colorDepth,pixelRatio:window.devicePixelRatio||1},e.timezone=Intl.DateTimeFormat().resolvedOptions().timeZone,e.language=navigator.language,e.platform=navigator.platform,e.userAgent=navigator.userAgent,e.cookiesEnabled=navigator.cookieEnabled,e.localStorage=this.testStorage("localStorage"),e.sessionStorage=this.testStorage("sessionStorage"),e.indexedDB="indexedDB"in window,e.canvas=await this.generateCanvasFingerprint(),e.webgl=this.generateWebGLFingerprint(),e.audio=await this.generateAudioFingerprint(),e.fonts=this.detectFonts(),e.webRTC=await this.generateWebRTCFingerprint()}catch(e){this.log("Component collection error",e)}return e}async generateVisitorId(e){const t=JSON.stringify(e,Object.keys(e).sort()),n=(new TextEncoder).encode(t),r=await crypto.subtle.digest("SHA-256",n);return`fp_${Array.from(new Uint8Array(r)).map(e=>e.toString(16).padStart(2,"0")).join("").substring(0,32)}`}calculateConfidence(e){let t=0,n=0;const r={canvas:.25,webgl:.2,audio:.15,fonts:.15,screen:.1,webRTC:.15};for(const[i,o]of Object.entries(r))n+=o,e[i]&&(t+=o);return Math.min(.995,Math.max(.7,t/n))}async generateCanvasFingerprint(){try{const e=document.createElement("canvas"),t=e.getContext("2d");return t?(e.width=200,e.height=50,t.textBaseline="top",t.font="14px Arial",t.fillStyle="#f60",t.fillRect(125,1,62,20),t.fillStyle="#069",t.fillText("TraceTail 🔒",2,15),t.fillStyle="rgba(102, 204, 0, 0.2)",t.fillText("TraceTail 🔒",4,17),e.toDataURL().substring(0,100)):"unsupported"}catch(e){return"error"}}generateWebGLFingerprint(){try{const e=document.createElement("canvas"),t=e.getContext("webgl")||e.getContext("experimental-webgl");if(!t)return"unsupported";const n=t.getParameter(t.RENDERER);return`${t.getParameter(t.VENDOR)}-${n}`.substring(0,100)}catch(e){return"error"}}async generateAudioFingerprint(){try{const e=window.AudioContext||window.webkitAudioContext;if(!e)return"unsupported";const t=new e,n=t.createOscillator(),r=t.createAnalyser(),i=t.createDynamicsCompressor();n.type="triangle",n.frequency.setValueAtTime(1e4,t.currentTime),n.connect(i),i.connect(r),n.start(0),await new Promise(e=>setTimeout(e,100));const o=new Float32Array(r.frequencyBinCount);return r.getFloatFrequencyData(o),n.stop(),await t.close(),Array.from(o.slice(0,30)).map(e=>Math.abs(e)).join(",")}catch(e){return"error"}}detectFonts(){const e=["Arial","Helvetica","Times","Courier","Verdana","Georgia","Palatino","Garamond","Bookman","Comic Sans MS","Trebuchet MS","Arial Black","Impact"],t=[],n=document.createElement("div");n.style.position="absolute",n.style.left="-9999px",document.body.appendChild(n);try{for(const r of e){const e=document.createElement("span");e.style.fontSize="72px",e.style.fontFamily=r,e.textContent="mmmmmmmmmmlli",n.appendChild(e),e.offsetWidth>0&&t.push(r)}}finally{document.body.removeChild(n)}return t}async generateWebRTCFingerprint(){try{if(!window.RTCPeerConnection)return"unsupported";const e=new RTCPeerConnection({iceServers:[{urls:"stun:stun.l.google.com:19302"}]});e.createDataChannel("tracetail");const t=new Promise(t=>{const n=setTimeout(()=>t(),1e3);e.onicegatheringstatechange=()=>{"complete"===e.iceGatheringState&&(clearTimeout(n),t())}});await e.createOffer(),await e.setLocalDescription(),await t;const n=e.localDescription;e.close();return((null==n?void 0:n.sdp)||"error").split("\n").filter(e=>!e.includes("a=ice-pwd")&&!e.includes("a=ice-ufrag")).join("").substring(0,100)}catch(e){return"error"}}testStorage(e){try{const t=window[e],n="__tt_test__";return t.setItem(n,"test"),t.removeItem(n),!0}catch(e){return!1}}isDNTEnabled(){return"1"===navigator.doNotTrack||"1"===window.doNotTrack||"1"===navigator.msDoNotTrack}log(e,t){this.options.debug&&console.log(`[TraceTail] ${e}`,t)}}export{e as TraceTail,e as default};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tracetail/js",
3
- "version": "2.3.7",
3
+ "version": "2.3.8",
4
4
  "description": "TraceTail JavaScript SDK for browser fingerprinting",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",