@tracetail/js 2.3.11 → 2.3.12

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/README.md CHANGED
@@ -339,7 +339,7 @@ npm run build
339
339
  - **Documentation**: [docs.tracetail.io](https://docs.tracetail.io)
340
340
  - **API Reference**: [tracetail.io/api/docs](https://tracetail.io/api/docs)
341
341
  - **GitHub Issues**: [github.com/tracetail/tracetail/issues](https://github.com/tracetail/tracetail/issues)
342
- - **Email**: support@tracetail.com
342
+ - **Email**: support@tracetail.io
343
343
  - **Discord**: [discord.gg/tracetail](https://discord.gg/tracetail)
344
344
 
345
345
  ## 📄 License
package/dist/core.d.ts CHANGED
@@ -11,15 +11,30 @@
11
11
  * SHA-256 based hash, returning the first 32 hex chars (128 bits).
12
12
  */
13
13
  export declare function complexHash(str: string): Promise<string>;
14
+ /**
15
+ * Heuristics to detect incognito / privacy mode.
16
+ * Returns a score 0-1 where higher = more likely private browsing.
17
+ */
18
+ export declare function detectPrivacyMode(): Promise<{
19
+ isPrivate: boolean;
20
+ score: number;
21
+ signals: string[];
22
+ }>;
14
23
  /**
15
24
  * Sort object keys recursively for deterministic JSON.stringify output.
16
25
  */
17
26
  export declare function sortObjectKeysRecursively(obj: unknown): unknown;
27
+ /**
28
+ * Signal keys that are known to change in privacy/incognito mode.
29
+ * When privacy mode is detected, these are excluded from the primary hash.
30
+ */
31
+ export declare const UNSTABLE_IN_PRIVACY_KEYS: Set<string>;
18
32
  /**
19
33
  * Extract stable components for hashing.
20
34
  * Matches extractStableComponents() in the script-tag SDK.
35
+ * When privacyMode is true, excludes signals known to be noised in incognito.
21
36
  */
22
- export declare function extractStableComponents(components: Record<string, unknown>): Record<string, unknown>;
37
+ export declare function extractStableComponents(components: Record<string, unknown>, privacyMode?: boolean): Record<string, unknown>;
23
38
  export interface CoreComponents {
24
39
  basic?: Record<string, unknown>;
25
40
  canvas?: Record<string, unknown>;
@@ -36,5 +51,10 @@ export declare function collectCoreComponents(): Promise<CoreComponents>;
36
51
  /**
37
52
  * Generate a visitor ID from collected components.
38
53
  * Uses the same extraction → sort → hash → prefix pipeline as the script-tag SDK.
54
+ *
55
+ * When privacy mode is detected, canvas/WebGL are excluded from the primary hash
56
+ * to ensure the visitor ID remains stable across normal and incognito sessions.
57
+ * A secondary hash incorporating all signals is appended for disambiguation when
58
+ * the environment is NOT private.
39
59
  */
40
60
  export declare function generateCoreVisitorId(components: Record<string, unknown>, isFree: boolean): Promise<string>;
package/dist/index.d.ts CHANGED
@@ -55,6 +55,19 @@ export declare class TraceTail {
55
55
  private sendToServer;
56
56
  static getVersion(): string;
57
57
  static validateApiKey(apiKey: string): boolean;
58
+ /**
59
+ * Calculate confidence based on actual signal entropy and environment stability.
60
+ *
61
+ * Entropy weights reflect how unique each signal type is across browsers:
62
+ * - Canvas: very high entropy (~10+ bits), but unstable in privacy mode
63
+ * - WebGL renderer: high entropy (~8 bits)
64
+ * - Fonts: medium-high entropy (~6 bits)
65
+ * - Audio: medium entropy (~4 bits)
66
+ * - Basic (UA, screen, timezone, etc.): low-medium individually (~2-3 bits each)
67
+ *
68
+ * Typical result: 0.85-0.95 for most browsers. Lower for privacy/incognito.
69
+ */
70
+ private calculateConfidenceAsync;
58
71
  private calculateConfidence;
59
72
  private isDNTEnabled;
60
73
  private log;
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- "use strict";function e(e){let t=0;const r=e.length;if(0===r)return"0";for(let n=0;n<r;n++)t=(t<<5)-t+e.charCodeAt(n),t|=0;return Math.abs(t).toString(36)}function t(e){if(null===e||"object"!=typeof e)return e;if(Array.isArray(e))return e.map(t);const r={},n=Object.keys(e).sort();for(const o of n)r[o]=t(e[o]);return r}Object.defineProperty(exports,"__esModule",{value:!0});const r=new Set(["network","processingTime","timestamp","realUserDetection","storage","battery","webrtc","performance","timing","memoryProfile"]);function n(e){if(!e||"object"!=typeof e)return!1;if(!(e.error||e.unavailable||e.disabled))return!1;const t=Object.keys(e),r=new Set(["error","unavailable","disabled","id","timestamp"]);return 0===t.filter(e=>!r.has(e)).length}const o=["Arial","Arial Black","Arial Narrow","Arial Unicode MS","Calibri","Cambria","Century Gothic","Comic Sans MS","Consolas","Courier","Courier New","Georgia","Helvetica","Impact","Lucida Console","Lucida Grande","Palatino","Tahoma","Times","Times New Roman","Trebuchet MS","Verdana","Monaco","Menlo"];async function i(){const t={};try{t.basic={userAgent:navigator.userAgent,language:navigator.language,platform:navigator.platform,cookieEnabled:navigator.cookieEnabled,screen:{width:screen.width,height:screen.height,colorDepth:screen.colorDepth,pixelRatio:window.devicePixelRatio||1},timezone:Intl.DateTimeFormat().resolvedOptions().timeZone,timezoneOffset:(new Date).getTimezoneOffset(),hardwareConcurrency:navigator.hardwareConcurrency,maxTouchPoints:navigator.maxTouchPoints,deviceMemory:navigator.deviceMemory}}catch(e){}try{t.canvas=await async function(){try{const t=document.createElement("canvas"),r=t.getContext("2d");if(!r)return{unavailable:!0};t.width=256,t.height=256,r.fillStyle="#f60",r.fillRect(0,0,256,256);const n=r.createLinearGradient(0,0,256,256);n.addColorStop(0,"#ff6b6b"),n.addColorStop(.5,"#4ecdc4"),n.addColorStop(1,"#1a1a2e"),r.fillStyle=n,r.fillRect(0,0,128,128);const o=r.createRadialGradient(192,64,10,192,64,60);o.addColorStop(0,"#e74c3c"),o.addColorStop(1,"rgba(46,204,113,0.4)"),r.fillStyle=o,r.fillRect(128,0,128,128),r.fillStyle="#069",r.font="14px Arial",r.fillText("TraceTail",4,150),r.font="italic 12px Georgia",r.fillText("Canvas FP",4,170),r.font="20px serif",r.fillText("😀🌍🚀❤️",4,200),r.beginPath(),r.moveTo(130,140),r.bezierCurveTo(150,200,200,160,240,210),r.strokeStyle="#9b59b6",r.lineWidth=2,r.stroke(),r.beginPath(),r.arc(200,200,30,0,2*Math.PI),r.fillStyle="rgba(52,152,219,0.6)",r.fill(),r.shadowColor="rgba(0,0,0,0.5)",r.shadowBlur=6,r.shadowOffsetX=3,r.shadowOffsetY=3,r.fillStyle="#2ecc71",r.fillRect(60,200,50,40),r.shadowColor="transparent",r.globalCompositeOperation="multiply",r.fillStyle="#e67e22",r.fillRect(80,180,60,60),r.globalCompositeOperation="screen",r.fillStyle="#3498db",r.fillRect(100,190,60,60),r.globalCompositeOperation="source-over",r.font="11px Arial",r.fillStyle="#000",r.fillText("Subpx",10.5,245.5);const i=[r.getImageData(0,0,32,32),r.getImageData(128,0,32,32),r.getImageData(0,128,32,32),r.getImageData(180,180,32,32)].map(e=>Array.from(e.data.slice(0,64)).reduce((e,t)=>e+t,0));return{hash:e(i.join(",")),samples:i}}catch(e){return{error:e instanceof Error?e.message:String(e)}}}()}catch(e){t.canvas={error:"collection failed"}}try{t.webgl=function(){try{const e=document.createElement("canvas"),t=e.getContext("webgl")||e.getContext("experimental-webgl");if(!t)return{unavailable:!0};const r=t.getExtension("WEBGL_debug_renderer_info"),n=r?t.getParameter(r.UNMASKED_VENDOR_WEBGL):t.getParameter(t.VENDOR),o=r?t.getParameter(r.UNMASKED_RENDERER_WEBGL):t.getParameter(t.RENDERER);return{vendor:t.getParameter(t.VENDOR),renderer:t.getParameter(t.RENDERER),version:t.getParameter(t.VERSION),unmaskedVendor:n,unmaskedRenderer:o}}catch(e){return{error:e instanceof Error?e.message:String(e)}}}()}catch(e){t.webgl={error:"collection failed"}}try{t.fonts=function(){try{const t=document.createElement("canvas"),r=t.getContext("2d");if(!r)return{unavailable:!0};t.width=200,t.height=50;const n=[],i=["mmmmmmmmmmlli","ABCDEFGHIJKLMNOPQRSTUVWXYZ","1234567890"];r.font="14px monospace";const a=i.map(e=>r.measureText(e).width);for(const e of o){r.font=`14px "${e}", monospace`;const t=i.map(e=>r.measureText(e).width);t.some((e,t)=>{var r;return Math.abs(e-(null!==(r=a[t])&&void 0!==r?r:0))>.1})&&n.push(e)}return{detected:n,count:n.length,hash:e(n.join(","))}}catch(e){return{error:e instanceof Error?e.message:String(e)}}}()}catch(e){t.fonts={error:"collection failed"}}try{t.audio=function(){try{const e=window.AudioContext||window.webkitAudioContext;if(!e)return{unavailable:!0};const t=new e,r={sampleRate:t.sampleRate,maxChannelCount:t.destination.maxChannelCount,baseLatency:t.baseLatency};return t.close(),r}catch(e){return{error:e instanceof Error?e.message:String(e)}}}()}catch(e){t.audio={error:"collection failed"}}return t}async function a(e,o){const i=function(e){const t={};for(const[o,i]of Object.entries(e))if(!r.has(o))if(i&&"object"==typeof i&&!Array.isArray(i)){const e=i;if(n(e))continue;if(0===Object.keys(e).length)continue;t[o]=i}else null!=i&&(t[o]=i);return t}(e),a=t(i),s=JSON.stringify(a);return"fp2_"+(await async function(e){if(!e.length)return"0000000000000000";const t=(new TextEncoder).encode(e),r=await crypto.subtle.digest("SHA-256",t);return Array.from(new Uint8Array(r)).map(e=>e.toString(16).padStart(2,"0")).join("").substring(0,32)}(s)).substring(0,16)}class s{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 r=!0===(null==e?void 0:e.verbose),n=r?"fingerprint_verbose":"fingerprint_basic";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 o=await i(),s=Math.round(performance.now()-t);if(this.options.apiKey&&this.options.endpoint)try{const e={...await this.sendToServer(o,r),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 c=await a(o),l={visitorId:c,confidence:this.calculateConfidence(o),processingTime:s,...r&&{components:o}};return this.options.caching&&this.cache.set(n,l),this.log("Client-side fingerprint generated",l),l}catch(e){throw this.log("Fingerprint generation failed",e),e}}async sendToServer(e,t){const r=new AbortController,n=setTimeout(()=>r.abort(),this.options.timeout);try{const o=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:r.signal});if(clearTimeout(n),!o.ok){if(401===o.status)throw new Error("Invalid API key");throw new Error(`Server returned ${o.status}`)}const i=await o.json(),a={visitorId:i.visitorId,confidence:i.confidence,processingTime:i.processingTime||0};if(t){if(!i.components)throw new Error("Server did not return components in verbose mode");a.components=i.components}return a}catch(e){throw clearTimeout(n),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)}calculateConfidence(e){let t=1;e.canvas||(t-=.03),e.webgl||(t-=.03),e.audio||(t-=.02),e.fonts||(t-=.02),e.webRTC||(t-=.01);const r=Object.values(e).filter(e=>null!=e).length;return r<3?t-=.1:r<5&&(t-=.03),Math.min(.999,Math.max(.5,t))}isDNTEnabled(){return"1"===navigator.doNotTrack||"1"===window.doNotTrack||"1"===navigator.msDoNotTrack}log(e,t){this.options.debug&&console.log(`[TraceTail] ${e}`,t)}}exports.TraceTail=s,exports.default=s;
1
+ "use strict";function e(e){let t=0;const r=e.length;if(0===r)return"0";for(let n=0;n<r;n++)t=(t<<5)-t+e.charCodeAt(n),t|=0;return Math.abs(t).toString(36)}async function t(e){if(!e.length)return"0000000000000000";const t=(new TextEncoder).encode(e),r=await crypto.subtle.digest("SHA-256",t);return Array.from(new Uint8Array(r)).map(e=>e.toString(16).padStart(2,"0")).join("").substring(0,32)}async function r(){const e=[];let t=0;try{if(navigator.storage&&navigator.storage.estimate){const r=await navigator.storage.estimate();(r.quota||0)/1073741824<.5&&(t+=.4,e.push("low_storage_quota"))}}catch(r){t+=.15,e.push("storage_api_error")}try{!!!window.webkitRequestFileSystem&&/Chrome/.test(navigator.userAgent)&&(t+=.2,e.push("no_filesystem_api"))}catch(r){t+=.1,e.push("filesystem_check_error")}try{/Safari/.test(navigator.userAgent)&&!/Chrome/.test(navigator.userAgent)&&(navigator.serviceWorker||(t+=.3,e.push("no_service_worker_safari")))}catch(e){}try{navigator.brave&&(t+=.15,e.push("brave_browser"))}catch(e){}try{/Firefox/.test(navigator.userAgent)&&screen.width%200==0&&screen.height%100==0&&(t+=.2,e.push("firefox_rfp_screen"))}catch(e){}return{isPrivate:t>=.35,score:Math.min(1,t),signals:e}}function n(e){if(null===e||"object"!=typeof e)return e;if(Array.isArray(e))return e.map(n);const t={},r=Object.keys(e).sort();for(const a of r)t[a]=n(e[a]);return t}Object.defineProperty(exports,"__esModule",{value:!0});const a=new Set(["network","processingTime","timestamp","realUserDetection","storage","battery","webrtc","performance","timing","memoryProfile","advancedAudio"]);function o(e){if(!e||"object"!=typeof e)return!1;if(!(e.error||e.unavailable||e.disabled))return!1;const t=Object.keys(e),r=new Set(["error","unavailable","disabled","id","timestamp"]);return 0===t.filter(e=>!r.has(e)).length}const i=new Set(["canvas","webgl"]),s=new Set(["canvas","webgl","audio","fonts"]),c={unavailable:!0};function l(e,t=!1){const r={};for(const[n,l]of Object.entries(e))if(!(a.has(n)||t&&i.has(n)))if(l&&"object"==typeof l&&!Array.isArray(l)){const e=l;if(o(e)||0===Object.keys(e).length){s.has(n)&&(r[n]=c);continue}r[n]=l}else null!=l?r[n]=l:s.has(n)&&(r[n]=c);return r}const u=["Arial","Arial Black","Arial Narrow","Arial Unicode MS","Calibri","Cambria","Century Gothic","Comic Sans MS","Consolas","Courier","Courier New","Georgia","Helvetica","Impact","Lucida Console","Lucida Grande","Palatino","Tahoma","Times","Times New Roman","Trebuchet MS","Verdana","Monaco","Menlo"];async function f(){const t={};try{t.basic={userAgent:navigator.userAgent,language:navigator.language,platform:navigator.platform,cookieEnabled:navigator.cookieEnabled,screen:{width:screen.width,height:screen.height,colorDepth:screen.colorDepth,pixelRatio:window.devicePixelRatio||1},timezone:Intl.DateTimeFormat().resolvedOptions().timeZone,timezoneOffset:(new Date).getTimezoneOffset(),hardwareConcurrency:navigator.hardwareConcurrency,maxTouchPoints:navigator.maxTouchPoints,deviceMemory:navigator.deviceMemory}}catch(e){}try{t.canvas=await async function(){try{const t=document.createElement("canvas"),r=t.getContext("2d");if(!r)return{unavailable:!0};t.width=256,t.height=256,r.fillStyle="#f60",r.fillRect(0,0,256,256);const n=r.createLinearGradient(0,0,256,256);n.addColorStop(0,"#ff6b6b"),n.addColorStop(.5,"#4ecdc4"),n.addColorStop(1,"#1a1a2e"),r.fillStyle=n,r.fillRect(0,0,128,128);const a=r.createRadialGradient(192,64,10,192,64,60);a.addColorStop(0,"#e74c3c"),a.addColorStop(1,"rgba(46,204,113,0.4)"),r.fillStyle=a,r.fillRect(128,0,128,128),r.fillStyle="#069",r.font="14px Arial",r.fillText("TraceTail",4,150),r.font="italic 12px Georgia",r.fillText("Canvas FP",4,170),r.font="20px serif",r.fillText("😀🌍🚀❤️",4,200),r.beginPath(),r.moveTo(130,140),r.bezierCurveTo(150,200,200,160,240,210),r.strokeStyle="#9b59b6",r.lineWidth=2,r.stroke(),r.beginPath(),r.arc(200,200,30,0,2*Math.PI),r.fillStyle="rgba(52,152,219,0.6)",r.fill(),r.shadowColor="rgba(0,0,0,0.5)",r.shadowBlur=6,r.shadowOffsetX=3,r.shadowOffsetY=3,r.fillStyle="#2ecc71",r.fillRect(60,200,50,40),r.shadowColor="transparent",r.globalCompositeOperation="multiply",r.fillStyle="#e67e22",r.fillRect(80,180,60,60),r.globalCompositeOperation="screen",r.fillStyle="#3498db",r.fillRect(100,190,60,60),r.globalCompositeOperation="source-over",r.font="11px Arial",r.fillStyle="#000",r.fillText("Subpx",10.5,245.5);const o=[r.getImageData(0,0,32,32),r.getImageData(128,0,32,32),r.getImageData(0,128,32,32),r.getImageData(180,180,32,32)].map(e=>Array.from(e.data.slice(0,64)).reduce((e,t)=>e+t,0));return{hash:e(o.join(",")),samples:o}}catch(e){return{error:e instanceof Error?e.message:String(e)}}}()}catch(e){t.canvas={error:"collection failed"}}try{t.webgl=function(){try{const e=document.createElement("canvas"),t=e.getContext("webgl")||e.getContext("experimental-webgl");if(!t)return{unavailable:!0};const r=t.getExtension("WEBGL_debug_renderer_info"),n=r?t.getParameter(r.UNMASKED_VENDOR_WEBGL):t.getParameter(t.VENDOR),a=r?t.getParameter(r.UNMASKED_RENDERER_WEBGL):t.getParameter(t.RENDERER);return{vendor:t.getParameter(t.VENDOR),renderer:t.getParameter(t.RENDERER),version:t.getParameter(t.VERSION),unmaskedVendor:n,unmaskedRenderer:a}}catch(e){return{error:e instanceof Error?e.message:String(e)}}}()}catch(e){t.webgl={error:"collection failed"}}try{t.fonts=function(){try{const t=document.createElement("canvas"),r=t.getContext("2d");if(!r)return{unavailable:!0};t.width=200,t.height=50;const n=[],a=["mmmmmmmmmmlli","ABCDEFGHIJKLMNOPQRSTUVWXYZ","1234567890"];r.font="14px monospace";const o=a.map(e=>r.measureText(e).width);for(const e of u){r.font=`14px "${e}", monospace`;const t=a.map(e=>r.measureText(e).width);t.some((e,t)=>{var r;return Math.abs(e-(null!==(r=o[t])&&void 0!==r?r:0))>.1})&&n.push(e)}return{detected:n,count:n.length,hash:e(n.join(","))}}catch(e){return{error:e instanceof Error?e.message:String(e)}}}()}catch(e){t.fonts={error:"collection failed"}}try{t.audio=function(){try{const e=window.AudioContext||window.webkitAudioContext;if(!e)return{unavailable:!0};const t=new e,r={sampleRate:t.sampleRate,maxChannelCount:t.destination.maxChannelCount,baseLatency:t.baseLatency};return t.close(),r}catch(e){return{error:e instanceof Error?e.message:String(e)}}}()}catch(e){t.audio={error:"collection failed"}}return t}class h{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 a=performance.now();try{if(this.options.respectDNT&&this.isDNTEnabled())throw new Error("TraceTail: Do Not Track is enabled");const o=!0===(null==e?void 0:e.verbose),i=o?"fingerprint_verbose":"fingerprint_basic";if(this.options.caching&&this.cache.has(i)){const e=this.cache.get(i);if(e)return this.log("Using cached fingerprint",e),e}const s=await f(),c=Math.round(performance.now()-a);if(this.options.apiKey&&this.options.endpoint)try{const e={...await this.sendToServer(s,o),processingTime:Math.round(performance.now()-a)};return this.options.caching&&this.cache.set(i,e),this.log("Server-enhanced fingerprint generated",e),e}catch(e){this.log("Server processing failed, falling back to client-side",e)}const u=await async function(e){const a=await r(),o=n(l(e,!0)),i=JSON.stringify(o),s=await t(i);if(a.isPrivate)return"fp2_"+s.substring(0,16);const c=n(l(e,!1)),u=JSON.stringify(c),f=await t(u);return"fp2_"+(s.substring(0,12)+f.substring(0,4))}(s),h={visitorId:u,confidence:await this.calculateConfidenceAsync(s),processingTime:c,...o&&{components:s}};return this.options.caching&&this.cache.set(i,h),this.log("Client-side fingerprint generated",h),h}catch(e){throw this.log("Fingerprint generation failed",e),e}}async sendToServer(e,t){const r=new AbortController,n=setTimeout(()=>r.abort(),this.options.timeout);try{const a=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:r.signal});if(clearTimeout(n),!a.ok){if(401===a.status)throw new Error("Invalid API key");throw new Error(`Server returned ${a.status}`)}const o=await a.json(),i={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");i.components=o.components}return i}catch(e){throw clearTimeout(n),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 calculateConfidenceAsync(e){const t={canvas:.15,webgl:.12,fonts:.1,audio:.08,basic:.05};let n=.5;const a=e=>{if(!e)return!1;if("object"==typeof e){const t=e;return!t.error&&!t.unavailable}return!0};for(const[r,o]of Object.entries(t))a(e[r])&&(n+=o);if(e.basic&&"object"==typeof e.basic){const t=Object.keys(e.basic).filter(t=>void 0!==e.basic[t]);n+=Math.min(.1,.012*t.length)}const o=Object.keys(e).filter(t=>a(e[t]));o.length>=5?n+=.05:o.length>=3&&(n+=.02);try{const e=await r();e.isPrivate&&(n-=.08,n-=.02*e.signals.length)}catch(e){n-=.03}return Math.min(.99,Math.max(.4,Math.round(1e3*n)/1e3))}calculateConfidence(e){const t={canvas:.15,webgl:.12,fonts:.1,audio:.08,basic:.05};let r=.5;const n=e=>{if(!e)return!1;if("object"==typeof e){const t=e;return!t.error&&!t.unavailable}return!0};for(const[a,o]of Object.entries(t))n(e[a])&&(r+=o);if(e.basic&&"object"==typeof e.basic){const t=Object.keys(e.basic).filter(t=>void 0!==e.basic[t]);r+=Math.min(.1,.012*t.length)}const a=Object.keys(e).filter(t=>n(e[t]));return a.length>=5?r+=.05:a.length>=3&&(r+=.02),Math.min(.99,Math.max(.4,Math.round(1e3*r)/1e3))}isDNTEnabled(){return"1"===navigator.doNotTrack||"1"===window.doNotTrack||"1"===navigator.msDoNotTrack}log(e,t){this.options.debug&&console.log(`[TraceTail] ${e}`,t)}}exports.TraceTail=h,exports.default=h;
package/dist/index.mjs CHANGED
@@ -1 +1 @@
1
- function e(e){let t=0;const r=e.length;if(0===r)return"0";for(let n=0;n<r;n++)t=(t<<5)-t+e.charCodeAt(n),t|=0;return Math.abs(t).toString(36)}function t(e){if(null===e||"object"!=typeof e)return e;if(Array.isArray(e))return e.map(t);const r={},n=Object.keys(e).sort();for(const o of n)r[o]=t(e[o]);return r}const r=new Set(["network","processingTime","timestamp","realUserDetection","storage","battery","webrtc","performance","timing","memoryProfile"]);function n(e){if(!e||"object"!=typeof e)return!1;if(!(e.error||e.unavailable||e.disabled))return!1;const t=Object.keys(e),r=new Set(["error","unavailable","disabled","id","timestamp"]);return 0===t.filter(e=>!r.has(e)).length}const o=["Arial","Arial Black","Arial Narrow","Arial Unicode MS","Calibri","Cambria","Century Gothic","Comic Sans MS","Consolas","Courier","Courier New","Georgia","Helvetica","Impact","Lucida Console","Lucida Grande","Palatino","Tahoma","Times","Times New Roman","Trebuchet MS","Verdana","Monaco","Menlo"];async function a(){const t={};try{t.basic={userAgent:navigator.userAgent,language:navigator.language,platform:navigator.platform,cookieEnabled:navigator.cookieEnabled,screen:{width:screen.width,height:screen.height,colorDepth:screen.colorDepth,pixelRatio:window.devicePixelRatio||1},timezone:Intl.DateTimeFormat().resolvedOptions().timeZone,timezoneOffset:(new Date).getTimezoneOffset(),hardwareConcurrency:navigator.hardwareConcurrency,maxTouchPoints:navigator.maxTouchPoints,deviceMemory:navigator.deviceMemory}}catch(e){}try{t.canvas=await async function(){try{const t=document.createElement("canvas"),r=t.getContext("2d");if(!r)return{unavailable:!0};t.width=256,t.height=256,r.fillStyle="#f60",r.fillRect(0,0,256,256);const n=r.createLinearGradient(0,0,256,256);n.addColorStop(0,"#ff6b6b"),n.addColorStop(.5,"#4ecdc4"),n.addColorStop(1,"#1a1a2e"),r.fillStyle=n,r.fillRect(0,0,128,128);const o=r.createRadialGradient(192,64,10,192,64,60);o.addColorStop(0,"#e74c3c"),o.addColorStop(1,"rgba(46,204,113,0.4)"),r.fillStyle=o,r.fillRect(128,0,128,128),r.fillStyle="#069",r.font="14px Arial",r.fillText("TraceTail",4,150),r.font="italic 12px Georgia",r.fillText("Canvas FP",4,170),r.font="20px serif",r.fillText("😀🌍🚀❤️",4,200),r.beginPath(),r.moveTo(130,140),r.bezierCurveTo(150,200,200,160,240,210),r.strokeStyle="#9b59b6",r.lineWidth=2,r.stroke(),r.beginPath(),r.arc(200,200,30,0,2*Math.PI),r.fillStyle="rgba(52,152,219,0.6)",r.fill(),r.shadowColor="rgba(0,0,0,0.5)",r.shadowBlur=6,r.shadowOffsetX=3,r.shadowOffsetY=3,r.fillStyle="#2ecc71",r.fillRect(60,200,50,40),r.shadowColor="transparent",r.globalCompositeOperation="multiply",r.fillStyle="#e67e22",r.fillRect(80,180,60,60),r.globalCompositeOperation="screen",r.fillStyle="#3498db",r.fillRect(100,190,60,60),r.globalCompositeOperation="source-over",r.font="11px Arial",r.fillStyle="#000",r.fillText("Subpx",10.5,245.5);const a=[r.getImageData(0,0,32,32),r.getImageData(128,0,32,32),r.getImageData(0,128,32,32),r.getImageData(180,180,32,32)].map(e=>Array.from(e.data.slice(0,64)).reduce((e,t)=>e+t,0));return{hash:e(a.join(",")),samples:a}}catch(e){return{error:e instanceof Error?e.message:String(e)}}}()}catch(e){t.canvas={error:"collection failed"}}try{t.webgl=function(){try{const e=document.createElement("canvas"),t=e.getContext("webgl")||e.getContext("experimental-webgl");if(!t)return{unavailable:!0};const r=t.getExtension("WEBGL_debug_renderer_info"),n=r?t.getParameter(r.UNMASKED_VENDOR_WEBGL):t.getParameter(t.VENDOR),o=r?t.getParameter(r.UNMASKED_RENDERER_WEBGL):t.getParameter(t.RENDERER);return{vendor:t.getParameter(t.VENDOR),renderer:t.getParameter(t.RENDERER),version:t.getParameter(t.VERSION),unmaskedVendor:n,unmaskedRenderer:o}}catch(e){return{error:e instanceof Error?e.message:String(e)}}}()}catch(e){t.webgl={error:"collection failed"}}try{t.fonts=function(){try{const t=document.createElement("canvas"),r=t.getContext("2d");if(!r)return{unavailable:!0};t.width=200,t.height=50;const n=[],a=["mmmmmmmmmmlli","ABCDEFGHIJKLMNOPQRSTUVWXYZ","1234567890"];r.font="14px monospace";const i=a.map(e=>r.measureText(e).width);for(const e of o){r.font=`14px "${e}", monospace`;const t=a.map(e=>r.measureText(e).width);t.some((e,t)=>{var r;return Math.abs(e-(null!==(r=i[t])&&void 0!==r?r:0))>.1})&&n.push(e)}return{detected:n,count:n.length,hash:e(n.join(","))}}catch(e){return{error:e instanceof Error?e.message:String(e)}}}()}catch(e){t.fonts={error:"collection failed"}}try{t.audio=function(){try{const e=window.AudioContext||window.webkitAudioContext;if(!e)return{unavailable:!0};const t=new e,r={sampleRate:t.sampleRate,maxChannelCount:t.destination.maxChannelCount,baseLatency:t.baseLatency};return t.close(),r}catch(e){return{error:e instanceof Error?e.message:String(e)}}}()}catch(e){t.audio={error:"collection failed"}}return t}async function i(e,o){const a=function(e){const t={};for(const[o,a]of Object.entries(e))if(!r.has(o))if(a&&"object"==typeof a&&!Array.isArray(a)){const e=a;if(n(e))continue;if(0===Object.keys(e).length)continue;t[o]=a}else null!=a&&(t[o]=a);return t}(e),i=t(a),s=JSON.stringify(i);return"fp2_"+(await async function(e){if(!e.length)return"0000000000000000";const t=(new TextEncoder).encode(e),r=await crypto.subtle.digest("SHA-256",t);return Array.from(new Uint8Array(r)).map(e=>e.toString(16).padStart(2,"0")).join("").substring(0,32)}(s)).substring(0,16)}class s{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 r=!0===(null==e?void 0:e.verbose),n=r?"fingerprint_verbose":"fingerprint_basic";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 o=await a(),s=Math.round(performance.now()-t);if(this.options.apiKey&&this.options.endpoint)try{const e={...await this.sendToServer(o,r),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 c=await i(o),l={visitorId:c,confidence:this.calculateConfidence(o),processingTime:s,...r&&{components:o}};return this.options.caching&&this.cache.set(n,l),this.log("Client-side fingerprint generated",l),l}catch(e){throw this.log("Fingerprint generation failed",e),e}}async sendToServer(e,t){const r=new AbortController,n=setTimeout(()=>r.abort(),this.options.timeout);try{const o=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:r.signal});if(clearTimeout(n),!o.ok){if(401===o.status)throw new Error("Invalid API key");throw new Error(`Server returned ${o.status}`)}const a=await o.json(),i={visitorId:a.visitorId,confidence:a.confidence,processingTime:a.processingTime||0};if(t){if(!a.components)throw new Error("Server did not return components in verbose mode");i.components=a.components}return i}catch(e){throw clearTimeout(n),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)}calculateConfidence(e){let t=1;e.canvas||(t-=.03),e.webgl||(t-=.03),e.audio||(t-=.02),e.fonts||(t-=.02),e.webRTC||(t-=.01);const r=Object.values(e).filter(e=>null!=e).length;return r<3?t-=.1:r<5&&(t-=.03),Math.min(.999,Math.max(.5,t))}isDNTEnabled(){return"1"===navigator.doNotTrack||"1"===window.doNotTrack||"1"===navigator.msDoNotTrack}log(e,t){this.options.debug&&console.log(`[TraceTail] ${e}`,t)}}export{s as TraceTail,s as default};
1
+ function e(e){let t=0;const r=e.length;if(0===r)return"0";for(let n=0;n<r;n++)t=(t<<5)-t+e.charCodeAt(n),t|=0;return Math.abs(t).toString(36)}async function t(e){if(!e.length)return"0000000000000000";const t=(new TextEncoder).encode(e),r=await crypto.subtle.digest("SHA-256",t);return Array.from(new Uint8Array(r)).map(e=>e.toString(16).padStart(2,"0")).join("").substring(0,32)}async function r(){const e=[];let t=0;try{if(navigator.storage&&navigator.storage.estimate){const r=await navigator.storage.estimate();(r.quota||0)/1073741824<.5&&(t+=.4,e.push("low_storage_quota"))}}catch(r){t+=.15,e.push("storage_api_error")}try{!!!window.webkitRequestFileSystem&&/Chrome/.test(navigator.userAgent)&&(t+=.2,e.push("no_filesystem_api"))}catch(r){t+=.1,e.push("filesystem_check_error")}try{/Safari/.test(navigator.userAgent)&&!/Chrome/.test(navigator.userAgent)&&(navigator.serviceWorker||(t+=.3,e.push("no_service_worker_safari")))}catch(e){}try{navigator.brave&&(t+=.15,e.push("brave_browser"))}catch(e){}try{/Firefox/.test(navigator.userAgent)&&screen.width%200==0&&screen.height%100==0&&(t+=.2,e.push("firefox_rfp_screen"))}catch(e){}return{isPrivate:t>=.35,score:Math.min(1,t),signals:e}}function n(e){if(null===e||"object"!=typeof e)return e;if(Array.isArray(e))return e.map(n);const t={},r=Object.keys(e).sort();for(const a of r)t[a]=n(e[a]);return t}const a=new Set(["network","processingTime","timestamp","realUserDetection","storage","battery","webrtc","performance","timing","memoryProfile","advancedAudio"]);function o(e){if(!e||"object"!=typeof e)return!1;if(!(e.error||e.unavailable||e.disabled))return!1;const t=Object.keys(e),r=new Set(["error","unavailable","disabled","id","timestamp"]);return 0===t.filter(e=>!r.has(e)).length}const i=new Set(["canvas","webgl"]),s=new Set(["canvas","webgl","audio","fonts"]),c={unavailable:!0};function l(e,t=!1){const r={};for(const[n,l]of Object.entries(e))if(!(a.has(n)||t&&i.has(n)))if(l&&"object"==typeof l&&!Array.isArray(l)){const e=l;if(o(e)||0===Object.keys(e).length){s.has(n)&&(r[n]=c);continue}r[n]=l}else null!=l?r[n]=l:s.has(n)&&(r[n]=c);return r}const u=["Arial","Arial Black","Arial Narrow","Arial Unicode MS","Calibri","Cambria","Century Gothic","Comic Sans MS","Consolas","Courier","Courier New","Georgia","Helvetica","Impact","Lucida Console","Lucida Grande","Palatino","Tahoma","Times","Times New Roman","Trebuchet MS","Verdana","Monaco","Menlo"];async function f(){const t={};try{t.basic={userAgent:navigator.userAgent,language:navigator.language,platform:navigator.platform,cookieEnabled:navigator.cookieEnabled,screen:{width:screen.width,height:screen.height,colorDepth:screen.colorDepth,pixelRatio:window.devicePixelRatio||1},timezone:Intl.DateTimeFormat().resolvedOptions().timeZone,timezoneOffset:(new Date).getTimezoneOffset(),hardwareConcurrency:navigator.hardwareConcurrency,maxTouchPoints:navigator.maxTouchPoints,deviceMemory:navigator.deviceMemory}}catch(e){}try{t.canvas=await async function(){try{const t=document.createElement("canvas"),r=t.getContext("2d");if(!r)return{unavailable:!0};t.width=256,t.height=256,r.fillStyle="#f60",r.fillRect(0,0,256,256);const n=r.createLinearGradient(0,0,256,256);n.addColorStop(0,"#ff6b6b"),n.addColorStop(.5,"#4ecdc4"),n.addColorStop(1,"#1a1a2e"),r.fillStyle=n,r.fillRect(0,0,128,128);const a=r.createRadialGradient(192,64,10,192,64,60);a.addColorStop(0,"#e74c3c"),a.addColorStop(1,"rgba(46,204,113,0.4)"),r.fillStyle=a,r.fillRect(128,0,128,128),r.fillStyle="#069",r.font="14px Arial",r.fillText("TraceTail",4,150),r.font="italic 12px Georgia",r.fillText("Canvas FP",4,170),r.font="20px serif",r.fillText("😀🌍🚀❤️",4,200),r.beginPath(),r.moveTo(130,140),r.bezierCurveTo(150,200,200,160,240,210),r.strokeStyle="#9b59b6",r.lineWidth=2,r.stroke(),r.beginPath(),r.arc(200,200,30,0,2*Math.PI),r.fillStyle="rgba(52,152,219,0.6)",r.fill(),r.shadowColor="rgba(0,0,0,0.5)",r.shadowBlur=6,r.shadowOffsetX=3,r.shadowOffsetY=3,r.fillStyle="#2ecc71",r.fillRect(60,200,50,40),r.shadowColor="transparent",r.globalCompositeOperation="multiply",r.fillStyle="#e67e22",r.fillRect(80,180,60,60),r.globalCompositeOperation="screen",r.fillStyle="#3498db",r.fillRect(100,190,60,60),r.globalCompositeOperation="source-over",r.font="11px Arial",r.fillStyle="#000",r.fillText("Subpx",10.5,245.5);const o=[r.getImageData(0,0,32,32),r.getImageData(128,0,32,32),r.getImageData(0,128,32,32),r.getImageData(180,180,32,32)].map(e=>Array.from(e.data.slice(0,64)).reduce((e,t)=>e+t,0));return{hash:e(o.join(",")),samples:o}}catch(e){return{error:e instanceof Error?e.message:String(e)}}}()}catch(e){t.canvas={error:"collection failed"}}try{t.webgl=function(){try{const e=document.createElement("canvas"),t=e.getContext("webgl")||e.getContext("experimental-webgl");if(!t)return{unavailable:!0};const r=t.getExtension("WEBGL_debug_renderer_info"),n=r?t.getParameter(r.UNMASKED_VENDOR_WEBGL):t.getParameter(t.VENDOR),a=r?t.getParameter(r.UNMASKED_RENDERER_WEBGL):t.getParameter(t.RENDERER);return{vendor:t.getParameter(t.VENDOR),renderer:t.getParameter(t.RENDERER),version:t.getParameter(t.VERSION),unmaskedVendor:n,unmaskedRenderer:a}}catch(e){return{error:e instanceof Error?e.message:String(e)}}}()}catch(e){t.webgl={error:"collection failed"}}try{t.fonts=function(){try{const t=document.createElement("canvas"),r=t.getContext("2d");if(!r)return{unavailable:!0};t.width=200,t.height=50;const n=[],a=["mmmmmmmmmmlli","ABCDEFGHIJKLMNOPQRSTUVWXYZ","1234567890"];r.font="14px monospace";const o=a.map(e=>r.measureText(e).width);for(const e of u){r.font=`14px "${e}", monospace`;const t=a.map(e=>r.measureText(e).width);t.some((e,t)=>{var r;return Math.abs(e-(null!==(r=o[t])&&void 0!==r?r:0))>.1})&&n.push(e)}return{detected:n,count:n.length,hash:e(n.join(","))}}catch(e){return{error:e instanceof Error?e.message:String(e)}}}()}catch(e){t.fonts={error:"collection failed"}}try{t.audio=function(){try{const e=window.AudioContext||window.webkitAudioContext;if(!e)return{unavailable:!0};const t=new e,r={sampleRate:t.sampleRate,maxChannelCount:t.destination.maxChannelCount,baseLatency:t.baseLatency};return t.close(),r}catch(e){return{error:e instanceof Error?e.message:String(e)}}}()}catch(e){t.audio={error:"collection failed"}}return t}class h{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 a=performance.now();try{if(this.options.respectDNT&&this.isDNTEnabled())throw new Error("TraceTail: Do Not Track is enabled");const o=!0===(null==e?void 0:e.verbose),i=o?"fingerprint_verbose":"fingerprint_basic";if(this.options.caching&&this.cache.has(i)){const e=this.cache.get(i);if(e)return this.log("Using cached fingerprint",e),e}const s=await f(),c=Math.round(performance.now()-a);if(this.options.apiKey&&this.options.endpoint)try{const e={...await this.sendToServer(s,o),processingTime:Math.round(performance.now()-a)};return this.options.caching&&this.cache.set(i,e),this.log("Server-enhanced fingerprint generated",e),e}catch(e){this.log("Server processing failed, falling back to client-side",e)}const u=await async function(e){const a=await r(),o=n(l(e,!0)),i=JSON.stringify(o),s=await t(i);if(a.isPrivate)return"fp2_"+s.substring(0,16);const c=n(l(e,!1)),u=JSON.stringify(c),f=await t(u);return"fp2_"+(s.substring(0,12)+f.substring(0,4))}(s),h={visitorId:u,confidence:await this.calculateConfidenceAsync(s),processingTime:c,...o&&{components:s}};return this.options.caching&&this.cache.set(i,h),this.log("Client-side fingerprint generated",h),h}catch(e){throw this.log("Fingerprint generation failed",e),e}}async sendToServer(e,t){const r=new AbortController,n=setTimeout(()=>r.abort(),this.options.timeout);try{const a=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:r.signal});if(clearTimeout(n),!a.ok){if(401===a.status)throw new Error("Invalid API key");throw new Error(`Server returned ${a.status}`)}const o=await a.json(),i={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");i.components=o.components}return i}catch(e){throw clearTimeout(n),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 calculateConfidenceAsync(e){const t={canvas:.15,webgl:.12,fonts:.1,audio:.08,basic:.05};let n=.5;const a=e=>{if(!e)return!1;if("object"==typeof e){const t=e;return!t.error&&!t.unavailable}return!0};for(const[r,o]of Object.entries(t))a(e[r])&&(n+=o);if(e.basic&&"object"==typeof e.basic){const t=Object.keys(e.basic).filter(t=>void 0!==e.basic[t]);n+=Math.min(.1,.012*t.length)}const o=Object.keys(e).filter(t=>a(e[t]));o.length>=5?n+=.05:o.length>=3&&(n+=.02);try{const e=await r();e.isPrivate&&(n-=.08,n-=.02*e.signals.length)}catch(e){n-=.03}return Math.min(.99,Math.max(.4,Math.round(1e3*n)/1e3))}calculateConfidence(e){const t={canvas:.15,webgl:.12,fonts:.1,audio:.08,basic:.05};let r=.5;const n=e=>{if(!e)return!1;if("object"==typeof e){const t=e;return!t.error&&!t.unavailable}return!0};for(const[a,o]of Object.entries(t))n(e[a])&&(r+=o);if(e.basic&&"object"==typeof e.basic){const t=Object.keys(e.basic).filter(t=>void 0!==e.basic[t]);r+=Math.min(.1,.012*t.length)}const a=Object.keys(e).filter(t=>n(e[t]));return a.length>=5?r+=.05:a.length>=3&&(r+=.02),Math.min(.99,Math.max(.4,Math.round(1e3*r)/1e3))}isDNTEnabled(){return"1"===navigator.doNotTrack||"1"===window.doNotTrack||"1"===navigator.msDoNotTrack}log(e,t){this.options.debug&&console.log(`[TraceTail] ${e}`,t)}}export{h as TraceTail,h as default};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tracetail/js",
3
- "version": "2.3.11",
3
+ "version": "2.3.12",
4
4
  "description": "TraceTail JavaScript SDK for browser fingerprinting",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -34,6 +34,9 @@
34
34
  ],
35
35
  "author": "TraceTail",
36
36
  "license": "MIT",
37
+ "dependencies": {
38
+ "tslib": "^2.8.1"
39
+ },
37
40
  "devDependencies": {
38
41
  "@rollup/plugin-typescript": "^11.1.6",
39
42
  "rollup": "^4.9.6",