diff --git a/package.json b/package.json index 63deb3e..1388e02 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,7 @@ "jsdom": "^30.1.1", "typescript": "^6.0.3", "typescript-eslint": "^8.70.1", - "vite": "^8.3.0", + "vite": "^8.3.2", "vitest": "^3.0.4" }, "pnpm": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 09ee2fd..182397c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -30,8 +30,8 @@ importers: specifier: ^8.70.1 version: 8.70.1(eslint@10.10.0)(typescript@6.0.3) vite: - specifier: ^8.3.0 - version: 8.3.0(@types/node@26.6.2)(esbuild@0.28.2) + specifier: ^8.3.2 + version: 8.3.2(@types/node@26.6.2)(esbuild@0.28.2) vitest: specifier: ^3.0.4 version: 3.2.7(@types/node@26.6.2)(jsdom@30.1.1)(lightningcss@1.33.0) @@ -378,105 +378,105 @@ packages: os: [linux] libc: [glibc] - '@oxc-project/types@0.149.0': - resolution: {integrity: sha512-Efcc+iF0j3Bf67YjEqIqWXbX5XddXoK/Mw4K1/JuXwRCZ8N16VR7iT23nlCc9XrveFVh/E5Rqs2StT0V8v9LdA==} + '@oxc-project/types@0.152.0': + resolution: {integrity: sha512-oM/5rLBm2tPkg0iBgkH/FOeR3PCDpY19GTgAZjMFM8h9WI9VW7cLgzp6nwtarYKmovavIQZ+Fe/RKX/8C8O/Rw==} '@pkgjs/parseargs@0.11.0': resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} - '@rolldown/binding-android-arm-eabi@1.2.8': - resolution: {integrity: sha512-tN5aztYkKCte4i5SIrrz5yK/HMjEuCqCSCJa418jOV8tZ1cBY3YF2otxB1ktPxzsLA1BeTqwapK0bfjxNvHJVw==} + '@rolldown/binding-android-arm-eabi@1.2.12': + resolution: {integrity: sha512-dB/a1214qKfHMXCpgqR4OZT+jS4kTyEXbQGJPqzobt5EwH5rX080pxE37alt3RzvR1bf1Yz/yGqRfrYAxuPw0A==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [android] - '@rolldown/binding-android-arm64@1.2.8': - resolution: {integrity: sha512-dIYTWl9XprMUiQFoc55KUyk/oS8SKYH3zFl0LTR7RT0Xj4hgSVyuJcroH8JUu8RcpF8fTB6E0aOwCkZoYPcDSQ==} + '@rolldown/binding-android-arm64@1.2.12': + resolution: {integrity: sha512-7KHFgQ5VJxIHcLlrwrc3Xbds7oTNQT7Pgi9gQCJKrd2VGab/UksIOYp6VD8MzCstGxOKMgNamPwUCfxPdP1OHg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [android] - '@rolldown/binding-darwin-arm64@1.2.8': - resolution: {integrity: sha512-PCSDQGXD2IyTEFrcgPyBM8jJuGmrbCMuoIOXdbEGVemruKACXoLQJrb+A45Z0L5t1RQkdfJprAYPkikbh7dzdA==} + '@rolldown/binding-darwin-arm64@1.2.12': + resolution: {integrity: sha512-3YIhqHD96nA5SaYNRBR16HnGv4oavZvXfD/ayHM+oYZ0WD/8lBAtf6zQua4kEyAvpqrluKXl0lnOBoiNby7x9w==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [darwin] - '@rolldown/binding-darwin-x64@1.2.8': - resolution: {integrity: sha512-Uk7lRsGhPFHVX/sAUC6D5H9Ol30dFHd6iquokll2th3LpdJ3F5CzQB+7DHn0Ri2mG+U7k2zXiPHDrwZenXhwSA==} + '@rolldown/binding-darwin-x64@1.2.12': + resolution: {integrity: sha512-UuuJ35MFw4gmFOrE9pEqIV+K3syIKveph+Qc1/ljHZVdoDW4pz/JHR/eMVom+TZGl/5OOvGJOWaOCVt3ZfqhxA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [darwin] - '@rolldown/binding-freebsd-x64@1.2.8': - resolution: {integrity: sha512-DjszaTEVogPqA5bYzsEeqDCQxbcp2fexQwKcRspYji2yzR68fCf+e4fx6kBSRDwX5/brZaHw/hWS9+A/+/w9sQ==} + '@rolldown/binding-freebsd-x64@1.2.12': + resolution: {integrity: sha512-uMvssit0a4W+/7D8CbHUvG719mH3R2jwXAlh/XcPvuHTE0g++LymF88DCGNX0HM2rBOn0xrzgXktIB6fLSJBTQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [freebsd] - '@rolldown/binding-linux-arm-gnueabihf@1.2.8': - resolution: {integrity: sha512-zmwa7FTmdzB6aaEEuuls18H6Ap5JmJPSoPTuXixeJZV6tG40SyLkApQtz1g8ptZtiEKqj9OM0oNLPh1AgvE31Q==} + '@rolldown/binding-linux-arm-gnueabihf@1.2.12': + resolution: {integrity: sha512-XcFu0R0xWnwzSf4IQgFH1rJIckPN1pLy2R+4r9IDB7Yfu/ys9cVqfa4pBrMHj7a3gl8mIR4nRNPg0e5IvEVs6g==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@rolldown/binding-linux-arm64-gnu@1.2.8': - resolution: {integrity: sha512-KdYQDPHwJVnbFwdTGMgxsI9SqblBlz6STGM+w1We/d5B8OWWidYH0MwkU/uA1wM5fIpO2MkOVxXrNzzuZhw9ew==} + '@rolldown/binding-linux-arm64-gnu@1.2.12': + resolution: {integrity: sha512-260UrKgn8tz39ak+SMDOirKzr7V04M9dWPw5llW00SwBivCZoWcRBKV1d8cXnRkUmSZA3BdiUmBHWk7734Ulpw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [glibc] - '@rolldown/binding-linux-arm64-musl@1.2.8': - resolution: {integrity: sha512-jFJTifHnNPY+yzOoNZQfSIysrVyXzEQPhPnOUjmD1bcQGHH6s7c8cViKWar8YplQImE5N9JRqMCLrM2CdxOrZA==} + '@rolldown/binding-linux-arm64-musl@1.2.12': + resolution: {integrity: sha512-5YK1I9SqDkbPgc1IA8BgDl34suqUS2q0KWnBrirm0E51YjOs6eo6dV6jbQfNE/argHRSvd0QUGgtpIoYx+WWpw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] libc: [musl] - '@rolldown/binding-linux-ppc64-gnu@1.2.8': - resolution: {integrity: sha512-FhiOziBDWPBjbcmRzfLyIJnaP7AVMFXT7YCXPjXxj7wKU3vx24RjrCNN/zjvVa+N2vVoHJwCoUBvsrN/DG3zIA==} + '@rolldown/binding-linux-ppc64-gnu@1.2.12': + resolution: {integrity: sha512-Rkcrmp7eFRg74yL5fXEU91JEWbdEPLevWwGtXpmhbjlD1StScbWTmO94Bhly+Mo+ketKYkdmM1vNUKeWSlx8cQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ppc64] os: [linux] libc: [glibc] - '@rolldown/binding-linux-s390x-gnu@1.2.8': - resolution: {integrity: sha512-WnHfADMzOV2Y55wlx1hzzQnar/wDt/VdvWSD99r18Mz9ylNieIGOkRx3UV21h7m/eJvjySYJkO26VvGNFkwsIQ==} + '@rolldown/binding-linux-s390x-gnu@1.2.12': + resolution: {integrity: sha512-qvK4DuAsQc2BSjlx+Xr+IzOIvvxbGZqxFwdWfG6F518Erj0GGISyQbJ6pIappnOxlNPzNHvo/L0BwB30GZ+zVw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [s390x] os: [linux] libc: [glibc] - '@rolldown/binding-linux-x64-gnu@1.2.8': - resolution: {integrity: sha512-H9tRr5ibfXFVLxbPOseVewewFpl28zcEdjRDt2FTUZU7odxP0gEv1ki4/kGmcGOh78oRwZuuQllGLZ9zTJp84g==} + '@rolldown/binding-linux-x64-gnu@1.2.12': + resolution: {integrity: sha512-Q9uLBO53Xd4QIq1WOycVQyPP1O4HhraEV2qqb3uTrnVw6QZih9duY4vNXOivL1xoUS1/z+W8eF4NMfl2a8Sdjw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [glibc] - '@rolldown/binding-linux-x64-musl@1.2.8': - resolution: {integrity: sha512-UefiqfM3D6IVNlZ8tSGs9+Ejjud2T+oxO0IHADU45Y+lyEjD2dVFyZHbkfX0LUb5Zugo/oIv1eCO/KVYhgYJYA==} + '@rolldown/binding-linux-x64-musl@1.2.12': + resolution: {integrity: sha512-3IBxWFMjbOZskDPKv8Lf9BCnahlKuHthWkYnyIxOH/QcJrFcS4EmcenthApkwr/5+nEqZlLzeYbxeMaX7A5u4g==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] libc: [musl] - '@rolldown/binding-openharmony-arm64@1.2.8': - resolution: {integrity: sha512-637Ke4kWSy6rp9cxQ9gMOXlxPgIw/c1beASV4M//3+9I4uwBVOOl74G+e3zyU3u19U7RkRl/HuewixZ/Z6+Rjg==} + '@rolldown/binding-openharmony-arm64@1.2.12': + resolution: {integrity: sha512-xtX61xg4LKPkPWilZU1ynKClz5Gj4bf74LML4r3eVLWumKnGjoEr1OSHQhMdbBDoYTi+yjrujvpZe2pUnqCrrA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [openharmony] - '@rolldown/binding-win32-arm64-msvc@1.2.8': - resolution: {integrity: sha512-xWBkPOF1Q9k/Gv1nQXnVdLxKu74jXppuOM4Z3mnypVUJJJwLsMl7hNJGRAUJoG8A5MgOI1ACKM+wBFxSJzKy4A==} + '@rolldown/binding-win32-arm64-msvc@1.2.12': + resolution: {integrity: sha512-At7fPB6PCaIjzgIhEZFxuT+BBFqiQibJDT4d3PhiR3f4E7bbMZF4aKblbFfEM3sETRDd1YiQx/+U/g/B/ou5Ew==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [win32] - '@rolldown/binding-win32-x64-msvc@1.2.8': - resolution: {integrity: sha512-uz2ZvfgXbxqNwijjjbxrnvALwpyODDcgc1T1N8N3rf/DXKQmaFwmB4LX4yyjggpwN2obdQLb2rgirX5ffCWYng==} + '@rolldown/binding-win32-x64-msvc@1.2.12': + resolution: {integrity: sha512-WIw2haVKwjuYdXkHaoC0mF8Le71TuCBxjrdKqLbJGctbBABj+ClfmNvtbOnzpq3RokNo5+V1qhtSzJyXorsklQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [win32] @@ -1260,8 +1260,8 @@ packages: resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} engines: {node: '>=0.10.0'} - rolldown@1.2.8: - resolution: {integrity: sha512-Z67nTmhZe7anqnM/EjI392w5i/ANUinjip7QYsOyN37oayduxt3ksdX0hf5OOamkAd53BiIHfbfSzfUmzKFQqQ==} + rolldown@1.2.12: + resolution: {integrity: sha512-8wafseiaG80xmXSfqidUNqZcylTlhmPZZt+za2m+js2sFZ8dTNlhIOV2WcbIPx2hgwPBJpEUGFAMZ9bgBBLTSQ==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true @@ -1298,6 +1298,10 @@ packages: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} + source-map-js@1.2.2: + resolution: {integrity: sha512-KGj/8Y43x35aZVDtt+J4mK1hoLGHULMYfSkODJNQjNDC3oW1PqPoxMwo0pLUsWM/UEGzON/NxeHywEfNXNP3Vw==} + engines: {node: '>=0.10.0'} + stackback@0.0.2: resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} @@ -1445,8 +1449,8 @@ packages: yaml: optional: true - vite@8.3.0: - resolution: {integrity: sha512-lhZBVvEHefgE+HQZC9O7EBJgCU/nVzFNl7vkS4RE0APtWLP02/8QVIkQtzBxPquh7lq5/78NHipTj7ODQ6XuyQ==} + vite@8.3.2: + resolution: {integrity: sha512-SQr1x6W5vVSbROg7vsyXIaxK9b0G7zsT68acdWWRmnBUsgDieLCRG+Rep9WdZgcposvv/GSnr4GUUBqB3vXq6w==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: @@ -1812,54 +1816,54 @@ snapshots: '@napi-rs/lzma-linux-x64-gnu@1.5.1': optional: true - '@oxc-project/types@0.149.0': {} + '@oxc-project/types@0.152.0': {} '@pkgjs/parseargs@0.11.0': optional: true - '@rolldown/binding-android-arm-eabi@1.2.8': + '@rolldown/binding-android-arm-eabi@1.2.12': optional: true - '@rolldown/binding-android-arm64@1.2.8': + '@rolldown/binding-android-arm64@1.2.12': optional: true - '@rolldown/binding-darwin-arm64@1.2.8': + '@rolldown/binding-darwin-arm64@1.2.12': optional: true - '@rolldown/binding-darwin-x64@1.2.8': + '@rolldown/binding-darwin-x64@1.2.12': optional: true - '@rolldown/binding-freebsd-x64@1.2.8': + '@rolldown/binding-freebsd-x64@1.2.12': optional: true - '@rolldown/binding-linux-arm-gnueabihf@1.2.8': + '@rolldown/binding-linux-arm-gnueabihf@1.2.12': optional: true - '@rolldown/binding-linux-arm64-gnu@1.2.8': + '@rolldown/binding-linux-arm64-gnu@1.2.12': optional: true - '@rolldown/binding-linux-arm64-musl@1.2.8': + '@rolldown/binding-linux-arm64-musl@1.2.12': optional: true - '@rolldown/binding-linux-ppc64-gnu@1.2.8': + '@rolldown/binding-linux-ppc64-gnu@1.2.12': optional: true - '@rolldown/binding-linux-s390x-gnu@1.2.8': + '@rolldown/binding-linux-s390x-gnu@1.2.12': optional: true - '@rolldown/binding-linux-x64-gnu@1.2.8': + '@rolldown/binding-linux-x64-gnu@1.2.12': optional: true - '@rolldown/binding-linux-x64-musl@1.2.8': + '@rolldown/binding-linux-x64-musl@1.2.12': optional: true - '@rolldown/binding-openharmony-arm64@1.2.8': + '@rolldown/binding-openharmony-arm64@1.2.12': optional: true - '@rolldown/binding-win32-arm64-msvc@1.2.8': + '@rolldown/binding-win32-arm64-msvc@1.2.12': optional: true - '@rolldown/binding-win32-x64-msvc@1.2.8': + '@rolldown/binding-win32-x64-msvc@1.2.12': optional: true '@rolldown/pluginutils@1.0.1': {} @@ -2612,7 +2616,7 @@ snapshots: dependencies: nanoid: 3.3.19 picocolors: 1.1.1 - source-map-js: 1.2.1 + source-map-js: 1.2.2 prelude-ls@1.2.1: {} @@ -2624,26 +2628,26 @@ snapshots: require-from-string@2.0.2: {} - rolldown@1.2.8: + rolldown@1.2.12: dependencies: - '@oxc-project/types': 0.149.0 + '@oxc-project/types': 0.152.0 '@rolldown/pluginutils': 1.0.1 optionalDependencies: - '@rolldown/binding-android-arm-eabi': 1.2.8 - '@rolldown/binding-android-arm64': 1.2.8 - '@rolldown/binding-darwin-arm64': 1.2.8 - '@rolldown/binding-darwin-x64': 1.2.8 - '@rolldown/binding-freebsd-x64': 1.2.8 - '@rolldown/binding-linux-arm-gnueabihf': 1.2.8 - '@rolldown/binding-linux-arm64-gnu': 1.2.8 - '@rolldown/binding-linux-arm64-musl': 1.2.8 - '@rolldown/binding-linux-ppc64-gnu': 1.2.8 - '@rolldown/binding-linux-s390x-gnu': 1.2.8 - '@rolldown/binding-linux-x64-gnu': 1.2.8 - '@rolldown/binding-linux-x64-musl': 1.2.8 - '@rolldown/binding-openharmony-arm64': 1.2.8 - '@rolldown/binding-win32-arm64-msvc': 1.2.8 - '@rolldown/binding-win32-x64-msvc': 1.2.8 + '@rolldown/binding-android-arm-eabi': 1.2.12 + '@rolldown/binding-android-arm64': 1.2.12 + '@rolldown/binding-darwin-arm64': 1.2.12 + '@rolldown/binding-darwin-x64': 1.2.12 + '@rolldown/binding-freebsd-x64': 1.2.12 + '@rolldown/binding-linux-arm-gnueabihf': 1.2.12 + '@rolldown/binding-linux-arm64-gnu': 1.2.12 + '@rolldown/binding-linux-arm64-musl': 1.2.12 + '@rolldown/binding-linux-ppc64-gnu': 1.2.12 + '@rolldown/binding-linux-s390x-gnu': 1.2.12 + '@rolldown/binding-linux-x64-gnu': 1.2.12 + '@rolldown/binding-linux-x64-musl': 1.2.12 + '@rolldown/binding-openharmony-arm64': 1.2.12 + '@rolldown/binding-win32-arm64-msvc': 1.2.12 + '@rolldown/binding-win32-x64-msvc': 1.2.12 rollup@4.62.5: dependencies: @@ -2695,6 +2699,8 @@ snapshots: source-map-js@1.2.1: {} + source-map-js@1.2.2: {} + stackback@0.0.2: {} std-env@3.10.0: {} @@ -2825,12 +2831,12 @@ snapshots: fsevents: 2.3.3 lightningcss: 1.33.0 - vite@8.3.0(@types/node@26.6.2)(esbuild@0.28.2): + vite@8.3.2(@types/node@26.6.2)(esbuild@0.28.2): dependencies: lightningcss: 1.33.0 picomatch: 4.0.7 postcss: 8.5.28 - rolldown: 1.2.8 + rolldown: 1.2.12 tinyglobby: 0.2.17 optionalDependencies: '@types/node': 26.6.2 diff --git a/src/Resources/public/js/device-intelligence.min.js b/src/Resources/public/js/device-intelligence.min.js index 3e906f8..76f734c 100644 --- a/src/Resources/public/js/device-intelligence.min.js +++ b/src/Resources/public/js/device-intelligence.min.js @@ -1,2 +1,2 @@ -var DeviceIntelligence=(function(e){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});var t=class{entry=null;get(){return this.entry===null?null:Date.now()>=this.entry.expiresAt?(this.entry=null,null):this.entry.value}set(e,t){let n=t*1e3;this.entry={value:e,expiresAt:Date.now()+n},n<=0&&(this.entry=null)}clear(){this.entry=null}has(){return this.get()!==null}},n=16;async function r(e){let t=globalThis.crypto?.subtle;if(!t)throw Error(`WebCrypto SubtleCrypto is not available`);let n=typeof e==`string`?new TextEncoder().encode(e):e,r=await t.digest(`SHA-256`,n),i=new Uint8Array(r),a=``;for(let e=0;e1?1:e}function o(e){return{name:e.name,value:e.value,normalizedValue:e.normalizedValue,quality:a(e.quality),stability:a(e.stability),entropyCategory:e.entropyCategory,collectedAt:e.collectedAt??Date.now()}}function s(e){return new Promise((t,n)=>{let r=()=>{n(new DOMException(`The operation was aborted.`,`AbortError`))};if(e.aborted){r();return}e.addEventListener(`abort`,r,{once:!0})})}function c(e,t){return Promise.race([e,s(t)])}function l(e){if(e.abortSignal.aborted)throw new DOMException(`The operation was aborted.`,`AbortError`)}var u=44100,d=44100,f=256,p=class{name=`audio`;async collect(e){l(e);let t=m();if(!t)throw Error(`OfflineAudioContext is not available`);let n=new t(1,d,u),r=n.createOscillator();r.type=`triangle`,r.frequency.value=1e4;let a=n.createDynamicsCompressor();a.threshold.value=-50,a.knee.value=40,a.ratio.value=12,a.attack.value=0,a.release.value=.25,r.connect(a),a.connect(n.destination),r.start(0);let s=await i(h((await c(n.startRendering(),e.abortSignal)).getChannelData(0),f).join(`,`));return o({name:this.name,value:s,normalizedValue:s,quality:.85,stability:.9,entropyCategory:`high`})}};function m(){let e=globalThis;return e.OfflineAudioContext??e.webkitOfflineAudioContext??null}function h(e,t){let n=Math.max(1,Math.floor(e.length/t)),r=[];for(let i=0;i`u`?null:navigator,r=n?.userAgent??``;n&&n.webdriver===!0&&t.push(`webdriver`),!n||!Array.isArray(n.languages)||n.languages.length===0?t.push(`missing-languages`):n.language&&n.languages[0]&&n.language!==n.languages[0]&&t.push(`language-mismatch`),!n||typeof n.hardwareConcurrency!=`number`?t.push(`missing-hardware-concurrency`):(n.hardwareConcurrency<=0||n.hardwareConcurrency>128)&&t.push(`implausible-hardware-concurrency`),/headless/i.test(r)&&t.push(`headless-ua`),/HeadlessChrome/i.test(r)&&t.push(`headless-chrome`),typeof window<`u`&&window.outerWidth===0&&window.outerHeight===0&&t.push(`zero-outer-size`);let i={indicators:t,confidence:a(t.reduce((e,t)=>e+(ee[t]??.15),0))};return o({name:this.name,value:i,normalizedValue:i,quality:.8,stability:.5,entropyCategory:`low`})}},g=280,_=80,v=class{name=`canvas`;async collect(e){if(l(e),typeof document>`u`)throw Error(`document is not available`);let t=document.createElement(`canvas`);t.width=g,t.height=_,t.style.display=`none`;let n=t.getContext(`2d`,{willReadFrequently:!0});if(!n)throw Error(`CanvasRenderingContext2D is not available`);y(n);let r=await i(n.getImageData(0,0,g,_).data);return o({name:this.name,value:r,normalizedValue:r,quality:.92,stability:.95,entropyCategory:`high`})}};function y(e){e.fillStyle=`#f60`,e.fillRect(8,8,90,48),e.fillStyle=`#069`,e.fillRect(108,12,70,40),e.strokeStyle=`#111827`,e.lineWidth=2,e.beginPath(),e.arc(220,36,26,0,Math.PI*2),e.stroke(),e.beginPath(),e.arc(248,52,14,.25*Math.PI,1.6*Math.PI),e.stroke(),e.fillStyle=`#111827`,e.font=`16px Arial, sans-serif`,e.textBaseline=`top`,e.fillText(`DeviceIntelligence`,12,58),e.fillStyle=`rgba(16, 185, 129, 0.45)`,e.fillRect(40,20,36,18)}var b=class{name=`capabilities`;async collect(e){l(e);let t=typeof navigator>`u`?null:navigator,n=typeof window>`u`?null:window,r={cookieEnabled:t?.cookieEnabled??!1,pdfViewerEnabled:!!t?.pdfViewerEnabled,serviceWorker:!!(t&&`serviceWorker`in t),webgl:x(),webgpu:!!(t&&`gpu`in t),wasm:typeof WebAssembly<`u`,sharedArrayBuffer:typeof SharedArrayBuffer<`u`,touch:(t?.maxTouchPoints??0)>0,matchMedia:typeof n?.matchMedia==`function`,localStorage:S(`localStorage`),sessionStorage:S(`sessionStorage`),indexedDB:typeof indexedDB<`u`},i=Object.entries(r).filter(([,e])=>e).map(([e])=>e).sort();return o({name:this.name,value:r,normalizedValue:i,quality:.9,stability:.9,entropyCategory:`medium`})}};function x(){if(typeof document>`u`||typeof navigator<`u`&&/jsdom/i.test(navigator.userAgent))return!1;try{let e=document.createElement(`canvas`);return!!(e.getContext(`webgl`)||e.getContext(`experimental-webgl`))}catch{return!1}}function S(e){try{let t=globalThis[e],n=`__di_cap__`;return t.setItem(n,`1`),t.removeItem(n),!0}catch{return!1}}function C(e){let t=e.trim();return t.length===0?`other`:/Edg(?:e|A|iOS)?\/|\bEdge\//i.test(t)||/^Edge\s/i.test(t)?w(t,`Edge`,/(?:Edg(?:e|A|iOS)?|Edge)[/\s](\d+)/i):/\bOPR\/|\bOpera\//i.test(t)||/^Opera\s/i.test(t)?w(t,`Opera`,/(?:OPR|Opera)[/\s](\d+)/i):/\bFirefox\/|\bFxiOS\//i.test(t)||/^Firefox\s/i.test(t)?w(t,`Firefox`,/(?:Firefox|FxiOS)[/\s](\d+)/i):/^Chrome\s+\d+/i.test(t)?w(t,`Chrome`,/^Chrome\s+(\d+)/i):/\bSafari\//i.test(t)&&/\bVersion\//i.test(t)&&!/\b(Chrome|Chromium|CriOS|Edg|OPR)\b/i.test(t)||/^Safari\s/i.test(t)?w(t,`Safari`,/(?:Version|Safari)[/\s](\d+)/i):/\b(Chrome|Chromium|CriOS)\//i.test(t)?w(t,`Chrome`,/(?:Chrome|Chromium|CriOS)\/(\d+)/i):`other`}function w(e,t,n){let r=e.match(n)?.[1];return r?`${t} ${r}`:t}function T(e){let t=e.toLowerCase();return t.includes(`win`)?`windows`:t.includes(`android`)?`android`:t.includes(`iphone`)||t.includes(`ipad`)||t.includes(`ipod`)||t.includes(`ios`)?`ios`:t.includes(`mac`)||t.includes(`darwin`)?`macos`:t.includes(`linux`)||t.includes(`x11`)||t.includes(`cros`)?`linux`:`other`}function E(e,t){let n=Math.max(e,t);return!Number.isFinite(n)||n<=0?`other`:n<=480?`mobile-s`:n<=767?`mobile-l`:n<=1280?`tablet`:n<=1920?`hd`:n<=2560?`qhd`:n<=3840?`uhd`:`other`}function D(e,t){let n=`${e} ${t}`.toLowerCase();return n.includes(`apple`)||n.includes(`metal`)?`apple`:n.includes(`nvidia`)||n.includes(`geforce`)||n.includes(`quadro`)?`nvidia`:n.includes(`amd`)||n.includes(`radeon`)||n.includes(`ati`)?`amd`:n.includes(`intel`)?`intel`:n.includes(`mali`)?`mali`:n.includes(`adreno`)?`adreno`:`other`}var O=[`architecture`,`bitness`,`model`,`platformVersion`,`uaFullVersion`,`fullVersionList`],ne=class{name=`client_hints`;async collect(e){if(l(e),typeof navigator>`u`)throw Error(`navigator is not available`);let t=navigator.userAgentData;if(!t)return o({name:this.name,value:{brands:[],mobile:null,platform:``,highEntropy:!1,available:!1},normalizedValue:{browser:C(navigator.userAgent??``),platform:T(navigator.platform??navigator.userAgent??``),highEntropy:!1},quality:.35,stability:.7,entropyCategory:`medium`});let n={brands:Array.isArray(t.brands)?t.brands:[],mobile:typeof t.mobile==`boolean`?t.mobile:null,platform:t.platform??``,highEntropy:!1,available:!0},r={},i=!1;if(e.consent.highEntropy&&typeof t.getHighEntropyValues==`function`)try{r=await c(t.getHighEntropyValues([...O]),e.abortSignal),i=!0}catch{i=!1}let a={...n,...r,highEntropy:i},s=re(n.brands),u=typeof r.uaFullVersion==`string`?String(r.uaFullVersion):s?.version??``,d=s?`${s.brand} ${u}`:navigator.userAgent;return o({name:this.name,value:a,normalizedValue:{browser:C(d),platform:T(n.platform||navigator.platform||``),highEntropy:i},quality:i?.95:.7,stability:.75,entropyCategory:`medium`})}};function re(e){return e.find(e=>{let t=e.brand.toLowerCase();return t!==`not?a;brand`&&t!==`not a;brand`&&!t.includes(`not:`)})??e[0]??null}var k=`mmmmmmmmmmlli`,A=`monospace`,j=[`Arial`,`Times New Roman`,`Courier New`,`Georgia`,`Verdana`,`Roboto`],M=class{name=`fonts`;async collect(e){if(l(e),typeof document>`u`||!document.body)throw Error(`document.body is not available`);let t=N(k,A),n=j.filter(e=>N(k,`${e}, ${A}`)!==t);return o({name:this.name,value:n,normalizedValue:[...n].sort(),quality:.7,stability:.8,entropyCategory:`high`})}};function N(e,t){let n=document.createElement(`span`);n.style.cssText=[`position:absolute`,`left:-9999px`,`top:0`,`visibility:hidden`,`white-space:nowrap`,`font:72px ${t}`].join(`;`),n.textContent=e,document.body.appendChild(n);let r=n.offsetWidth;return document.body.removeChild(n),r}var P=class{name=`navigator`;async collect(e){if(l(e),typeof navigator>`u`)throw Error(`navigator is not available`);let t=navigator.userAgent??``,n=navigator.platform??``,r=Array.isArray(navigator.languages)?[...navigator.languages]:[],i=navigator,a={userAgent:t,platform:n,language:navigator.language??``,languages:r,hardwareConcurrency:navigator.hardwareConcurrency??null,deviceMemory:typeof i.deviceMemory==`number`?i.deviceMemory:null,maxTouchPoints:navigator.maxTouchPoints??0,vendor:navigator.vendor??``},s=C(t),c=T(n||t);return o({name:this.name,value:a,normalizedValue:{browser:s,platform:c,hardwareConcurrency:a.hardwareConcurrency},quality:t.length>0?.9:.4,stability:.8,entropyCategory:`medium`})}},F=class{name=`screen`;async collect(e){l(e);let t=typeof screen>`u`?null:screen;if(!t)throw Error(`screen is not available`);let n=I(t.width),r=I(t.height),i={width:n,height:r,availWidth:I(t.availWidth),availHeight:I(t.availHeight),colorDepth:I(t.colorDepth),pixelDepth:I(t.pixelDepth),pixelRatio:I(typeof devicePixelRatio==`number`?devicePixelRatio:1)},a=E(n,r);return o({name:this.name,value:i,normalizedValue:{screenClass:a,width:n,height:r},quality:n>0&&r>0?.95:.4,stability:.7,entropyCategory:`low`})}};function I(e){return Number.isFinite(e)?e:0}var L=class{name=`timezone`;async collect(e){l(e);let t=`UTC`;try{t=Intl.DateTimeFormat().resolvedOptions().timeZone||`UTC`}catch{t=`UTC`}let n=new Date().getTimezoneOffset(),r={timeZone:t,offsetMinutes:n};return o({name:this.name,value:r,normalizedValue:t,quality:t.length>0?.99:.3,stability:.85,entropyCategory:`low`})}},R=class{name=`webgl`;async collect(e){if(l(e),typeof document>`u`)throw Error(`document is not available`);let t=document.createElement(`canvas`);t.width=1,t.height=1;let n=z(t);if(!n)throw Error(`WebGL is not available`);try{let e=n.getExtension(`WEBGL_debug_renderer_info`),t=B(n,e?e.UNMASKED_VENDOR_WEBGL:n.VENDOR),r=B(n,e?e.UNMASKED_RENDERER_WEBGL:n.RENDERER),a=await i([...n.getSupportedExtensions()??[]].sort().join(`,`)),s=n.getParameter(n.MAX_VIEWPORT_DIMS),c={maxTextureSize:V(n,n.MAX_TEXTURE_SIZE),maxViewportDims:Array.isArray(s)?[Number(s[0]),Number(s[1])]:s instanceof Int32Array?[s[0]??0,s[1]??0]:null,maxRenderbufferSize:V(n,n.MAX_RENDERBUFFER_SIZE),maxVertexAttribs:V(n,n.MAX_VERTEX_ATTRIBS),maxFragmentUniformVectors:V(n,n.MAX_FRAGMENT_UNIFORM_VECTORS)},l={vendor:t,renderer:r,extensionsHash:a,limits:c},u=typeof r==`string`&&r.length>0,d=u&&e?.88:u?.7:.45;return o({name:this.name,value:l,normalizedValue:{gpuFamily:D(t??``,r??``),extensionsHash:a,maxTextureSize:c.maxTextureSize},quality:d,stability:.95,entropyCategory:`high`})}finally{n.getExtension(`WEBGL_lose_context`)?.loseContext()}}};function z(e){let t={alpha:!0,antialias:!1,depth:!1,failIfMajorPerformanceCaveat:!1,preserveDrawingBuffer:!1};return e.getContext(`webgl`,t)||e.getContext(`experimental-webgl`,t)}function B(e,t){try{let n=e.getParameter(t);return typeof n==`string`&&n.length>0?n:null}catch{return null}}function V(e,t){try{let n=e.getParameter(t);return typeof n==`number`&&Number.isFinite(n)?n:null}catch{return null}}var H=`X-Previous-Debug-Token`;function U(){if(typeof document>`u`)return;let e=document.querySelector(`[id^="sfwdt"]`);if(!(e instanceof Element)||!e.id.startsWith(`sfwdt`))return;let t=e.id.slice(5);return t.length>0?t:void 0}async function W(e,t,n){try{let r={"Content-Type":`application/json`},i=U();i!==void 0&&(r[H]=i);let a=await fetch(e,{method:`POST`,credentials:`same-origin`,headers:r,body:JSON.stringify(t),signal:n});if(!a.ok)return null;let o=await a.text();if(o.trim().length===0)return{ok:!0};let s=JSON.parse(o);return typeof s!=`object`||!s?{ok:!0}:s}catch{return null}}var G=`1.0.0`,K=`/_device/collect`,q=1500,J=3600,Y={audio:!0,canvas:!0,webgl:!0,screen:!0,timezone:!0,navigator:!0,clientHints:!0,capabilities:!0,automation:!0,fonts:!1},ie=class{endpoint;timeout;cacheTtl;cacheEnabled;consent;cache=new t;collectors=[];constructor(e={}){this.endpoint=e.endpoint??K,this.timeout=oe(e.timeout),this.cacheEnabled=e.cache?.enabled??!0,this.cacheTtl=e.cache?.ttl??J,this.consent={highEntropy:e.consent?.highEntropy??!0},this.collectors=ae({...Y,...e.collectors})}async collect(){return this.runCollect(!1)}async refresh(){return this.runCollect(!0)}getCachedObservation(){return this.cache.get()}clear(){this.cache.clear()}registerCollector(e){this.collectors.push(e)}async runCollect(e){try{if(!e&&this.cacheEnabled){let e=this.cache.get();if(e)return e.result}let t=new AbortController,n=globalThis.setTimeout(()=>t.abort(),this.timeout),r={timeout:this.timeout,abortSignal:t.signal,consent:this.consent},i={};try{i=await this.collectSignals(r)}finally{globalThis.clearTimeout(n)}let a=this.collectors.length,o=Object.keys(i).length,s=ol.abort(),this.timeout),d=null;try{d=await W(this.endpoint,c,l.signal)}finally{globalThis.clearTimeout(u)}let f=d===null,p=o>0,m={ok:!f&&p&&d?.ok!==!1,degraded:!!d?.degraded||s||f||!p,signals:i};d?.new!==void 0&&(m.new=d.new),d?.token!==void 0&&(m.token=d.token),d?.expiresAt!==void 0&&(m.expiresAt=d.expiresAt),d?.deviceId!==void 0&&(m.deviceId=d.deviceId),d?.confidence!==void 0&&(m.confidence=d.confidence),d?.risk!==void 0&&(m.risk=d.risk),(f||!p)&&(m.ok=!1,m.degraded=!0);let h={timestamp:Date.now(),signals:i,result:m};return this.cacheEnabled&&this.cache.set(h,this.cacheTtl),m}catch{return{ok:!1,degraded:!0,signals:{}}}}async collectSignals(e){let t={},n=this.collectors.map(async n=>{try{let r=await c(n.collect(e),e.abortSignal);r&&typeof r.name==`string`&&(t[r.name]=r)}catch{}}),r=Promise.all(n),i=ce(this.timeout,e.abortSignal);return await Promise.race([r,i]),await Promise.allSettled(n),t}toPayload(e){let t={};for(let[n,r]of Object.entries(e))t[n]={value:r.value,quality:r.quality,collectedAt:r.collectedAt};return{v:1,sdkVersion:G,timestamp:Math.floor(Date.now()/1e3),nonce:se(),consent:this.consent,signals:t}}};function ae(e){let t=[];return e.navigator&&t.push(new P),e.clientHints&&t.push(new ne),e.screen&&t.push(new F),e.timezone&&t.push(new L),e.capabilities&&t.push(new b),e.automation&&t.push(new te),e.canvas&&t.push(new v),e.webgl&&t.push(new R),e.audio&&t.push(new p),e.fonts&&t.push(new M),t}function oe(e){return typeof e==`number`&&Number.isFinite(e)&&e>0?e:q}function se(){let e=new Uint8Array(16);if(globalThis.crypto?.getRandomValues)globalThis.crypto.getRandomValues(e);else for(let t=0;t{if(t.aborted){n();return}let r=globalThis.setTimeout(n,e);t.addEventListener(`abort`,()=>{globalThis.clearTimeout(r),n()},{once:!0})})}var X={script:`color:#0ea5e9;font-weight:bold`,debug:`color:#6b7280`,info:`color:#2563eb`,warn:`color:#d97706`,error:`color:#dc2626;font-weight:bold`},Z={script:`đŸ“Ļ`,debug:`🔍`,info:`â„šī¸`,warn:`âš ī¸`,error:`❌`};function le(e){return e.map(e=>typeof e==`object`&&e&&!(e instanceof Error)?JSON.stringify(e):e)}function ue(e,t){if(t!==void 0&&t!==``){console.log(`%c${Z.script} ${e} script loaded, build time: %c${t}`,X.script,`color:#059669`);return}console.log(`%c${Z.script} ${e} script loaded`,X.script)}function Q(e,t,n){let r=Z[e],i=X[e],a=`%c${r} ${t}`,o=console[e];if(n.length>0){o(a,i,...le(n));return}o(a,i)}function $(e,t,n){return(...r)=>{e()&&Q(n,t,r)}}function de(e,t={}){let n=`[${e}]`,{buildTime:r,alwaysLog:i=!1}=t,a=i===!0,o=a;return{scriptLoaded(){ue(n,r)},setDebug(e){o=a?!0:e},debug:$(()=>o,n,`debug`),info:$(()=>o,n,`info`),warn:$(()=>o,n,`warn`),error:$(()=>o,n,`error`)}}return de(`device-intelligence`,{buildTime:`2026-09-28T07:47:30.314Z`}).scriptLoaded(),e.DeviceIntelligence=ie,e.MemoryCache=t,e.SDK_VERSION=G,e.normalizeBrowser=C,e.normalizeGpuFamily=D,e.normalizePlatform=T,e.normalizeScreenClass=E,e})({});globalThis.DeviceIntelligence=DeviceIntelligence.DeviceIntelligence; +var DeviceIntelligence=(function(e){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});var t=class{entry=null;get(){return this.entry===null?null:Date.now()>=this.entry.expiresAt?(this.entry=null,null):this.entry.value}set(e,t){let n=t*1e3;this.entry={value:e,expiresAt:Date.now()+n},n<=0&&(this.entry=null)}clear(){this.entry=null}has(){return this.get()!==null}},n=16;async function r(e){let t=globalThis.crypto?.subtle;if(!t)throw Error(`WebCrypto SubtleCrypto is not available`);let n=typeof e==`string`?new TextEncoder().encode(e):e,r=await t.digest(`SHA-256`,n),i=new Uint8Array(r),a=``;for(let e=0;e1?1:e}function o(e){return{name:e.name,value:e.value,normalizedValue:e.normalizedValue,quality:a(e.quality),stability:a(e.stability),entropyCategory:e.entropyCategory,collectedAt:e.collectedAt??Date.now()}}function s(e){return new Promise((t,n)=>{let r=()=>{n(new DOMException(`The operation was aborted.`,`AbortError`))};if(e.aborted){r();return}e.addEventListener(`abort`,r,{once:!0})})}function c(e,t){return Promise.race([e,s(t)])}function l(e){if(e.abortSignal.aborted)throw new DOMException(`The operation was aborted.`,`AbortError`)}var u=44100,d=44100,f=256,p=class{name=`audio`;async collect(e){l(e);let t=m();if(!t)throw Error(`OfflineAudioContext is not available`);let n=new t(1,d,u),r=n.createOscillator();r.type=`triangle`,r.frequency.value=1e4;let a=n.createDynamicsCompressor();a.threshold.value=-50,a.knee.value=40,a.ratio.value=12,a.attack.value=0,a.release.value=.25,r.connect(a),a.connect(n.destination),r.start(0);let s=await i(h((await c(n.startRendering(),e.abortSignal)).getChannelData(0),f).join(`,`));return o({name:this.name,value:s,normalizedValue:s,quality:.85,stability:.9,entropyCategory:`high`})}};function m(){let e=globalThis;return e.OfflineAudioContext??e.webkitOfflineAudioContext??null}function h(e,t){let n=Math.max(1,Math.floor(e.length/t)),r=[];for(let i=0;i`u`?null:navigator,r=n?.userAgent??``;n&&n.webdriver===!0&&t.push(`webdriver`),!n||!Array.isArray(n.languages)||n.languages.length===0?t.push(`missing-languages`):n.language&&n.languages[0]&&n.language!==n.languages[0]&&t.push(`language-mismatch`),!n||typeof n.hardwareConcurrency!=`number`?t.push(`missing-hardware-concurrency`):(n.hardwareConcurrency<=0||n.hardwareConcurrency>128)&&t.push(`implausible-hardware-concurrency`),/headless/i.test(r)&&t.push(`headless-ua`),/HeadlessChrome/i.test(r)&&t.push(`headless-chrome`),typeof window<`u`&&window.outerWidth===0&&window.outerHeight===0&&t.push(`zero-outer-size`);let i={indicators:t,confidence:a(t.reduce((e,t)=>e+(ee[t]??.15),0))};return o({name:this.name,value:i,normalizedValue:i,quality:.8,stability:.5,entropyCategory:`low`})}},g=280,_=80,v=class{name=`canvas`;async collect(e){if(l(e),typeof document>`u`)throw Error(`document is not available`);let t=document.createElement(`canvas`);t.width=g,t.height=_,t.style.display=`none`;let n=t.getContext(`2d`,{willReadFrequently:!0});if(!n)throw Error(`CanvasRenderingContext2D is not available`);y(n);let r=await i(n.getImageData(0,0,g,_).data);return o({name:this.name,value:r,normalizedValue:r,quality:.92,stability:.95,entropyCategory:`high`})}};function y(e){e.fillStyle=`#f60`,e.fillRect(8,8,90,48),e.fillStyle=`#069`,e.fillRect(108,12,70,40),e.strokeStyle=`#111827`,e.lineWidth=2,e.beginPath(),e.arc(220,36,26,0,Math.PI*2),e.stroke(),e.beginPath(),e.arc(248,52,14,.25*Math.PI,1.6*Math.PI),e.stroke(),e.fillStyle=`#111827`,e.font=`16px Arial, sans-serif`,e.textBaseline=`top`,e.fillText(`DeviceIntelligence`,12,58),e.fillStyle=`rgba(16, 185, 129, 0.45)`,e.fillRect(40,20,36,18)}var b=class{name=`capabilities`;async collect(e){l(e);let t=typeof navigator>`u`?null:navigator,n=typeof window>`u`?null:window,r={cookieEnabled:t?.cookieEnabled??!1,pdfViewerEnabled:!!t?.pdfViewerEnabled,serviceWorker:!!(t&&`serviceWorker`in t),webgl:x(),webgpu:!!(t&&`gpu`in t),wasm:typeof WebAssembly<`u`,sharedArrayBuffer:typeof SharedArrayBuffer<`u`,touch:(t?.maxTouchPoints??0)>0,matchMedia:typeof n?.matchMedia==`function`,localStorage:S(`localStorage`),sessionStorage:S(`sessionStorage`),indexedDB:typeof indexedDB<`u`},i=Object.entries(r).filter(([,e])=>e).map(([e])=>e).sort();return o({name:this.name,value:r,normalizedValue:i,quality:.9,stability:.9,entropyCategory:`medium`})}};function x(){if(typeof document>`u`||typeof navigator<`u`&&/jsdom/i.test(navigator.userAgent))return!1;try{let e=document.createElement(`canvas`);return!!(e.getContext(`webgl`)||e.getContext(`experimental-webgl`))}catch{return!1}}function S(e){try{let t=globalThis[e],n=`__di_cap__`;return t.setItem(n,`1`),t.removeItem(n),!0}catch{return!1}}function C(e){let t=e.trim();return t.length===0?`other`:/Edg(?:e|A|iOS)?\/|\bEdge\//i.test(t)||/^Edge\s/i.test(t)?w(t,`Edge`,/(?:Edg(?:e|A|iOS)?|Edge)[/\s](\d+)/i):/\bOPR\/|\bOpera\//i.test(t)||/^Opera\s/i.test(t)?w(t,`Opera`,/(?:OPR|Opera)[/\s](\d+)/i):/\bFirefox\/|\bFxiOS\//i.test(t)||/^Firefox\s/i.test(t)?w(t,`Firefox`,/(?:Firefox|FxiOS)[/\s](\d+)/i):/^Chrome\s+\d+/i.test(t)?w(t,`Chrome`,/^Chrome\s+(\d+)/i):/\bSafari\//i.test(t)&&/\bVersion\//i.test(t)&&!/\b(Chrome|Chromium|CriOS|Edg|OPR)\b/i.test(t)||/^Safari\s/i.test(t)?w(t,`Safari`,/(?:Version|Safari)[/\s](\d+)/i):/\b(Chrome|Chromium|CriOS)\//i.test(t)?w(t,`Chrome`,/(?:Chrome|Chromium|CriOS)\/(\d+)/i):`other`}function w(e,t,n){let r=e.match(n)?.[1];return r?`${t} ${r}`:t}function T(e){let t=e.toLowerCase();return t.includes(`win`)?`windows`:t.includes(`android`)?`android`:t.includes(`iphone`)||t.includes(`ipad`)||t.includes(`ipod`)||t.includes(`ios`)?`ios`:t.includes(`mac`)||t.includes(`darwin`)?`macos`:t.includes(`linux`)||t.includes(`x11`)||t.includes(`cros`)?`linux`:`other`}function E(e,t){let n=Math.max(e,t);return!Number.isFinite(n)||n<=0?`other`:n<=480?`mobile-s`:n<=767?`mobile-l`:n<=1280?`tablet`:n<=1920?`hd`:n<=2560?`qhd`:n<=3840?`uhd`:`other`}function D(e,t){let n=`${e} ${t}`.toLowerCase();return n.includes(`apple`)||n.includes(`metal`)?`apple`:n.includes(`nvidia`)||n.includes(`geforce`)||n.includes(`quadro`)?`nvidia`:n.includes(`amd`)||n.includes(`radeon`)||n.includes(`ati`)?`amd`:n.includes(`intel`)?`intel`:n.includes(`mali`)?`mali`:n.includes(`adreno`)?`adreno`:`other`}var O=[`architecture`,`bitness`,`model`,`platformVersion`,`uaFullVersion`,`fullVersionList`],ne=class{name=`client_hints`;async collect(e){if(l(e),typeof navigator>`u`)throw Error(`navigator is not available`);let t=navigator.userAgentData;if(!t)return o({name:this.name,value:{brands:[],mobile:null,platform:``,highEntropy:!1,available:!1},normalizedValue:{browser:C(navigator.userAgent??``),platform:T(navigator.platform??navigator.userAgent??``),highEntropy:!1},quality:.35,stability:.7,entropyCategory:`medium`});let n={brands:Array.isArray(t.brands)?t.brands:[],mobile:typeof t.mobile==`boolean`?t.mobile:null,platform:t.platform??``,highEntropy:!1,available:!0},r={},i=!1;if(e.consent.highEntropy&&typeof t.getHighEntropyValues==`function`)try{r=await c(t.getHighEntropyValues([...O]),e.abortSignal),i=!0}catch{i=!1}let a={...n,...r,highEntropy:i},s=re(n.brands),u=typeof r.uaFullVersion==`string`?String(r.uaFullVersion):s?.version??``,d=s?`${s.brand} ${u}`:navigator.userAgent;return o({name:this.name,value:a,normalizedValue:{browser:C(d),platform:T(n.platform||navigator.platform||``),highEntropy:i},quality:i?.95:.7,stability:.75,entropyCategory:`medium`})}};function re(e){return e.find(e=>{let t=e.brand.toLowerCase();return t!==`not?a;brand`&&t!==`not a;brand`&&!t.includes(`not:`)})??e[0]??null}var k=`mmmmmmmmmmlli`,A=`monospace`,j=[`Arial`,`Times New Roman`,`Courier New`,`Georgia`,`Verdana`,`Roboto`],M=class{name=`fonts`;async collect(e){if(l(e),typeof document>`u`||!document.body)throw Error(`document.body is not available`);let t=N(k,A),n=j.filter(e=>N(k,`${e}, ${A}`)!==t);return o({name:this.name,value:n,normalizedValue:[...n].sort(),quality:.7,stability:.8,entropyCategory:`high`})}};function N(e,t){let n=document.createElement(`span`);n.style.cssText=[`position:absolute`,`left:-9999px`,`top:0`,`visibility:hidden`,`white-space:nowrap`,`font:72px ${t}`].join(`;`),n.textContent=e,document.body.appendChild(n);let r=n.offsetWidth;return document.body.removeChild(n),r}var P=class{name=`navigator`;async collect(e){if(l(e),typeof navigator>`u`)throw Error(`navigator is not available`);let t=navigator.userAgent??``,n=navigator.platform??``,r=Array.isArray(navigator.languages)?[...navigator.languages]:[],i=navigator,a={userAgent:t,platform:n,language:navigator.language??``,languages:r,hardwareConcurrency:navigator.hardwareConcurrency??null,deviceMemory:typeof i.deviceMemory==`number`?i.deviceMemory:null,maxTouchPoints:navigator.maxTouchPoints??0,vendor:navigator.vendor??``},s=C(t),c=T(n||t);return o({name:this.name,value:a,normalizedValue:{browser:s,platform:c,hardwareConcurrency:a.hardwareConcurrency},quality:t.length>0?.9:.4,stability:.8,entropyCategory:`medium`})}},F=class{name=`screen`;async collect(e){l(e);let t=typeof screen>`u`?null:screen;if(!t)throw Error(`screen is not available`);let n=I(t.width),r=I(t.height),i={width:n,height:r,availWidth:I(t.availWidth),availHeight:I(t.availHeight),colorDepth:I(t.colorDepth),pixelDepth:I(t.pixelDepth),pixelRatio:I(typeof devicePixelRatio==`number`?devicePixelRatio:1)},a=E(n,r);return o({name:this.name,value:i,normalizedValue:{screenClass:a,width:n,height:r},quality:n>0&&r>0?.95:.4,stability:.7,entropyCategory:`low`})}};function I(e){return Number.isFinite(e)?e:0}var L=class{name=`timezone`;async collect(e){l(e);let t=`UTC`;try{t=Intl.DateTimeFormat().resolvedOptions().timeZone||`UTC`}catch{t=`UTC`}let n=new Date().getTimezoneOffset(),r={timeZone:t,offsetMinutes:n};return o({name:this.name,value:r,normalizedValue:t,quality:t.length>0?.99:.3,stability:.85,entropyCategory:`low`})}},R=class{name=`webgl`;async collect(e){if(l(e),typeof document>`u`)throw Error(`document is not available`);let t=document.createElement(`canvas`);t.width=1,t.height=1;let n=z(t);if(!n)throw Error(`WebGL is not available`);try{let e=n.getExtension(`WEBGL_debug_renderer_info`),t=B(n,e?e.UNMASKED_VENDOR_WEBGL:n.VENDOR),r=B(n,e?e.UNMASKED_RENDERER_WEBGL:n.RENDERER),a=await i([...n.getSupportedExtensions()??[]].sort().join(`,`)),s=n.getParameter(n.MAX_VIEWPORT_DIMS),c={maxTextureSize:V(n,n.MAX_TEXTURE_SIZE),maxViewportDims:Array.isArray(s)?[Number(s[0]),Number(s[1])]:s instanceof Int32Array?[s[0]??0,s[1]??0]:null,maxRenderbufferSize:V(n,n.MAX_RENDERBUFFER_SIZE),maxVertexAttribs:V(n,n.MAX_VERTEX_ATTRIBS),maxFragmentUniformVectors:V(n,n.MAX_FRAGMENT_UNIFORM_VECTORS)},l={vendor:t,renderer:r,extensionsHash:a,limits:c},u=typeof r==`string`&&r.length>0,d=u&&e?.88:u?.7:.45;return o({name:this.name,value:l,normalizedValue:{gpuFamily:D(t??``,r??``),extensionsHash:a,maxTextureSize:c.maxTextureSize},quality:d,stability:.95,entropyCategory:`high`})}finally{n.getExtension(`WEBGL_lose_context`)?.loseContext()}}};function z(e){let t={alpha:!0,antialias:!1,depth:!1,failIfMajorPerformanceCaveat:!1,preserveDrawingBuffer:!1};return e.getContext(`webgl`,t)||e.getContext(`experimental-webgl`,t)}function B(e,t){try{let n=e.getParameter(t);return typeof n==`string`&&n.length>0?n:null}catch{return null}}function V(e,t){try{let n=e.getParameter(t);return typeof n==`number`&&Number.isFinite(n)?n:null}catch{return null}}var H=`X-Previous-Debug-Token`;function U(){if(typeof document>`u`)return;let e=document.querySelector(`[id^="sfwdt"]`);if(!(e instanceof Element)||!e.id.startsWith(`sfwdt`))return;let t=e.id.slice(5);return t.length>0?t:void 0}async function W(e,t,n){try{let r={"Content-Type":`application/json`},i=U();i!==void 0&&(r[H]=i);let a=await fetch(e,{method:`POST`,credentials:`same-origin`,headers:r,body:JSON.stringify(t),signal:n});if(!a.ok)return null;let o=await a.text();if(o.trim().length===0)return{ok:!0};let s=JSON.parse(o);return typeof s!=`object`||!s?{ok:!0}:s}catch{return null}}var G=`1.0.0`,K=`/_device/collect`,q=1500,J=3600,Y={audio:!0,canvas:!0,webgl:!0,screen:!0,timezone:!0,navigator:!0,clientHints:!0,capabilities:!0,automation:!0,fonts:!1},ie=class{endpoint;timeout;cacheTtl;cacheEnabled;consent;cache=new t;collectors=[];constructor(e={}){this.endpoint=e.endpoint??K,this.timeout=oe(e.timeout),this.cacheEnabled=e.cache?.enabled??!0,this.cacheTtl=e.cache?.ttl??J,this.consent={highEntropy:e.consent?.highEntropy??!0},this.collectors=ae({...Y,...e.collectors})}async collect(){return this.runCollect(!1)}async refresh(){return this.runCollect(!0)}getCachedObservation(){return this.cache.get()}clear(){this.cache.clear()}registerCollector(e){this.collectors.push(e)}async runCollect(e){try{if(!e&&this.cacheEnabled){let e=this.cache.get();if(e)return e.result}let t=new AbortController,n=globalThis.setTimeout(()=>t.abort(),this.timeout),r={timeout:this.timeout,abortSignal:t.signal,consent:this.consent},i={};try{i=await this.collectSignals(r)}finally{globalThis.clearTimeout(n)}let a=this.collectors.length,o=Object.keys(i).length,s=ol.abort(),this.timeout),d=null;try{d=await W(this.endpoint,c,l.signal)}finally{globalThis.clearTimeout(u)}let f=d===null,p=o>0,m={ok:!f&&p&&d?.ok!==!1,degraded:!!d?.degraded||s||f||!p,signals:i};d?.new!==void 0&&(m.new=d.new),d?.token!==void 0&&(m.token=d.token),d?.expiresAt!==void 0&&(m.expiresAt=d.expiresAt),d?.deviceId!==void 0&&(m.deviceId=d.deviceId),d?.confidence!==void 0&&(m.confidence=d.confidence),d?.risk!==void 0&&(m.risk=d.risk),(f||!p)&&(m.ok=!1,m.degraded=!0);let h={timestamp:Date.now(),signals:i,result:m};return this.cacheEnabled&&this.cache.set(h,this.cacheTtl),m}catch{return{ok:!1,degraded:!0,signals:{}}}}async collectSignals(e){let t={},n=this.collectors.map(async n=>{try{let r=await c(n.collect(e),e.abortSignal);r&&typeof r.name==`string`&&(t[r.name]=r)}catch{}}),r=Promise.all(n),i=ce(this.timeout,e.abortSignal);return await Promise.race([r,i]),await Promise.allSettled(n),t}toPayload(e){let t={};for(let[n,r]of Object.entries(e))t[n]={value:r.value,quality:r.quality,collectedAt:r.collectedAt};return{v:1,sdkVersion:G,timestamp:Math.floor(Date.now()/1e3),nonce:se(),consent:this.consent,signals:t}}};function ae(e){let t=[];return e.navigator&&t.push(new P),e.clientHints&&t.push(new ne),e.screen&&t.push(new F),e.timezone&&t.push(new L),e.capabilities&&t.push(new b),e.automation&&t.push(new te),e.canvas&&t.push(new v),e.webgl&&t.push(new R),e.audio&&t.push(new p),e.fonts&&t.push(new M),t}function oe(e){return typeof e==`number`&&Number.isFinite(e)&&e>0?e:q}function se(){let e=new Uint8Array(16);if(globalThis.crypto?.getRandomValues)globalThis.crypto.getRandomValues(e);else for(let t=0;t{if(t.aborted){n();return}let r=globalThis.setTimeout(n,e);t.addEventListener(`abort`,()=>{globalThis.clearTimeout(r),n()},{once:!0})})}var X={script:`color:#0ea5e9;font-weight:bold`,debug:`color:#6b7280`,info:`color:#2563eb`,warn:`color:#d97706`,error:`color:#dc2626;font-weight:bold`},Z={script:`đŸ“Ļ`,debug:`🔍`,info:`â„šī¸`,warn:`âš ī¸`,error:`❌`};function le(e){return e.map(e=>typeof e==`object`&&e&&!(e instanceof Error)?JSON.stringify(e):e)}function ue(e,t){if(t!==void 0&&t!==``){console.log(`%c${Z.script} ${e} script loaded, build time: %c${t}`,X.script,`color:#059669`);return}console.log(`%c${Z.script} ${e} script loaded`,X.script)}function Q(e,t,n){let r=Z[e],i=X[e],a=`%c${r} ${t}`,o=console[e];if(n.length>0){o(a,i,...le(n));return}o(a,i)}function $(e,t,n){return(...r)=>{e()&&Q(n,t,r)}}function de(e,t={}){let n=`[${e}]`,{buildTime:r,alwaysLog:i=!1}=t,a=i===!0,o=a;return{scriptLoaded(){ue(n,r)},setDebug(e){o=a?!0:e},debug:$(()=>o,n,`debug`),info:$(()=>o,n,`info`),warn:$(()=>o,n,`warn`),error:$(()=>o,n,`error`)}}return de(`device-intelligence`,{buildTime:`2026-10-05T08:24:29.838Z`}).scriptLoaded(),e.DeviceIntelligence=ie,e.MemoryCache=t,e.SDK_VERSION=G,e.normalizeBrowser=C,e.normalizeGpuFamily=D,e.normalizePlatform=T,e.normalizeScreenClass=E,e})({});globalThis.DeviceIntelligence=DeviceIntelligence.DeviceIntelligence; //# sourceMappingURL=device-intelligence.min.js.map \ No newline at end of file diff --git a/src/Resources/public/js/device-intelligence.min.js.map b/src/Resources/public/js/device-intelligence.min.js.map index ade6c16..519ff16 100644 --- a/src/Resources/public/js/device-intelligence.min.js.map +++ b/src/Resources/public/js/device-intelligence.min.js.map @@ -1 +1 @@ -{"version":3,"file":"device-intelligence.min.js","names":[],"sources":["../../assets/src/cache/memory-cache.ts","../../assets/src/crypto/digest.ts","../../assets/src/collectors/collector.ts","../../assets/src/collectors/audio.ts","../../assets/src/collectors/automation.ts","../../assets/src/collectors/canvas.ts","../../assets/src/collectors/capabilities.ts","../../assets/src/normalization/normalize.ts","../../assets/src/collectors/client-hints.ts","../../assets/src/collectors/fonts.ts","../../assets/src/collectors/navigator.ts","../../assets/src/collectors/screen.ts","../../assets/src/collectors/timezone.ts","../../assets/src/collectors/webgl.ts","../../assets/src/transport/fetch-transport.ts","../../assets/src/version.ts","../../assets/src/client.ts","../../assets/src/logger.ts","../../assets/src/index.ts"],"sourcesContent":["/**\n * Process-local TTL cache. Not shared across tabs or origins.\n */\n\ninterface CacheEntry {\n value: T;\n expiresAt: number;\n}\n\n/**\n * In-memory cache with a per-entry TTL expressed in seconds.\n */\nexport class MemoryCache {\n private entry: CacheEntry | null = null;\n\n /**\n * Return the cached value when present and unexpired; otherwise `null`.\n */\n get(): T | null {\n if (this.entry === null) {\n return null;\n }\n if (Date.now() >= this.entry.expiresAt) {\n this.entry = null;\n return null;\n }\n return this.entry.value;\n }\n\n /**\n * Store `value` for `ttlSeconds`. A non-positive TTL is treated as already expired.\n */\n set(value: T, ttlSeconds: number): void {\n const ttlMs = ttlSeconds * 1000;\n this.entry = {\n value,\n expiresAt: Date.now() + ttlMs,\n };\n if (ttlMs <= 0) {\n this.entry = null;\n }\n }\n\n /** Drop the cached value immediately. */\n clear(): void {\n this.entry = null;\n }\n\n /** Whether a non-expired value is stored. */\n has(): boolean {\n return this.get() !== null;\n }\n}\n","/**\n * Compact WebCrypto digests. Never send raw high-entropy buffers.\n */\n\nconst HEX = 16;\n\n/**\n * SHA-256 hex digest of a string or binary payload.\n *\n * @param data - UTF-8 string or bytes\n * @returns Full 64-character lowercase hex digest\n */\nexport async function sha256Hex(data: string | BufferSource): Promise {\n const subtle = globalThis.crypto?.subtle;\n if (!subtle) {\n throw new Error('WebCrypto SubtleCrypto is not available');\n }\n\n const bytes = typeof data === 'string' ? new TextEncoder().encode(data) : data;\n const hash = await subtle.digest('SHA-256', bytes);\n const view = new Uint8Array(hash);\n let hex = '';\n for (let i = 0; i < view.length; i += 1) {\n hex += (view[i] ?? 0).toString(16).padStart(2, '0');\n }\n return hex;\n}\n\n/**\n * Truncated SHA-256 hex digest used as a compact fingerprint token.\n *\n * @param data - UTF-8 string or bytes\n * @param length - Number of hex characters to keep (default 16)\n */\nexport async function compactDigest(\n data: string | BufferSource,\n length: number = HEX,\n): Promise {\n const hex = await sha256Hex(data);\n return hex.slice(0, length);\n}\n","import type { CollectorContext, EntropyCategory, Signal } from '../types/index';\n\n/**\n * Clamp a numeric quality/stability score into `[0, 1]`.\n */\nexport function clamp01(value: number): number {\n if (!Number.isFinite(value)) {\n return 0;\n }\n if (value < 0) {\n return 0;\n }\n if (value > 1) {\n return 1;\n }\n return value;\n}\n\n/**\n * Build a {@link Signal} with clamped scores and a default timestamp.\n */\nexport function createSignal(input: {\n name: string;\n value: unknown;\n normalizedValue: unknown;\n quality: number;\n stability: number;\n entropyCategory: EntropyCategory;\n collectedAt?: number;\n}): Signal {\n return {\n name: input.name,\n value: input.value,\n normalizedValue: input.normalizedValue,\n quality: clamp01(input.quality),\n stability: clamp01(input.stability),\n entropyCategory: input.entropyCategory,\n collectedAt: input.collectedAt ?? Date.now(),\n };\n}\n\n/**\n * Reject when `signal` is already aborted or becomes aborted.\n */\nexport function rejectedWhenAborted(signal: AbortSignal): Promise {\n return new Promise((_resolve, reject) => {\n const abort = (): void => {\n reject(new DOMException('The operation was aborted.', 'AbortError'));\n };\n if (signal.aborted) {\n abort();\n return;\n }\n signal.addEventListener('abort', abort, { once: true });\n });\n}\n\n/**\n * Race a collector promise against the shared abort signal.\n */\nexport function raceAbort(promise: Promise, signal: AbortSignal): Promise {\n return Promise.race([promise, rejectedWhenAborted(signal)]);\n}\n\n/**\n * Throw when the collector context has already been cancelled.\n */\nexport function throwIfAborted(ctx: CollectorContext): void {\n if (ctx.abortSignal.aborted) {\n throw new DOMException('The operation was aborted.', 'AbortError');\n }\n}\n","import { compactDigest } from '../crypto/digest';\nimport type { Collector, CollectorContext, Signal } from '../types/index';\nimport { createSignal, raceAbort, throwIfAborted } from './collector';\n\ntype OfflineAudioContextCtor = new (\n numberOfChannels: number,\n length: number,\n sampleRate: number,\n) => OfflineAudioContext;\n\nconst SAMPLE_RATE = 44100;\nconst DURATION_SAMPLES = 44100;\nconst SNAPSHOT_BINS = 256;\n\n/**\n * WebAudio fingerprint using an offline graph only.\n *\n * Uses OfflineAudioContext + OscillatorNode + DynamicsCompressorNode.\n * Never calls `getUserMedia` and never touches the microphone.\n */\nexport class AudioCollector implements Collector {\n readonly name = 'audio';\n\n async collect(ctx: CollectorContext): Promise {\n throwIfAborted(ctx);\n\n const Ctor = resolveOfflineAudioContext();\n if (!Ctor) {\n throw new Error('OfflineAudioContext is not available');\n }\n\n const offline = new Ctor(1, DURATION_SAMPLES, SAMPLE_RATE);\n const oscillator = offline.createOscillator();\n oscillator.type = 'triangle';\n oscillator.frequency.value = 10000;\n\n const compressor = offline.createDynamicsCompressor();\n compressor.threshold.value = -50;\n compressor.knee.value = 40;\n compressor.ratio.value = 12;\n compressor.attack.value = 0;\n compressor.release.value = 0.25;\n\n oscillator.connect(compressor);\n compressor.connect(offline.destination);\n oscillator.start(0);\n\n const buffer = await raceAbort(offline.startRendering(), ctx.abortSignal);\n const channel = buffer.getChannelData(0);\n const snapshot = downsample(channel, SNAPSHOT_BINS);\n const digest = await compactDigest(snapshot.join(','));\n\n return createSignal({\n name: this.name,\n value: digest,\n normalizedValue: digest,\n quality: 0.85,\n stability: 0.9,\n entropyCategory: 'high',\n });\n }\n}\n\nfunction resolveOfflineAudioContext(): OfflineAudioContextCtor | null {\n const root = globalThis as typeof globalThis & {\n OfflineAudioContext?: OfflineAudioContextCtor;\n webkitOfflineAudioContext?: OfflineAudioContextCtor;\n };\n return root.OfflineAudioContext ?? root.webkitOfflineAudioContext ?? null;\n}\n\nfunction downsample(channel: Float32Array, bins: number): number[] {\n const step = Math.max(1, Math.floor(channel.length / bins));\n const values: number[] = [];\n for (let i = 0; i < channel.length && values.length < bins; i += step) {\n const sample = channel[i] ?? 0;\n values.push(Math.round(sample * 1_000_000));\n }\n return values;\n}\n","import type { Collector, CollectorContext, Signal } from '../types/index';\nimport { clamp01, createSignal, throwIfAborted } from './collector';\n\nexport interface AutomationValue {\n indicators: string[];\n confidence: number;\n}\n\nconst WEIGHTS: Record = {\n webdriver: 0.7,\n 'headless-ua': 0.6,\n 'missing-languages': 0.25,\n 'language-mismatch': 0.2,\n 'missing-hardware-concurrency': 0.2,\n 'implausible-hardware-concurrency': 0.25,\n 'zero-outer-size': 0.2,\n 'headless-chrome': 0.55,\n};\n\n/**\n * Automation heuristics. Returns indicators + confidence, never a boolean.\n */\nexport class AutomationCollector implements Collector {\n readonly name = 'automation';\n\n async collect(ctx: CollectorContext): Promise {\n throwIfAborted(ctx);\n\n const indicators: string[] = [];\n const nav = typeof navigator === 'undefined' ? null : navigator;\n const userAgent = nav?.userAgent ?? '';\n\n if (nav && nav.webdriver === true) {\n indicators.push('webdriver');\n }\n\n if (!nav || !Array.isArray(nav.languages) || nav.languages.length === 0) {\n indicators.push('missing-languages');\n } else if (nav.language && nav.languages[0] && nav.language !== nav.languages[0]) {\n indicators.push('language-mismatch');\n }\n\n if (!nav || typeof nav.hardwareConcurrency !== 'number') {\n indicators.push('missing-hardware-concurrency');\n } else if (nav.hardwareConcurrency <= 0 || nav.hardwareConcurrency > 128) {\n indicators.push('implausible-hardware-concurrency');\n }\n\n if (/headless/i.test(userAgent)) {\n indicators.push('headless-ua');\n }\n if (/HeadlessChrome/i.test(userAgent)) {\n indicators.push('headless-chrome');\n }\n\n if (typeof window !== 'undefined' && window.outerWidth === 0 && window.outerHeight === 0) {\n indicators.push('zero-outer-size');\n }\n\n const confidence = clamp01(\n indicators.reduce((sum, name) => sum + (WEIGHTS[name] ?? 0.15), 0),\n );\n\n const value: AutomationValue = {\n indicators,\n confidence,\n };\n\n return createSignal({\n name: this.name,\n value,\n normalizedValue: value,\n quality: 0.8,\n stability: 0.5,\n entropyCategory: 'low',\n });\n }\n}\n","import { compactDigest } from '../crypto/digest';\nimport type { Collector, CollectorContext, Signal } from '../types/index';\nimport { createSignal, throwIfAborted } from './collector';\n\nconst WIDTH = 280;\nconst HEIGHT = 80;\n\n/**\n * Deterministic 2D canvas scene. Pixels are digested locally; the image\n * is never sent to the server.\n */\nexport class CanvasCollector implements Collector {\n readonly name = 'canvas';\n\n async collect(ctx: CollectorContext): Promise {\n throwIfAborted(ctx);\n\n if (typeof document === 'undefined') {\n throw new Error('document is not available');\n }\n\n const canvas = document.createElement('canvas');\n canvas.width = WIDTH;\n canvas.height = HEIGHT;\n canvas.style.display = 'none';\n\n const context = canvas.getContext('2d', { willReadFrequently: true });\n if (!context) {\n throw new Error('CanvasRenderingContext2D is not available');\n }\n\n paintScene(context);\n\n const image = context.getImageData(0, 0, WIDTH, HEIGHT);\n const digest = await compactDigest(image.data);\n\n return createSignal({\n name: this.name,\n value: digest,\n normalizedValue: digest,\n quality: 0.92,\n stability: 0.95,\n entropyCategory: 'high',\n });\n }\n}\n\n/**\n * Fixed geometry: rectangles, the label \"DeviceIntelligence\", and arcs.\n */\nfunction paintScene(ctx: CanvasRenderingContext2D): void {\n ctx.fillStyle = '#f60';\n ctx.fillRect(8, 8, 90, 48);\n\n ctx.fillStyle = '#069';\n ctx.fillRect(108, 12, 70, 40);\n\n ctx.strokeStyle = '#111827';\n ctx.lineWidth = 2;\n ctx.beginPath();\n ctx.arc(220, 36, 26, 0, Math.PI * 2);\n ctx.stroke();\n\n ctx.beginPath();\n ctx.arc(248, 52, 14, 0.25 * Math.PI, 1.6 * Math.PI);\n ctx.stroke();\n\n ctx.fillStyle = '#111827';\n ctx.font = '16px Arial, sans-serif';\n ctx.textBaseline = 'top';\n ctx.fillText('DeviceIntelligence', 12, 58);\n\n ctx.fillStyle = 'rgba(16, 185, 129, 0.45)';\n ctx.fillRect(40, 20, 36, 18);\n}\n","import type { Collector, CollectorContext, Signal } from '../types/index';\nimport { createSignal, throwIfAborted } from './collector';\n\n/**\n * Boolean capability set used for Jaccard matching. Avoids expensive probes.\n */\nexport class CapabilitiesCollector implements Collector {\n readonly name = 'capabilities';\n\n async collect(ctx: CollectorContext): Promise {\n throwIfAborted(ctx);\n\n const nav = typeof navigator === 'undefined' ? null : navigator;\n const win = typeof window === 'undefined' ? null : window;\n\n const value = {\n cookieEnabled: nav?.cookieEnabled ?? false,\n pdfViewerEnabled: Boolean((nav as Navigator & { pdfViewerEnabled?: boolean } | null)?.pdfViewerEnabled),\n serviceWorker: Boolean(nav && 'serviceWorker' in nav),\n webgl: hasWebGl(),\n webgpu: Boolean(nav && 'gpu' in nav),\n wasm: typeof WebAssembly !== 'undefined',\n sharedArrayBuffer: typeof SharedArrayBuffer !== 'undefined',\n touch: (nav?.maxTouchPoints ?? 0) > 0,\n matchMedia: typeof win?.matchMedia === 'function',\n localStorage: hasStorage('localStorage'),\n sessionStorage: hasStorage('sessionStorage'),\n indexedDB: typeof indexedDB !== 'undefined',\n };\n\n const flags = Object.entries(value)\n .filter(([, enabled]) => enabled)\n .map(([key]) => key)\n .sort();\n\n return createSignal({\n name: this.name,\n value,\n normalizedValue: flags,\n quality: 0.9,\n stability: 0.9,\n entropyCategory: 'medium',\n });\n }\n}\n\nfunction hasWebGl(): boolean {\n if (typeof document === 'undefined') {\n return false;\n }\n // jsdom implements getContext but cannot create a GPU context and logs loudly.\n if (typeof navigator !== 'undefined' && /jsdom/i.test(navigator.userAgent)) {\n return false;\n }\n try {\n const canvas = document.createElement('canvas');\n return Boolean(canvas.getContext('webgl') || canvas.getContext('experimental-webgl'));\n } catch {\n return false;\n }\n}\n\nfunction hasStorage(name: 'localStorage' | 'sessionStorage'): boolean {\n try {\n const storage = globalThis[name];\n const key = '__di_cap__';\n storage.setItem(key, '1');\n storage.removeItem(key);\n return true;\n } catch {\n return false;\n }\n}\n","/**\n * Client-side normalizers. Output is family + major, never a full version string.\n */\n\nexport type PlatformFamily = 'windows' | 'macos' | 'linux' | 'ios' | 'android' | 'other';\n\nexport type ScreenClass = 'mobile-s' | 'mobile-l' | 'tablet' | 'hd' | 'qhd' | 'uhd' | 'other';\n\nexport type GpuFamily = 'apple' | 'intel' | 'nvidia' | 'amd' | 'mali' | 'adreno' | 'other';\n\n/**\n * Normalize a user-agent or \"Family x.y.z\" label to `Family `.\n *\n * @example\n * normalizeBrowser('Chrome 143.0.7312.58') // 'Chrome 143'\n * normalizeBrowser('... Chrome/143.0.7312.58 Safari/537.36') // 'Chrome 143'\n */\nexport function normalizeBrowser(input: string): string {\n const text = input.trim();\n if (text.length === 0) {\n return 'other';\n }\n\n if (/Edg(?:e|A|iOS)?\\/|\\bEdge\\//i.test(text) || /^Edge\\s/i.test(text)) {\n return labeledFamily(text, 'Edge', /(?:Edg(?:e|A|iOS)?|Edge)[/\\s](\\d+)/i);\n }\n\n if (/\\bOPR\\/|\\bOpera\\//i.test(text) || /^Opera\\s/i.test(text)) {\n return labeledFamily(text, 'Opera', /(?:OPR|Opera)[/\\s](\\d+)/i);\n }\n\n if (/\\bFirefox\\/|\\bFxiOS\\//i.test(text) || /^Firefox\\s/i.test(text)) {\n return labeledFamily(text, 'Firefox', /(?:Firefox|FxiOS)[/\\s](\\d+)/i);\n }\n\n if (/^Chrome\\s+\\d+/i.test(text)) {\n return labeledFamily(text, 'Chrome', /^Chrome\\s+(\\d+)/i);\n }\n\n const isSafari =\n /\\bSafari\\//i.test(text) &&\n /\\bVersion\\//i.test(text) &&\n !/\\b(Chrome|Chromium|CriOS|Edg|OPR)\\b/i.test(text);\n if (isSafari || /^Safari\\s/i.test(text)) {\n return labeledFamily(text, 'Safari', /(?:Version|Safari)[/\\s](\\d+)/i);\n }\n\n if (/\\b(Chrome|Chromium|CriOS)\\//i.test(text)) {\n return labeledFamily(text, 'Chrome', /(?:Chrome|Chromium|CriOS)\\/(\\d+)/i);\n }\n\n return 'other';\n}\n\nfunction labeledFamily(text: string, family: string, majorPattern: RegExp): string {\n const match = text.match(majorPattern);\n const major = match?.[1];\n return major ? `${family} ${major}` : family;\n}\n\n/**\n * Map a platform / oscpu / UA-CH platform string to a lowercase family.\n */\nexport function normalizePlatform(input: string): PlatformFamily {\n const value = input.toLowerCase();\n if (value.includes('win')) {\n return 'windows';\n }\n if (value.includes('android')) {\n return 'android';\n }\n if (\n value.includes('iphone') ||\n value.includes('ipad') ||\n value.includes('ipod') ||\n value.includes('ios')\n ) {\n return 'ios';\n }\n if (value.includes('mac') || value.includes('darwin')) {\n return 'macos';\n }\n if (value.includes('linux') || value.includes('x11') || value.includes('cros')) {\n return 'linux';\n }\n return 'other';\n}\n\n/**\n * Classify a viewport/screen by its largest dimension in CSS pixels.\n *\n * - `mobile-s` ≤ 480\n * - `mobile-l` ≤ 767\n * - `tablet` ≤ 1280\n * - `hd` ≤ 1920\n * - `qhd` ≤ 2560\n * - `uhd` ≤ 3840\n * - `other` otherwise (including non-finite values)\n */\nexport function normalizeScreenClass(width: number, height: number): ScreenClass {\n const max = Math.max(width, height);\n if (!Number.isFinite(max) || max <= 0) {\n return 'other';\n }\n if (max <= 480) {\n return 'mobile-s';\n }\n if (max <= 767) {\n return 'mobile-l';\n }\n if (max <= 1280) {\n return 'tablet';\n }\n if (max <= 1920) {\n return 'hd';\n }\n if (max <= 2560) {\n return 'qhd';\n }\n if (max <= 3840) {\n return 'uhd';\n }\n return 'other';\n}\n\n/**\n * Coarse GPU vendor family from WebGL vendor/renderer strings.\n */\nexport function normalizeGpuFamily(vendor: string, renderer: string): GpuFamily {\n const text = `${vendor} ${renderer}`.toLowerCase();\n if (text.includes('apple') || text.includes('metal')) {\n return 'apple';\n }\n if (text.includes('nvidia') || text.includes('geforce') || text.includes('quadro')) {\n return 'nvidia';\n }\n if (text.includes('amd') || text.includes('radeon') || text.includes('ati')) {\n return 'amd';\n }\n if (text.includes('intel')) {\n return 'intel';\n }\n if (text.includes('mali')) {\n return 'mali';\n }\n if (text.includes('adreno')) {\n return 'adreno';\n }\n return 'other';\n}\n","import { normalizeBrowser, normalizePlatform } from '../normalization/normalize';\nimport type { Collector, CollectorContext, NavigatorUADataLike, Signal } from '../types/index';\nimport { createSignal, raceAbort, throwIfAborted } from './collector';\n\nconst HIGH_ENTROPY_HINTS = [\n 'architecture',\n 'bitness',\n 'model',\n 'platformVersion',\n 'uaFullVersion',\n 'fullVersionList',\n] as const;\n\n/**\n * JS User-Agent Client Hints. Never the sole identity source; quality drops\n * when high-entropy values are denied or unavailable.\n */\nexport class ClientHintsCollector implements Collector {\n readonly name = 'client_hints';\n\n async collect(ctx: CollectorContext): Promise {\n throwIfAborted(ctx);\n\n if (typeof navigator === 'undefined') {\n throw new Error('navigator is not available');\n }\n\n const uaData = (navigator as Navigator & { userAgentData?: NavigatorUADataLike }).userAgentData;\n\n if (!uaData) {\n return createSignal({\n name: this.name,\n value: {\n brands: [],\n mobile: null,\n platform: '',\n highEntropy: false,\n available: false,\n },\n normalizedValue: {\n browser: normalizeBrowser(navigator.userAgent ?? ''),\n platform: normalizePlatform(navigator.platform ?? navigator.userAgent ?? ''),\n highEntropy: false,\n },\n quality: 0.35,\n stability: 0.7,\n entropyCategory: 'medium',\n });\n }\n\n const base = {\n brands: Array.isArray(uaData.brands) ? uaData.brands : [],\n mobile: typeof uaData.mobile === 'boolean' ? uaData.mobile : null,\n platform: uaData.platform ?? '',\n highEntropy: false,\n available: true,\n };\n\n let highEntropy: Record = {};\n let gotHighEntropy = false;\n\n if (ctx.consent.highEntropy && typeof uaData.getHighEntropyValues === 'function') {\n try {\n highEntropy = await raceAbort(\n uaData.getHighEntropyValues([...HIGH_ENTROPY_HINTS]),\n ctx.abortSignal,\n );\n gotHighEntropy = true;\n } catch {\n gotHighEntropy = false;\n }\n }\n\n const value = {\n ...base,\n ...highEntropy,\n highEntropy: gotHighEntropy,\n };\n\n const brandLabel = firstBrand(base.brands);\n const versionHint =\n typeof highEntropy['uaFullVersion'] === 'string'\n ? String(highEntropy['uaFullVersion'])\n : brandLabel?.version ?? '';\n const browserInput = brandLabel\n ? `${brandLabel.brand} ${versionHint}`\n : navigator.userAgent;\n\n return createSignal({\n name: this.name,\n value,\n normalizedValue: {\n browser: normalizeBrowser(browserInput),\n platform: normalizePlatform(base.platform || navigator.platform || ''),\n highEntropy: gotHighEntropy,\n },\n quality: gotHighEntropy ? 0.95 : 0.7,\n stability: 0.75,\n entropyCategory: 'medium',\n });\n }\n}\n\nfunction firstBrand(brands: Array<{ brand: string; version: string }>): {\n brand: string;\n version: string;\n} | null {\n const preferred = brands.find((item) => {\n const brand = item.brand.toLowerCase();\n return brand !== 'not?a;brand' && brand !== 'not a;brand' && !brand.includes('not:');\n });\n return preferred ?? brands[0] ?? null;\n}\n","import type { Collector, CollectorContext, Signal } from '../types/index';\nimport { createSignal, throwIfAborted } from './collector';\n\nconst SAMPLE = 'mmmmmmmmmmlli';\nconst BASELINE = 'monospace';\nconst CANDIDATES = ['Arial', 'Times New Roman', 'Courier New', 'Georgia', 'Verdana', 'Roboto'];\n\n/**\n * Cheap width-based font probe. Disabled by default (Level 3 / high entropy).\n */\nexport class FontsCollector implements Collector {\n readonly name = 'fonts';\n\n async collect(ctx: CollectorContext): Promise {\n throwIfAborted(ctx);\n\n if (typeof document === 'undefined' || !document.body) {\n throw new Error('document.body is not available');\n }\n\n const baseline = measureWidth(SAMPLE, BASELINE);\n const detected = CANDIDATES.filter((font) => {\n const width = measureWidth(SAMPLE, `${font}, ${BASELINE}`);\n return width !== baseline;\n });\n\n return createSignal({\n name: this.name,\n value: detected,\n normalizedValue: [...detected].sort(),\n quality: 0.7,\n stability: 0.8,\n entropyCategory: 'high',\n });\n }\n}\n\nfunction measureWidth(text: string, fontFamily: string): number {\n const span = document.createElement('span');\n span.style.cssText = [\n 'position:absolute',\n 'left:-9999px',\n 'top:0',\n 'visibility:hidden',\n 'white-space:nowrap',\n `font:72px ${fontFamily}`,\n ].join(';');\n span.textContent = text;\n document.body.appendChild(span);\n const width = span.offsetWidth;\n document.body.removeChild(span);\n return width;\n}\n","import { normalizeBrowser, normalizePlatform } from '../normalization/normalize';\nimport type { Collector, CollectorContext, Signal } from '../types/index';\nimport { createSignal, throwIfAborted } from './collector';\n\n/**\n * Compact navigator snapshot (Level 1). No high-entropy Client Hints here.\n */\nexport class NavigatorCollector implements Collector {\n readonly name = 'navigator';\n\n async collect(ctx: CollectorContext): Promise {\n throwIfAborted(ctx);\n\n if (typeof navigator === 'undefined') {\n throw new Error('navigator is not available');\n }\n\n const userAgent = navigator.userAgent ?? '';\n const platform = navigator.platform ?? '';\n const languages = Array.isArray(navigator.languages) ? [...navigator.languages] : [];\n const nav = navigator as Navigator & { deviceMemory?: number };\n\n const value = {\n userAgent,\n platform,\n language: navigator.language ?? '',\n languages,\n hardwareConcurrency: navigator.hardwareConcurrency ?? null,\n deviceMemory: typeof nav.deviceMemory === 'number' ? nav.deviceMemory : null,\n maxTouchPoints: navigator.maxTouchPoints ?? 0,\n vendor: navigator.vendor ?? '',\n };\n\n const browser = normalizeBrowser(userAgent);\n const platformFamily = normalizePlatform(platform || userAgent);\n\n return createSignal({\n name: this.name,\n value,\n normalizedValue: {\n browser,\n platform: platformFamily,\n hardwareConcurrency: value.hardwareConcurrency,\n },\n quality: userAgent.length > 0 ? 0.9 : 0.4,\n stability: 0.8,\n entropyCategory: 'medium',\n });\n }\n}\n","import { normalizeScreenClass } from '../normalization/normalize';\nimport type { Collector, CollectorContext, Signal } from '../types/index';\nimport { createSignal, throwIfAborted } from './collector';\n\n/**\n * Screen geometry and color depth. Window size is omitted (too volatile).\n */\nexport class ScreenCollector implements Collector {\n readonly name = 'screen';\n\n async collect(ctx: CollectorContext): Promise {\n throwIfAborted(ctx);\n\n const screenRef = typeof screen === 'undefined' ? null : screen;\n if (!screenRef) {\n throw new Error('screen is not available');\n }\n\n const width = finiteOrZero(screenRef.width);\n const height = finiteOrZero(screenRef.height);\n const value = {\n width,\n height,\n availWidth: finiteOrZero(screenRef.availWidth),\n availHeight: finiteOrZero(screenRef.availHeight),\n colorDepth: finiteOrZero(screenRef.colorDepth),\n pixelDepth: finiteOrZero(screenRef.pixelDepth),\n pixelRatio: finiteOrZero(typeof devicePixelRatio === 'number' ? devicePixelRatio : 1),\n };\n\n const screenClass = normalizeScreenClass(width, height);\n\n return createSignal({\n name: this.name,\n value,\n normalizedValue: {\n screenClass,\n width,\n height,\n },\n quality: width > 0 && height > 0 ? 0.95 : 0.4,\n stability: 0.7,\n entropyCategory: 'low',\n });\n }\n}\n\nfunction finiteOrZero(value: number): number {\n return Number.isFinite(value) ? value : 0;\n}\n","import type { Collector, CollectorContext, Signal } from '../types/index';\nimport { createSignal, throwIfAborted } from './collector';\n\n/**\n * IANA timezone and UTC offset. Offset is informational; identity uses the name.\n */\nexport class TimezoneCollector implements Collector {\n readonly name = 'timezone';\n\n async collect(ctx: CollectorContext): Promise {\n throwIfAborted(ctx);\n\n let timeZone = 'UTC';\n try {\n timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone || 'UTC';\n } catch {\n timeZone = 'UTC';\n }\n\n const offsetMinutes = new Date().getTimezoneOffset();\n const value = {\n timeZone,\n offsetMinutes,\n };\n\n return createSignal({\n name: this.name,\n value,\n normalizedValue: timeZone,\n quality: timeZone.length > 0 ? 0.99 : 0.3,\n stability: 0.85,\n entropyCategory: 'low',\n });\n }\n}\n","import { compactDigest } from '../crypto/digest';\nimport { normalizeGpuFamily } from '../normalization/normalize';\nimport type { Collector, CollectorContext, Signal } from '../types/index';\nimport { createSignal, throwIfAborted } from './collector';\n\nexport interface WebGlValue {\n vendor: string | null;\n renderer: string | null;\n extensionsHash: string;\n limits: {\n maxTextureSize: number | null;\n maxViewportDims: number[] | null;\n maxRenderbufferSize: number | null;\n maxVertexAttribs: number | null;\n maxFragmentUniformVectors: number | null;\n };\n}\n\n/**\n * WebGL vendor/renderer (when unmasked), hashed extension set, and a few limits.\n * Does not assume `WEBGL_debug_renderer_info` is present.\n */\nexport class WebGlCollector implements Collector {\n readonly name = 'webgl';\n\n async collect(ctx: CollectorContext): Promise {\n throwIfAborted(ctx);\n\n if (typeof document === 'undefined') {\n throw new Error('document is not available');\n }\n\n const canvas = document.createElement('canvas');\n canvas.width = 1;\n canvas.height = 1;\n\n const gl = getWebGlContext(canvas);\n if (!gl) {\n throw new Error('WebGL is not available');\n }\n\n try {\n const debugInfo = gl.getExtension('WEBGL_debug_renderer_info');\n const vendor = readParameter(\n gl,\n debugInfo ? debugInfo.UNMASKED_VENDOR_WEBGL : gl.VENDOR,\n );\n const renderer = readParameter(\n gl,\n debugInfo ? debugInfo.UNMASKED_RENDERER_WEBGL : gl.RENDERER,\n );\n\n const extensions = gl.getSupportedExtensions() ?? [];\n const extensionsHash = await compactDigest([...extensions].sort().join(','));\n\n const maxViewport = gl.getParameter(gl.MAX_VIEWPORT_DIMS);\n const limits = {\n maxTextureSize: readNumeric(gl, gl.MAX_TEXTURE_SIZE),\n maxViewportDims: Array.isArray(maxViewport)\n ? [Number(maxViewport[0]), Number(maxViewport[1])]\n : maxViewport instanceof Int32Array\n ? [maxViewport[0] ?? 0, maxViewport[1] ?? 0]\n : null,\n maxRenderbufferSize: readNumeric(gl, gl.MAX_RENDERBUFFER_SIZE),\n maxVertexAttribs: readNumeric(gl, gl.MAX_VERTEX_ATTRIBS),\n maxFragmentUniformVectors: readNumeric(gl, gl.MAX_FRAGMENT_UNIFORM_VECTORS),\n };\n\n const value: WebGlValue = {\n vendor,\n renderer,\n extensionsHash,\n limits,\n };\n\n const hasRenderer = typeof renderer === 'string' && renderer.length > 0;\n const quality = hasRenderer && debugInfo ? 0.88 : hasRenderer ? 0.7 : 0.45;\n\n return createSignal({\n name: this.name,\n value,\n normalizedValue: {\n gpuFamily: normalizeGpuFamily(vendor ?? '', renderer ?? ''),\n extensionsHash,\n maxTextureSize: limits.maxTextureSize,\n },\n quality,\n stability: 0.95,\n entropyCategory: 'high',\n });\n } finally {\n const lose = gl.getExtension('WEBGL_lose_context');\n lose?.loseContext();\n }\n }\n}\n\nfunction getWebGlContext(canvas: HTMLCanvasElement): WebGLRenderingContext | null {\n const options: WebGLContextAttributes = {\n alpha: true,\n antialias: false,\n depth: false,\n failIfMajorPerformanceCaveat: false,\n preserveDrawingBuffer: false,\n };\n\n const standard = canvas.getContext('webgl', options);\n if (standard) {\n return standard;\n }\n\n return canvas.getContext('experimental-webgl', options) as WebGLRenderingContext | null;\n}\n\nfunction readParameter(gl: WebGLRenderingContext, pname: number): string | null {\n try {\n const value = gl.getParameter(pname);\n return typeof value === 'string' && value.length > 0 ? value : null;\n } catch {\n return null;\n }\n}\n\nfunction readNumeric(gl: WebGLRenderingContext, pname: number): number | null {\n try {\n const value = gl.getParameter(pname);\n return typeof value === 'number' && Number.isFinite(value) ? value : null;\n } catch {\n return null;\n }\n}\n","import type { CollectPayload, ServerCollectResponse } from '../types/index';\n\nconst PREVIOUS_DEBUG_TOKEN_HEADER = 'X-Previous-Debug-Token';\n\n/**\n * Token of the current HTML request's Web Debug Toolbar, if present.\n * Used so POST /_device/collect is stored as a child of that profiler profile.\n */\nexport function readProfilerPreviousToken(): string | undefined {\n if (typeof document === 'undefined') {\n return undefined;\n }\n const el = document.querySelector('[id^=\"sfwdt\"]');\n if (!(el instanceof Element) || !el.id.startsWith('sfwdt')) {\n return undefined;\n }\n const token = el.id.slice('sfwdt'.length);\n return token.length > 0 ? token : undefined;\n}\n\n/**\n * POST a collect payload. Never throws; returns `null` on any failure.\n *\n * @param endpoint - Same-origin collect URL\n * @param payload - Protocol v1 JSON body\n * @param abortSignal - Optional cancellation\n */\nexport async function postCollect(\n endpoint: string,\n payload: CollectPayload,\n abortSignal?: AbortSignal,\n): Promise {\n try {\n const headers: Record = {\n 'Content-Type': 'application/json',\n };\n const previousToken = readProfilerPreviousToken();\n if (previousToken !== undefined) {\n headers[PREVIOUS_DEBUG_TOKEN_HEADER] = previousToken;\n }\n\n const response = await fetch(endpoint, {\n method: 'POST',\n credentials: 'same-origin',\n headers,\n body: JSON.stringify(payload),\n signal: abortSignal,\n });\n\n if (!response.ok) {\n return null;\n }\n\n const text = await response.text();\n if (text.trim().length === 0) {\n return { ok: true };\n }\n\n const parsed: unknown = JSON.parse(text);\n if (parsed === null || typeof parsed !== 'object') {\n return { ok: true };\n }\n\n return parsed as ServerCollectResponse;\n } catch {\n return null;\n }\n}\n","/**\n * SDK protocol/semver identifier sent on every collect request.\n * Collect protocol identifier sent on every collect request (`v: 1` remains the schema).\n */\nexport const SDK_VERSION = '1.0.0';\n","import { MemoryCache } from './cache/memory-cache';\nimport { AudioCollector } from './collectors/audio';\nimport { AutomationCollector } from './collectors/automation';\nimport { CanvasCollector } from './collectors/canvas';\nimport { CapabilitiesCollector } from './collectors/capabilities';\nimport { ClientHintsCollector } from './collectors/client-hints';\nimport { raceAbort } from './collectors/collector';\nimport { FontsCollector } from './collectors/fonts';\nimport { NavigatorCollector } from './collectors/navigator';\nimport { ScreenCollector } from './collectors/screen';\nimport { TimezoneCollector } from './collectors/timezone';\nimport { WebGlCollector } from './collectors/webgl';\nimport { postCollect } from './transport/fetch-transport';\nimport type {\n CachedObservation,\n CollectPayload,\n CollectResult,\n CollectSignalWire,\n Collector,\n CollectorContext,\n CollectorsConfig,\n DeviceIntelligenceOptions,\n EnhancementLevel,\n Signal,\n} from './types/index';\nimport { SDK_VERSION } from './version';\n\nconst DEFAULT_ENDPOINT = '/_device/collect';\nconst DEFAULT_TIMEOUT_MS = 1500;\nconst DEFAULT_CACHE_TTL = 3600;\n\nconst DEFAULT_COLLECTORS: Required = {\n audio: true,\n canvas: true,\n webgl: true,\n screen: true,\n timezone: true,\n navigator: true,\n clientHints: true,\n capabilities: true,\n automation: true,\n fonts: false,\n};\n\nconst COLLECTOR_LEVELS: Record = {\n navigator: 1,\n client_hints: 1,\n screen: 1,\n timezone: 1,\n capabilities: 1,\n automation: 3,\n canvas: 2,\n webgl: 2,\n audio: 3,\n fonts: 3,\n};\n\n/**\n * Browser Device Intelligence client.\n *\n * `collect()` never throws into application code. Failures resolve to\n * `{ ok: false, degraded: true }` and omit the failing collector.\n */\nexport class DeviceIntelligence {\n private readonly endpoint: string;\n private readonly timeout: number;\n private readonly cacheTtl: number;\n private readonly cacheEnabled: boolean;\n private readonly consent: { highEntropy: boolean };\n private readonly cache = new MemoryCache();\n private readonly collectors: Collector[] = [];\n\n /**\n * @param options - Optional endpoint, collector flags, cache, and timeout\n */\n constructor(options: DeviceIntelligenceOptions = {}) {\n this.endpoint = options.endpoint ?? DEFAULT_ENDPOINT;\n this.timeout = positiveTimeout(options.timeout);\n this.cacheEnabled = options.cache?.enabled ?? true;\n this.cacheTtl = options.cache?.ttl ?? DEFAULT_CACHE_TTL;\n this.consent = {\n highEntropy: options.consent?.highEntropy ?? true,\n };\n this.collectors = createBuiltInCollectors({\n ...DEFAULT_COLLECTORS,\n ...options.collectors,\n });\n }\n\n /**\n * Collect enabled signals and POST them to the configured endpoint.\n * Returns a cached observation when the TTL is still valid.\n *\n * @returns Collect result; never rejects — failures set `ok: false` and `degraded: true`.\n */\n async collect(): Promise {\n return this.runCollect(false);\n }\n\n /**\n * Force a new collection, ignoring any cached observation.\n *\n * @returns Collect result; never rejects.\n */\n async refresh(): Promise {\n return this.runCollect(true);\n }\n\n /**\n * Last cached observation, or `null` when empty / expired.\n */\n getCachedObservation(): CachedObservation | null {\n return this.cache.get();\n }\n\n /** Drop the in-memory cache. */\n clear(): void {\n this.cache.clear();\n }\n\n /**\n * Register an additional collector. It runs on the next `collect()` / `refresh()`.\n *\n * @param collector Collector implementation with `name` and `collect()`.\n */\n registerCollector(collector: Collector): void {\n this.collectors.push(collector);\n }\n\n private async runCollect(forceRefresh: boolean): Promise {\n try {\n if (!forceRefresh && this.cacheEnabled) {\n const cached = this.cache.get();\n if (cached) {\n return cached.result;\n }\n }\n\n const controller = new AbortController();\n const timer = globalThis.setTimeout(() => controller.abort(), this.timeout);\n const ctx: CollectorContext = {\n timeout: this.timeout,\n abortSignal: controller.signal,\n consent: this.consent,\n };\n\n let signals: Record = {};\n try {\n signals = await this.collectSignals(ctx);\n } finally {\n globalThis.clearTimeout(timer);\n }\n\n const enabledCount = this.collectors.length;\n const collectedCount = Object.keys(signals).length;\n const collectorsDegraded = collectedCount < enabledCount;\n\n const payload = this.toPayload(signals);\n const transportController = new AbortController();\n const transportTimer = globalThis.setTimeout(\n () => transportController.abort(),\n this.timeout,\n );\n\n let server = null;\n try {\n server = await postCollect(this.endpoint, payload, transportController.signal);\n } finally {\n globalThis.clearTimeout(transportTimer);\n }\n\n const transportFailed = server === null;\n const hasSignals = collectedCount > 0;\n const result: CollectResult = {\n ok: !transportFailed && hasSignals && server?.ok !== false,\n degraded: Boolean(server?.degraded) || collectorsDegraded || transportFailed || !hasSignals,\n signals,\n };\n\n if (server?.new !== undefined) {\n result.new = server.new;\n }\n if (server?.token !== undefined) {\n result.token = server.token;\n }\n if (server?.expiresAt !== undefined) {\n result.expiresAt = server.expiresAt;\n }\n if (server?.deviceId !== undefined) {\n result.deviceId = server.deviceId;\n }\n if (server?.confidence !== undefined) {\n result.confidence = server.confidence;\n }\n if (server?.risk !== undefined) {\n result.risk = server.risk;\n }\n\n if (transportFailed || !hasSignals) {\n result.ok = false;\n result.degraded = true;\n }\n\n const observation: CachedObservation = {\n timestamp: Date.now(),\n signals,\n result,\n };\n\n if (this.cacheEnabled) {\n this.cache.set(observation, this.cacheTtl);\n }\n\n return result;\n } catch {\n return { ok: false, degraded: true, signals: {} };\n }\n }\n\n /**\n * Run collectors in parallel. Each collector is raced against the shared\n * AbortSignal. Level-1 results are preferred if Level 2/3 still pending\n * when the timeout fires.\n */\n private async collectSignals(ctx: CollectorContext): Promise> {\n const signals: Record = {};\n const jobs = this.collectors.map(async (collector) => {\n try {\n const signal = await raceAbort(collector.collect(ctx), ctx.abortSignal);\n if (signal && typeof signal.name === 'string') {\n signals[signal.name] = signal;\n }\n } catch {\n // Omit failed / timed-out collectors.\n }\n });\n\n const allSettled = Promise.all(jobs);\n const timeoutDone = sleep(this.timeout, ctx.abortSignal);\n\n await Promise.race([allSettled, timeoutDone]);\n await Promise.allSettled(jobs);\n\n return signals;\n }\n\n private toPayload(signals: Record): CollectPayload {\n const wire: Record = {};\n for (const [name, signal] of Object.entries(signals)) {\n wire[name] = {\n value: signal.value,\n quality: signal.quality,\n collectedAt: signal.collectedAt,\n };\n }\n\n return {\n v: 1,\n sdkVersion: SDK_VERSION,\n timestamp: Math.floor(Date.now() / 1000),\n nonce: createNonce(),\n consent: this.consent,\n signals: wire,\n };\n }\n}\n\nfunction createBuiltInCollectors(enabled: Required): Collector[] {\n const list: Collector[] = [];\n if (enabled.navigator) {\n list.push(new NavigatorCollector());\n }\n if (enabled.clientHints) {\n list.push(new ClientHintsCollector());\n }\n if (enabled.screen) {\n list.push(new ScreenCollector());\n }\n if (enabled.timezone) {\n list.push(new TimezoneCollector());\n }\n if (enabled.capabilities) {\n list.push(new CapabilitiesCollector());\n }\n if (enabled.automation) {\n list.push(new AutomationCollector());\n }\n if (enabled.canvas) {\n list.push(new CanvasCollector());\n }\n if (enabled.webgl) {\n list.push(new WebGlCollector());\n }\n if (enabled.audio) {\n list.push(new AudioCollector());\n }\n if (enabled.fonts) {\n list.push(new FontsCollector());\n }\n return list;\n}\n\nfunction positiveTimeout(value: number | undefined): number {\n if (typeof value === 'number' && Number.isFinite(value) && value > 0) {\n return value;\n }\n return DEFAULT_TIMEOUT_MS;\n}\n\nfunction createNonce(): string {\n const bytes = new Uint8Array(16);\n if (globalThis.crypto?.getRandomValues) {\n globalThis.crypto.getRandomValues(bytes);\n } else {\n for (let i = 0; i < bytes.length; i += 1) {\n bytes[i] = Math.floor(Math.random() * 256);\n }\n }\n let hex = '';\n for (let i = 0; i < bytes.length; i += 1) {\n hex += (bytes[i] ?? 0).toString(16).padStart(2, '0');\n }\n return hex;\n}\n\nfunction sleep(ms: number, signal: AbortSignal): Promise {\n return new Promise((resolve) => {\n if (signal.aborted) {\n resolve();\n return;\n }\n const id = globalThis.setTimeout(resolve, ms);\n signal.addEventListener(\n 'abort',\n () => {\n globalThis.clearTimeout(id);\n resolve();\n },\n { once: true },\n );\n });\n}\n\n/** @internal Exported for tests that need collector level metadata. */\nexport function collectorLevel(name: string): EnhancementLevel {\n return COLLECTOR_LEVELS[name] ?? 2;\n}\n","/**\n * Bundle logger for Device Intelligence (same API as other Nowo bundles).\n *\n * `scriptLoaded()` always logs. `debug` / `info` / `warn` / `error` require\n * `setDebug(true)` unless `alwaysLog` is set.\n */\n\nexport type BundleLoggerOptions = {\n /** If set, scriptLoaded() includes this (Vite injects compile time). */\n buildTime?: string;\n /** When true, debug/info/warn/error always output. */\n alwaysLog?: boolean;\n};\n\nexport type BundleLogger = {\n /** Call once at startup. Logs \"script loaded\" and optional build time. */\n scriptLoaded: () => void;\n setDebug: (enabled: boolean) => void;\n debug: (...args: unknown[]) => void;\n info: (...args: unknown[]) => void;\n warn: (...args: unknown[]) => void;\n error: (...args: unknown[]) => void;\n};\n\nconst STYLES = {\n script: 'color:#0ea5e9;font-weight:bold',\n debug: 'color:#6b7280',\n info: 'color:#2563eb',\n warn: 'color:#d97706',\n error: 'color:#dc2626;font-weight:bold',\n} as const;\n\nconst EMOJI = {\n script: 'đŸ“Ļ',\n debug: '🔍',\n info: 'â„šī¸',\n warn: 'âš ī¸',\n error: '❌',\n} as const;\n\nfunction formatArgs(args: unknown[]): unknown[] {\n return args.map((a) =>\n typeof a === 'object' && a !== null && !(a instanceof Error) ? JSON.stringify(a) : a,\n );\n}\n\ntype ConsoleLevel = 'debug' | 'info' | 'warn' | 'error';\n\nfunction logScriptLoaded(prefix: string, buildTime: string | undefined): void {\n if (buildTime !== undefined && buildTime !== '') {\n console.log(\n `%c${EMOJI.script} ${prefix} script loaded, build time: %c${buildTime}`,\n STYLES.script,\n 'color:#059669',\n );\n return;\n }\n console.log(`%c${EMOJI.script} ${prefix} script loaded`, STYLES.script);\n}\n\nfunction emitLevelLog(level: ConsoleLevel, prefix: string, args: unknown[]): void {\n const emoji = EMOJI[level];\n const style = STYLES[level];\n const label = `%c${emoji} ${prefix}`;\n const logFn = console[level] as (...fnArgs: unknown[]) => void;\n if (args.length > 0) {\n logFn(label, style, ...formatArgs(args));\n return;\n }\n logFn(label, style);\n}\n\nfunction makeLevelMethod(\n isEnabled: () => boolean,\n prefix: string,\n level: ConsoleLevel,\n): (...args: unknown[]) => void {\n return (...args: unknown[]): void => {\n if (!isEnabled()) {\n return;\n }\n emitLevelLog(level, prefix, args);\n };\n}\n\nfunction noop(): void {}\n\nlet instance: BundleLogger | null = null;\n\n/**\n * Registers the bundle logger. Call once from the entry after createBundleLogger.\n *\n * @param log - Logger instance to register\n */\nexport function setBundleLogger(log: BundleLogger): void {\n instance = log;\n}\n\n/**\n * Clears the registered logger (tests only).\n */\nexport function clearBundleLoggerForTest(): void {\n instance = null;\n}\n\n/**\n * Returns the bundle logger, or a no-op logger when none is registered.\n *\n * @returns The registered logger or a silent fallback\n */\nexport function getLogger(): BundleLogger {\n if (instance !== null) {\n return instance;\n }\n return {\n scriptLoaded: noop,\n setDebug: noop,\n debug: noop,\n info: noop,\n warn: noop,\n error: noop,\n };\n}\n\n/**\n * Creates a Device Intelligence console logger.\n *\n * @param name - Short name for the log prefix (e.g. `device-intelligence`)\n * @param options - Optional buildTime and alwaysLog\n * @returns A BundleLogger\n */\nexport function createBundleLogger(name: string, options: BundleLoggerOptions = {}): BundleLogger {\n const prefix = `[${name}]`;\n const { buildTime, alwaysLog = false } = options;\n const logAlways = alwaysLog === true;\n let debugEnabled = logAlways;\n\n return {\n scriptLoaded(): void {\n logScriptLoaded(prefix, buildTime);\n },\n\n setDebug(enabled: boolean): void {\n debugEnabled = logAlways ? true : enabled;\n },\n\n debug: makeLevelMethod(() => debugEnabled, prefix, 'debug'),\n info: makeLevelMethod(() => debugEnabled, prefix, 'info'),\n warn: makeLevelMethod(() => debugEnabled, prefix, 'warn'),\n error: makeLevelMethod(() => debugEnabled, prefix, 'error'),\n };\n}\n","/**\n * Browser Device Intelligence client (shipped as Composer package assets).\n *\n * Collects compact, privacy-aware signals and POSTs them to a same-origin\n * collect endpoint. `collect()` never throws.\n */\n\nimport { DeviceIntelligence } from './client';\nimport { createBundleLogger, setBundleLogger } from './logger';\n\ndeclare const __DEVICE_INTELLIGENCE_BUILD_TIME__: string;\n\nconst log = createBundleLogger('device-intelligence', {\n buildTime:\n typeof __DEVICE_INTELLIGENCE_BUILD_TIME__ !== 'undefined'\n ? __DEVICE_INTELLIGENCE_BUILD_TIME__\n : undefined,\n});\nlog.scriptLoaded();\nsetBundleLogger(log);\n\nexport { DeviceIntelligence };\nexport { MemoryCache } from './cache/memory-cache';\nexport { SDK_VERSION } from './version';\nexport {\n normalizeBrowser,\n normalizeGpuFamily,\n normalizePlatform,\n normalizeScreenClass,\n} from './normalization/normalize';\n\nexport type { Collector } from './types/index';\nexport type { CollectorContext } from './types/index';\nexport type { Signal } from './types/index';\nexport type { DeviceIntelligenceOptions } from './types/index';\nexport type { CollectorsConfig } from './types/index';\nexport type { CacheConfig } from './types/index';\nexport type { CollectResult } from './types/index';\nexport type { CachedObservation } from './types/index';\nexport type { CollectPayload } from './types/index';\nexport type { EntropyCategory } from './types/index';\n"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"device-intelligence.min.js","names":["exports","MemoryCache","ttlMs","ttlSeconds","HEX","sha256Hex","subtle","bytes","data","hash","view","hex","i","compactDigest","length","clamp01","value","createSignal","input","rejectedWhenAborted","abort","reject","signal","raceAbort","promise","throwIfAborted","ctx","SAMPLE_RATE","DURATION_SAMPLES","SNAPSHOT_BINS","AudioCollector","Ctor","resolveOfflineAudioContext","offline","oscillator","compressor","digest","downsample","root","step","channel","bins","values","sample","WEIGHTS","AutomationCollector","indicators","nav","userAgent","sum","name","WIDTH","HEIGHT","CanvasCollector","canvas","context","paintScene","CapabilitiesCollector","win","hasWebGl","hasStorage","flags","enabled","key","storage","normalizeBrowser","text","labeledFamily","major","majorPattern","family","normalizePlatform","normalizeScreenClass","max","width","height","normalizeGpuFamily","vendor","renderer","HIGH_ENTROPY_HINTS","ClientHintsCollector","uaData","base","highEntropy","gotHighEntropy","brandLabel","firstBrand","versionHint","\"uaFullVersion\"","browserInput","brands","brand","item","SAMPLE","BASELINE","CANDIDATES","FontsCollector","baseline","measureWidth","detected","font","span","fontFamily","NavigatorCollector","platform","languages","browser","platformFamily","ScreenCollector","screenRef","finiteOrZero","screenClass","TimezoneCollector","timeZone","offsetMinutes","WebGlCollector","gl","getWebGlContext","debugInfo","readParameter","extensionsHash","maxViewport","limits","readNumeric","hasRenderer","quality","options","pname","PREVIOUS_DEBUG_TOKEN_HEADER","readProfilerPreviousToken","el","token","postCollect","headers","previousToken","response","endpoint","payload","abortSignal","parsed","SDK_VERSION","DEFAULT_ENDPOINT","DEFAULT_TIMEOUT_MS","DEFAULT_CACHE_TTL","DEFAULT_COLLECTORS","DeviceIntelligence","positiveTimeout","createBuiltInCollectors","collector","forceRefresh","cached","controller","timer","signals","enabledCount","collectedCount","collectorsDegraded","transportController","transportTimer","server","transportFailed","hasSignals","result","observation","jobs","allSettled","timeoutDone","sleep","wire","createNonce","list","resolve","id","ms","STYLES","EMOJI","formatArgs","args","a","logScriptLoaded","buildTime","prefix","emitLevelLog","emoji","level","style","label","logFn","makeLevelMethod","isEnabled","createBundleLogger","logAlways","alwaysLog","debugEnabled"],"sources":["../../assets/src/cache/memory-cache.ts","../../assets/src/crypto/digest.ts","../../assets/src/collectors/collector.ts","../../assets/src/collectors/audio.ts","../../assets/src/collectors/automation.ts","../../assets/src/collectors/canvas.ts","../../assets/src/collectors/capabilities.ts","../../assets/src/normalization/normalize.ts","../../assets/src/collectors/client-hints.ts","../../assets/src/collectors/fonts.ts","../../assets/src/collectors/navigator.ts","../../assets/src/collectors/screen.ts","../../assets/src/collectors/timezone.ts","../../assets/src/collectors/webgl.ts","../../assets/src/transport/fetch-transport.ts","../../assets/src/version.ts","../../assets/src/client.ts","../../assets/src/logger.ts","../../assets/src/index.ts"],"sourcesContent":["/**\n * Process-local TTL cache. Not shared across tabs or origins.\n */\n\ninterface CacheEntry {\n value: T;\n expiresAt: number;\n}\n\n/**\n * In-memory cache with a per-entry TTL expressed in seconds.\n */\nexport class MemoryCache {\n private entry: CacheEntry | null = null;\n\n /**\n * Return the cached value when present and unexpired; otherwise `null`.\n */\n get(): T | null {\n if (this.entry === null) {\n return null;\n }\n if (Date.now() >= this.entry.expiresAt) {\n this.entry = null;\n return null;\n }\n return this.entry.value;\n }\n\n /**\n * Store `value` for `ttlSeconds`. A non-positive TTL is treated as already expired.\n */\n set(value: T, ttlSeconds: number): void {\n const ttlMs = ttlSeconds * 1000;\n this.entry = {\n value,\n expiresAt: Date.now() + ttlMs,\n };\n if (ttlMs <= 0) {\n this.entry = null;\n }\n }\n\n /** Drop the cached value immediately. */\n clear(): void {\n this.entry = null;\n }\n\n /** Whether a non-expired value is stored. */\n has(): boolean {\n return this.get() !== null;\n }\n}\n","/**\n * Compact WebCrypto digests. Never send raw high-entropy buffers.\n */\n\nconst HEX = 16;\n\n/**\n * SHA-256 hex digest of a string or binary payload.\n *\n * @param data - UTF-8 string or bytes\n * @returns Full 64-character lowercase hex digest\n */\nexport async function sha256Hex(data: string | BufferSource): Promise {\n const subtle = globalThis.crypto?.subtle;\n if (!subtle) {\n throw new Error('WebCrypto SubtleCrypto is not available');\n }\n\n const bytes = typeof data === 'string' ? new TextEncoder().encode(data) : data;\n const hash = await subtle.digest('SHA-256', bytes);\n const view = new Uint8Array(hash);\n let hex = '';\n for (let i = 0; i < view.length; i += 1) {\n hex += (view[i] ?? 0).toString(16).padStart(2, '0');\n }\n return hex;\n}\n\n/**\n * Truncated SHA-256 hex digest used as a compact fingerprint token.\n *\n * @param data - UTF-8 string or bytes\n * @param length - Number of hex characters to keep (default 16)\n */\nexport async function compactDigest(\n data: string | BufferSource,\n length: number = HEX,\n): Promise {\n const hex = await sha256Hex(data);\n return hex.slice(0, length);\n}\n","import type { CollectorContext, EntropyCategory, Signal } from '../types/index';\n\n/**\n * Clamp a numeric quality/stability score into `[0, 1]`.\n */\nexport function clamp01(value: number): number {\n if (!Number.isFinite(value)) {\n return 0;\n }\n if (value < 0) {\n return 0;\n }\n if (value > 1) {\n return 1;\n }\n return value;\n}\n\n/**\n * Build a {@link Signal} with clamped scores and a default timestamp.\n */\nexport function createSignal(input: {\n name: string;\n value: unknown;\n normalizedValue: unknown;\n quality: number;\n stability: number;\n entropyCategory: EntropyCategory;\n collectedAt?: number;\n}): Signal {\n return {\n name: input.name,\n value: input.value,\n normalizedValue: input.normalizedValue,\n quality: clamp01(input.quality),\n stability: clamp01(input.stability),\n entropyCategory: input.entropyCategory,\n collectedAt: input.collectedAt ?? Date.now(),\n };\n}\n\n/**\n * Reject when `signal` is already aborted or becomes aborted.\n */\nexport function rejectedWhenAborted(signal: AbortSignal): Promise {\n return new Promise((_resolve, reject) => {\n const abort = (): void => {\n reject(new DOMException('The operation was aborted.', 'AbortError'));\n };\n if (signal.aborted) {\n abort();\n return;\n }\n signal.addEventListener('abort', abort, { once: true });\n });\n}\n\n/**\n * Race a collector promise against the shared abort signal.\n */\nexport function raceAbort(promise: Promise, signal: AbortSignal): Promise {\n return Promise.race([promise, rejectedWhenAborted(signal)]);\n}\n\n/**\n * Throw when the collector context has already been cancelled.\n */\nexport function throwIfAborted(ctx: CollectorContext): void {\n if (ctx.abortSignal.aborted) {\n throw new DOMException('The operation was aborted.', 'AbortError');\n }\n}\n","import { compactDigest } from '../crypto/digest';\nimport type { Collector, CollectorContext, Signal } from '../types/index';\nimport { createSignal, raceAbort, throwIfAborted } from './collector';\n\ntype OfflineAudioContextCtor = new (\n numberOfChannels: number,\n length: number,\n sampleRate: number,\n) => OfflineAudioContext;\n\nconst SAMPLE_RATE = 44100;\nconst DURATION_SAMPLES = 44100;\nconst SNAPSHOT_BINS = 256;\n\n/**\n * WebAudio fingerprint using an offline graph only.\n *\n * Uses OfflineAudioContext + OscillatorNode + DynamicsCompressorNode.\n * Never calls `getUserMedia` and never touches the microphone.\n */\nexport class AudioCollector implements Collector {\n readonly name = 'audio';\n\n async collect(ctx: CollectorContext): Promise {\n throwIfAborted(ctx);\n\n const Ctor = resolveOfflineAudioContext();\n if (!Ctor) {\n throw new Error('OfflineAudioContext is not available');\n }\n\n const offline = new Ctor(1, DURATION_SAMPLES, SAMPLE_RATE);\n const oscillator = offline.createOscillator();\n oscillator.type = 'triangle';\n oscillator.frequency.value = 10000;\n\n const compressor = offline.createDynamicsCompressor();\n compressor.threshold.value = -50;\n compressor.knee.value = 40;\n compressor.ratio.value = 12;\n compressor.attack.value = 0;\n compressor.release.value = 0.25;\n\n oscillator.connect(compressor);\n compressor.connect(offline.destination);\n oscillator.start(0);\n\n const buffer = await raceAbort(offline.startRendering(), ctx.abortSignal);\n const channel = buffer.getChannelData(0);\n const snapshot = downsample(channel, SNAPSHOT_BINS);\n const digest = await compactDigest(snapshot.join(','));\n\n return createSignal({\n name: this.name,\n value: digest,\n normalizedValue: digest,\n quality: 0.85,\n stability: 0.9,\n entropyCategory: 'high',\n });\n }\n}\n\nfunction resolveOfflineAudioContext(): OfflineAudioContextCtor | null {\n const root = globalThis as typeof globalThis & {\n OfflineAudioContext?: OfflineAudioContextCtor;\n webkitOfflineAudioContext?: OfflineAudioContextCtor;\n };\n return root.OfflineAudioContext ?? root.webkitOfflineAudioContext ?? null;\n}\n\nfunction downsample(channel: Float32Array, bins: number): number[] {\n const step = Math.max(1, Math.floor(channel.length / bins));\n const values: number[] = [];\n for (let i = 0; i < channel.length && values.length < bins; i += step) {\n const sample = channel[i] ?? 0;\n values.push(Math.round(sample * 1_000_000));\n }\n return values;\n}\n","import type { Collector, CollectorContext, Signal } from '../types/index';\nimport { clamp01, createSignal, throwIfAborted } from './collector';\n\nexport interface AutomationValue {\n indicators: string[];\n confidence: number;\n}\n\nconst WEIGHTS: Record = {\n webdriver: 0.7,\n 'headless-ua': 0.6,\n 'missing-languages': 0.25,\n 'language-mismatch': 0.2,\n 'missing-hardware-concurrency': 0.2,\n 'implausible-hardware-concurrency': 0.25,\n 'zero-outer-size': 0.2,\n 'headless-chrome': 0.55,\n};\n\n/**\n * Automation heuristics. Returns indicators + confidence, never a boolean.\n */\nexport class AutomationCollector implements Collector {\n readonly name = 'automation';\n\n async collect(ctx: CollectorContext): Promise {\n throwIfAborted(ctx);\n\n const indicators: string[] = [];\n const nav = typeof navigator === 'undefined' ? null : navigator;\n const userAgent = nav?.userAgent ?? '';\n\n if (nav && nav.webdriver === true) {\n indicators.push('webdriver');\n }\n\n if (!nav || !Array.isArray(nav.languages) || nav.languages.length === 0) {\n indicators.push('missing-languages');\n } else if (nav.language && nav.languages[0] && nav.language !== nav.languages[0]) {\n indicators.push('language-mismatch');\n }\n\n if (!nav || typeof nav.hardwareConcurrency !== 'number') {\n indicators.push('missing-hardware-concurrency');\n } else if (nav.hardwareConcurrency <= 0 || nav.hardwareConcurrency > 128) {\n indicators.push('implausible-hardware-concurrency');\n }\n\n if (/headless/i.test(userAgent)) {\n indicators.push('headless-ua');\n }\n if (/HeadlessChrome/i.test(userAgent)) {\n indicators.push('headless-chrome');\n }\n\n if (typeof window !== 'undefined' && window.outerWidth === 0 && window.outerHeight === 0) {\n indicators.push('zero-outer-size');\n }\n\n const confidence = clamp01(\n indicators.reduce((sum, name) => sum + (WEIGHTS[name] ?? 0.15), 0),\n );\n\n const value: AutomationValue = {\n indicators,\n confidence,\n };\n\n return createSignal({\n name: this.name,\n value,\n normalizedValue: value,\n quality: 0.8,\n stability: 0.5,\n entropyCategory: 'low',\n });\n }\n}\n","import { compactDigest } from '../crypto/digest';\nimport type { Collector, CollectorContext, Signal } from '../types/index';\nimport { createSignal, throwIfAborted } from './collector';\n\nconst WIDTH = 280;\nconst HEIGHT = 80;\n\n/**\n * Deterministic 2D canvas scene. Pixels are digested locally; the image\n * is never sent to the server.\n */\nexport class CanvasCollector implements Collector {\n readonly name = 'canvas';\n\n async collect(ctx: CollectorContext): Promise {\n throwIfAborted(ctx);\n\n if (typeof document === 'undefined') {\n throw new Error('document is not available');\n }\n\n const canvas = document.createElement('canvas');\n canvas.width = WIDTH;\n canvas.height = HEIGHT;\n canvas.style.display = 'none';\n\n const context = canvas.getContext('2d', { willReadFrequently: true });\n if (!context) {\n throw new Error('CanvasRenderingContext2D is not available');\n }\n\n paintScene(context);\n\n const image = context.getImageData(0, 0, WIDTH, HEIGHT);\n const digest = await compactDigest(image.data);\n\n return createSignal({\n name: this.name,\n value: digest,\n normalizedValue: digest,\n quality: 0.92,\n stability: 0.95,\n entropyCategory: 'high',\n });\n }\n}\n\n/**\n * Fixed geometry: rectangles, the label \"DeviceIntelligence\", and arcs.\n */\nfunction paintScene(ctx: CanvasRenderingContext2D): void {\n ctx.fillStyle = '#f60';\n ctx.fillRect(8, 8, 90, 48);\n\n ctx.fillStyle = '#069';\n ctx.fillRect(108, 12, 70, 40);\n\n ctx.strokeStyle = '#111827';\n ctx.lineWidth = 2;\n ctx.beginPath();\n ctx.arc(220, 36, 26, 0, Math.PI * 2);\n ctx.stroke();\n\n ctx.beginPath();\n ctx.arc(248, 52, 14, 0.25 * Math.PI, 1.6 * Math.PI);\n ctx.stroke();\n\n ctx.fillStyle = '#111827';\n ctx.font = '16px Arial, sans-serif';\n ctx.textBaseline = 'top';\n ctx.fillText('DeviceIntelligence', 12, 58);\n\n ctx.fillStyle = 'rgba(16, 185, 129, 0.45)';\n ctx.fillRect(40, 20, 36, 18);\n}\n","import type { Collector, CollectorContext, Signal } from '../types/index';\nimport { createSignal, throwIfAborted } from './collector';\n\n/**\n * Boolean capability set used for Jaccard matching. Avoids expensive probes.\n */\nexport class CapabilitiesCollector implements Collector {\n readonly name = 'capabilities';\n\n async collect(ctx: CollectorContext): Promise {\n throwIfAborted(ctx);\n\n const nav = typeof navigator === 'undefined' ? null : navigator;\n const win = typeof window === 'undefined' ? null : window;\n\n const value = {\n cookieEnabled: nav?.cookieEnabled ?? false,\n pdfViewerEnabled: Boolean((nav as Navigator & { pdfViewerEnabled?: boolean } | null)?.pdfViewerEnabled),\n serviceWorker: Boolean(nav && 'serviceWorker' in nav),\n webgl: hasWebGl(),\n webgpu: Boolean(nav && 'gpu' in nav),\n wasm: typeof WebAssembly !== 'undefined',\n sharedArrayBuffer: typeof SharedArrayBuffer !== 'undefined',\n touch: (nav?.maxTouchPoints ?? 0) > 0,\n matchMedia: typeof win?.matchMedia === 'function',\n localStorage: hasStorage('localStorage'),\n sessionStorage: hasStorage('sessionStorage'),\n indexedDB: typeof indexedDB !== 'undefined',\n };\n\n const flags = Object.entries(value)\n .filter(([, enabled]) => enabled)\n .map(([key]) => key)\n .sort();\n\n return createSignal({\n name: this.name,\n value,\n normalizedValue: flags,\n quality: 0.9,\n stability: 0.9,\n entropyCategory: 'medium',\n });\n }\n}\n\nfunction hasWebGl(): boolean {\n if (typeof document === 'undefined') {\n return false;\n }\n // jsdom implements getContext but cannot create a GPU context and logs loudly.\n if (typeof navigator !== 'undefined' && /jsdom/i.test(navigator.userAgent)) {\n return false;\n }\n try {\n const canvas = document.createElement('canvas');\n return Boolean(canvas.getContext('webgl') || canvas.getContext('experimental-webgl'));\n } catch {\n return false;\n }\n}\n\nfunction hasStorage(name: 'localStorage' | 'sessionStorage'): boolean {\n try {\n const storage = globalThis[name];\n const key = '__di_cap__';\n storage.setItem(key, '1');\n storage.removeItem(key);\n return true;\n } catch {\n return false;\n }\n}\n","/**\n * Client-side normalizers. Output is family + major, never a full version string.\n */\n\nexport type PlatformFamily = 'windows' | 'macos' | 'linux' | 'ios' | 'android' | 'other';\n\nexport type ScreenClass = 'mobile-s' | 'mobile-l' | 'tablet' | 'hd' | 'qhd' | 'uhd' | 'other';\n\nexport type GpuFamily = 'apple' | 'intel' | 'nvidia' | 'amd' | 'mali' | 'adreno' | 'other';\n\n/**\n * Normalize a user-agent or \"Family x.y.z\" label to `Family `.\n *\n * @example\n * normalizeBrowser('Chrome 143.0.7312.58') // 'Chrome 143'\n * normalizeBrowser('... Chrome/143.0.7312.58 Safari/537.36') // 'Chrome 143'\n */\nexport function normalizeBrowser(input: string): string {\n const text = input.trim();\n if (text.length === 0) {\n return 'other';\n }\n\n if (/Edg(?:e|A|iOS)?\\/|\\bEdge\\//i.test(text) || /^Edge\\s/i.test(text)) {\n return labeledFamily(text, 'Edge', /(?:Edg(?:e|A|iOS)?|Edge)[/\\s](\\d+)/i);\n }\n\n if (/\\bOPR\\/|\\bOpera\\//i.test(text) || /^Opera\\s/i.test(text)) {\n return labeledFamily(text, 'Opera', /(?:OPR|Opera)[/\\s](\\d+)/i);\n }\n\n if (/\\bFirefox\\/|\\bFxiOS\\//i.test(text) || /^Firefox\\s/i.test(text)) {\n return labeledFamily(text, 'Firefox', /(?:Firefox|FxiOS)[/\\s](\\d+)/i);\n }\n\n if (/^Chrome\\s+\\d+/i.test(text)) {\n return labeledFamily(text, 'Chrome', /^Chrome\\s+(\\d+)/i);\n }\n\n const isSafari =\n /\\bSafari\\//i.test(text) &&\n /\\bVersion\\//i.test(text) &&\n !/\\b(Chrome|Chromium|CriOS|Edg|OPR)\\b/i.test(text);\n if (isSafari || /^Safari\\s/i.test(text)) {\n return labeledFamily(text, 'Safari', /(?:Version|Safari)[/\\s](\\d+)/i);\n }\n\n if (/\\b(Chrome|Chromium|CriOS)\\//i.test(text)) {\n return labeledFamily(text, 'Chrome', /(?:Chrome|Chromium|CriOS)\\/(\\d+)/i);\n }\n\n return 'other';\n}\n\nfunction labeledFamily(text: string, family: string, majorPattern: RegExp): string {\n const match = text.match(majorPattern);\n const major = match?.[1];\n return major ? `${family} ${major}` : family;\n}\n\n/**\n * Map a platform / oscpu / UA-CH platform string to a lowercase family.\n */\nexport function normalizePlatform(input: string): PlatformFamily {\n const value = input.toLowerCase();\n if (value.includes('win')) {\n return 'windows';\n }\n if (value.includes('android')) {\n return 'android';\n }\n if (\n value.includes('iphone') ||\n value.includes('ipad') ||\n value.includes('ipod') ||\n value.includes('ios')\n ) {\n return 'ios';\n }\n if (value.includes('mac') || value.includes('darwin')) {\n return 'macos';\n }\n if (value.includes('linux') || value.includes('x11') || value.includes('cros')) {\n return 'linux';\n }\n return 'other';\n}\n\n/**\n * Classify a viewport/screen by its largest dimension in CSS pixels.\n *\n * - `mobile-s` ≤ 480\n * - `mobile-l` ≤ 767\n * - `tablet` ≤ 1280\n * - `hd` ≤ 1920\n * - `qhd` ≤ 2560\n * - `uhd` ≤ 3840\n * - `other` otherwise (including non-finite values)\n */\nexport function normalizeScreenClass(width: number, height: number): ScreenClass {\n const max = Math.max(width, height);\n if (!Number.isFinite(max) || max <= 0) {\n return 'other';\n }\n if (max <= 480) {\n return 'mobile-s';\n }\n if (max <= 767) {\n return 'mobile-l';\n }\n if (max <= 1280) {\n return 'tablet';\n }\n if (max <= 1920) {\n return 'hd';\n }\n if (max <= 2560) {\n return 'qhd';\n }\n if (max <= 3840) {\n return 'uhd';\n }\n return 'other';\n}\n\n/**\n * Coarse GPU vendor family from WebGL vendor/renderer strings.\n */\nexport function normalizeGpuFamily(vendor: string, renderer: string): GpuFamily {\n const text = `${vendor} ${renderer}`.toLowerCase();\n if (text.includes('apple') || text.includes('metal')) {\n return 'apple';\n }\n if (text.includes('nvidia') || text.includes('geforce') || text.includes('quadro')) {\n return 'nvidia';\n }\n if (text.includes('amd') || text.includes('radeon') || text.includes('ati')) {\n return 'amd';\n }\n if (text.includes('intel')) {\n return 'intel';\n }\n if (text.includes('mali')) {\n return 'mali';\n }\n if (text.includes('adreno')) {\n return 'adreno';\n }\n return 'other';\n}\n","import { normalizeBrowser, normalizePlatform } from '../normalization/normalize';\nimport type { Collector, CollectorContext, NavigatorUADataLike, Signal } from '../types/index';\nimport { createSignal, raceAbort, throwIfAborted } from './collector';\n\nconst HIGH_ENTROPY_HINTS = [\n 'architecture',\n 'bitness',\n 'model',\n 'platformVersion',\n 'uaFullVersion',\n 'fullVersionList',\n] as const;\n\n/**\n * JS User-Agent Client Hints. Never the sole identity source; quality drops\n * when high-entropy values are denied or unavailable.\n */\nexport class ClientHintsCollector implements Collector {\n readonly name = 'client_hints';\n\n async collect(ctx: CollectorContext): Promise {\n throwIfAborted(ctx);\n\n if (typeof navigator === 'undefined') {\n throw new Error('navigator is not available');\n }\n\n const uaData = (navigator as Navigator & { userAgentData?: NavigatorUADataLike }).userAgentData;\n\n if (!uaData) {\n return createSignal({\n name: this.name,\n value: {\n brands: [],\n mobile: null,\n platform: '',\n highEntropy: false,\n available: false,\n },\n normalizedValue: {\n browser: normalizeBrowser(navigator.userAgent ?? ''),\n platform: normalizePlatform(navigator.platform ?? navigator.userAgent ?? ''),\n highEntropy: false,\n },\n quality: 0.35,\n stability: 0.7,\n entropyCategory: 'medium',\n });\n }\n\n const base = {\n brands: Array.isArray(uaData.brands) ? uaData.brands : [],\n mobile: typeof uaData.mobile === 'boolean' ? uaData.mobile : null,\n platform: uaData.platform ?? '',\n highEntropy: false,\n available: true,\n };\n\n let highEntropy: Record = {};\n let gotHighEntropy = false;\n\n if (ctx.consent.highEntropy && typeof uaData.getHighEntropyValues === 'function') {\n try {\n highEntropy = await raceAbort(\n uaData.getHighEntropyValues([...HIGH_ENTROPY_HINTS]),\n ctx.abortSignal,\n );\n gotHighEntropy = true;\n } catch {\n gotHighEntropy = false;\n }\n }\n\n const value = {\n ...base,\n ...highEntropy,\n highEntropy: gotHighEntropy,\n };\n\n const brandLabel = firstBrand(base.brands);\n const versionHint =\n typeof highEntropy['uaFullVersion'] === 'string'\n ? String(highEntropy['uaFullVersion'])\n : brandLabel?.version ?? '';\n const browserInput = brandLabel\n ? `${brandLabel.brand} ${versionHint}`\n : navigator.userAgent;\n\n return createSignal({\n name: this.name,\n value,\n normalizedValue: {\n browser: normalizeBrowser(browserInput),\n platform: normalizePlatform(base.platform || navigator.platform || ''),\n highEntropy: gotHighEntropy,\n },\n quality: gotHighEntropy ? 0.95 : 0.7,\n stability: 0.75,\n entropyCategory: 'medium',\n });\n }\n}\n\nfunction firstBrand(brands: Array<{ brand: string; version: string }>): {\n brand: string;\n version: string;\n} | null {\n const preferred = brands.find((item) => {\n const brand = item.brand.toLowerCase();\n return brand !== 'not?a;brand' && brand !== 'not a;brand' && !brand.includes('not:');\n });\n return preferred ?? brands[0] ?? null;\n}\n","import type { Collector, CollectorContext, Signal } from '../types/index';\nimport { createSignal, throwIfAborted } from './collector';\n\nconst SAMPLE = 'mmmmmmmmmmlli';\nconst BASELINE = 'monospace';\nconst CANDIDATES = ['Arial', 'Times New Roman', 'Courier New', 'Georgia', 'Verdana', 'Roboto'];\n\n/**\n * Cheap width-based font probe. Disabled by default (Level 3 / high entropy).\n */\nexport class FontsCollector implements Collector {\n readonly name = 'fonts';\n\n async collect(ctx: CollectorContext): Promise {\n throwIfAborted(ctx);\n\n if (typeof document === 'undefined' || !document.body) {\n throw new Error('document.body is not available');\n }\n\n const baseline = measureWidth(SAMPLE, BASELINE);\n const detected = CANDIDATES.filter((font) => {\n const width = measureWidth(SAMPLE, `${font}, ${BASELINE}`);\n return width !== baseline;\n });\n\n return createSignal({\n name: this.name,\n value: detected,\n normalizedValue: [...detected].sort(),\n quality: 0.7,\n stability: 0.8,\n entropyCategory: 'high',\n });\n }\n}\n\nfunction measureWidth(text: string, fontFamily: string): number {\n const span = document.createElement('span');\n span.style.cssText = [\n 'position:absolute',\n 'left:-9999px',\n 'top:0',\n 'visibility:hidden',\n 'white-space:nowrap',\n `font:72px ${fontFamily}`,\n ].join(';');\n span.textContent = text;\n document.body.appendChild(span);\n const width = span.offsetWidth;\n document.body.removeChild(span);\n return width;\n}\n","import { normalizeBrowser, normalizePlatform } from '../normalization/normalize';\nimport type { Collector, CollectorContext, Signal } from '../types/index';\nimport { createSignal, throwIfAborted } from './collector';\n\n/**\n * Compact navigator snapshot (Level 1). No high-entropy Client Hints here.\n */\nexport class NavigatorCollector implements Collector {\n readonly name = 'navigator';\n\n async collect(ctx: CollectorContext): Promise {\n throwIfAborted(ctx);\n\n if (typeof navigator === 'undefined') {\n throw new Error('navigator is not available');\n }\n\n const userAgent = navigator.userAgent ?? '';\n const platform = navigator.platform ?? '';\n const languages = Array.isArray(navigator.languages) ? [...navigator.languages] : [];\n const nav = navigator as Navigator & { deviceMemory?: number };\n\n const value = {\n userAgent,\n platform,\n language: navigator.language ?? '',\n languages,\n hardwareConcurrency: navigator.hardwareConcurrency ?? null,\n deviceMemory: typeof nav.deviceMemory === 'number' ? nav.deviceMemory : null,\n maxTouchPoints: navigator.maxTouchPoints ?? 0,\n vendor: navigator.vendor ?? '',\n };\n\n const browser = normalizeBrowser(userAgent);\n const platformFamily = normalizePlatform(platform || userAgent);\n\n return createSignal({\n name: this.name,\n value,\n normalizedValue: {\n browser,\n platform: platformFamily,\n hardwareConcurrency: value.hardwareConcurrency,\n },\n quality: userAgent.length > 0 ? 0.9 : 0.4,\n stability: 0.8,\n entropyCategory: 'medium',\n });\n }\n}\n","import { normalizeScreenClass } from '../normalization/normalize';\nimport type { Collector, CollectorContext, Signal } from '../types/index';\nimport { createSignal, throwIfAborted } from './collector';\n\n/**\n * Screen geometry and color depth. Window size is omitted (too volatile).\n */\nexport class ScreenCollector implements Collector {\n readonly name = 'screen';\n\n async collect(ctx: CollectorContext): Promise {\n throwIfAborted(ctx);\n\n const screenRef = typeof screen === 'undefined' ? null : screen;\n if (!screenRef) {\n throw new Error('screen is not available');\n }\n\n const width = finiteOrZero(screenRef.width);\n const height = finiteOrZero(screenRef.height);\n const value = {\n width,\n height,\n availWidth: finiteOrZero(screenRef.availWidth),\n availHeight: finiteOrZero(screenRef.availHeight),\n colorDepth: finiteOrZero(screenRef.colorDepth),\n pixelDepth: finiteOrZero(screenRef.pixelDepth),\n pixelRatio: finiteOrZero(typeof devicePixelRatio === 'number' ? devicePixelRatio : 1),\n };\n\n const screenClass = normalizeScreenClass(width, height);\n\n return createSignal({\n name: this.name,\n value,\n normalizedValue: {\n screenClass,\n width,\n height,\n },\n quality: width > 0 && height > 0 ? 0.95 : 0.4,\n stability: 0.7,\n entropyCategory: 'low',\n });\n }\n}\n\nfunction finiteOrZero(value: number): number {\n return Number.isFinite(value) ? value : 0;\n}\n","import type { Collector, CollectorContext, Signal } from '../types/index';\nimport { createSignal, throwIfAborted } from './collector';\n\n/**\n * IANA timezone and UTC offset. Offset is informational; identity uses the name.\n */\nexport class TimezoneCollector implements Collector {\n readonly name = 'timezone';\n\n async collect(ctx: CollectorContext): Promise {\n throwIfAborted(ctx);\n\n let timeZone = 'UTC';\n try {\n timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone || 'UTC';\n } catch {\n timeZone = 'UTC';\n }\n\n const offsetMinutes = new Date().getTimezoneOffset();\n const value = {\n timeZone,\n offsetMinutes,\n };\n\n return createSignal({\n name: this.name,\n value,\n normalizedValue: timeZone,\n quality: timeZone.length > 0 ? 0.99 : 0.3,\n stability: 0.85,\n entropyCategory: 'low',\n });\n }\n}\n","import { compactDigest } from '../crypto/digest';\nimport { normalizeGpuFamily } from '../normalization/normalize';\nimport type { Collector, CollectorContext, Signal } from '../types/index';\nimport { createSignal, throwIfAborted } from './collector';\n\nexport interface WebGlValue {\n vendor: string | null;\n renderer: string | null;\n extensionsHash: string;\n limits: {\n maxTextureSize: number | null;\n maxViewportDims: number[] | null;\n maxRenderbufferSize: number | null;\n maxVertexAttribs: number | null;\n maxFragmentUniformVectors: number | null;\n };\n}\n\n/**\n * WebGL vendor/renderer (when unmasked), hashed extension set, and a few limits.\n * Does not assume `WEBGL_debug_renderer_info` is present.\n */\nexport class WebGlCollector implements Collector {\n readonly name = 'webgl';\n\n async collect(ctx: CollectorContext): Promise {\n throwIfAborted(ctx);\n\n if (typeof document === 'undefined') {\n throw new Error('document is not available');\n }\n\n const canvas = document.createElement('canvas');\n canvas.width = 1;\n canvas.height = 1;\n\n const gl = getWebGlContext(canvas);\n if (!gl) {\n throw new Error('WebGL is not available');\n }\n\n try {\n const debugInfo = gl.getExtension('WEBGL_debug_renderer_info');\n const vendor = readParameter(\n gl,\n debugInfo ? debugInfo.UNMASKED_VENDOR_WEBGL : gl.VENDOR,\n );\n const renderer = readParameter(\n gl,\n debugInfo ? debugInfo.UNMASKED_RENDERER_WEBGL : gl.RENDERER,\n );\n\n const extensions = gl.getSupportedExtensions() ?? [];\n const extensionsHash = await compactDigest([...extensions].sort().join(','));\n\n const maxViewport = gl.getParameter(gl.MAX_VIEWPORT_DIMS);\n const limits = {\n maxTextureSize: readNumeric(gl, gl.MAX_TEXTURE_SIZE),\n maxViewportDims: Array.isArray(maxViewport)\n ? [Number(maxViewport[0]), Number(maxViewport[1])]\n : maxViewport instanceof Int32Array\n ? [maxViewport[0] ?? 0, maxViewport[1] ?? 0]\n : null,\n maxRenderbufferSize: readNumeric(gl, gl.MAX_RENDERBUFFER_SIZE),\n maxVertexAttribs: readNumeric(gl, gl.MAX_VERTEX_ATTRIBS),\n maxFragmentUniformVectors: readNumeric(gl, gl.MAX_FRAGMENT_UNIFORM_VECTORS),\n };\n\n const value: WebGlValue = {\n vendor,\n renderer,\n extensionsHash,\n limits,\n };\n\n const hasRenderer = typeof renderer === 'string' && renderer.length > 0;\n const quality = hasRenderer && debugInfo ? 0.88 : hasRenderer ? 0.7 : 0.45;\n\n return createSignal({\n name: this.name,\n value,\n normalizedValue: {\n gpuFamily: normalizeGpuFamily(vendor ?? '', renderer ?? ''),\n extensionsHash,\n maxTextureSize: limits.maxTextureSize,\n },\n quality,\n stability: 0.95,\n entropyCategory: 'high',\n });\n } finally {\n const lose = gl.getExtension('WEBGL_lose_context');\n lose?.loseContext();\n }\n }\n}\n\nfunction getWebGlContext(canvas: HTMLCanvasElement): WebGLRenderingContext | null {\n const options: WebGLContextAttributes = {\n alpha: true,\n antialias: false,\n depth: false,\n failIfMajorPerformanceCaveat: false,\n preserveDrawingBuffer: false,\n };\n\n const standard = canvas.getContext('webgl', options);\n if (standard) {\n return standard;\n }\n\n return canvas.getContext('experimental-webgl', options) as WebGLRenderingContext | null;\n}\n\nfunction readParameter(gl: WebGLRenderingContext, pname: number): string | null {\n try {\n const value = gl.getParameter(pname);\n return typeof value === 'string' && value.length > 0 ? value : null;\n } catch {\n return null;\n }\n}\n\nfunction readNumeric(gl: WebGLRenderingContext, pname: number): number | null {\n try {\n const value = gl.getParameter(pname);\n return typeof value === 'number' && Number.isFinite(value) ? value : null;\n } catch {\n return null;\n }\n}\n","import type { CollectPayload, ServerCollectResponse } from '../types/index';\n\nconst PREVIOUS_DEBUG_TOKEN_HEADER = 'X-Previous-Debug-Token';\n\n/**\n * Token of the current HTML request's Web Debug Toolbar, if present.\n * Used so POST /_device/collect is stored as a child of that profiler profile.\n */\nexport function readProfilerPreviousToken(): string | undefined {\n if (typeof document === 'undefined') {\n return undefined;\n }\n const el = document.querySelector('[id^=\"sfwdt\"]');\n if (!(el instanceof Element) || !el.id.startsWith('sfwdt')) {\n return undefined;\n }\n const token = el.id.slice('sfwdt'.length);\n return token.length > 0 ? token : undefined;\n}\n\n/**\n * POST a collect payload. Never throws; returns `null` on any failure.\n *\n * @param endpoint - Same-origin collect URL\n * @param payload - Protocol v1 JSON body\n * @param abortSignal - Optional cancellation\n */\nexport async function postCollect(\n endpoint: string,\n payload: CollectPayload,\n abortSignal?: AbortSignal,\n): Promise {\n try {\n const headers: Record = {\n 'Content-Type': 'application/json',\n };\n const previousToken = readProfilerPreviousToken();\n if (previousToken !== undefined) {\n headers[PREVIOUS_DEBUG_TOKEN_HEADER] = previousToken;\n }\n\n const response = await fetch(endpoint, {\n method: 'POST',\n credentials: 'same-origin',\n headers,\n body: JSON.stringify(payload),\n signal: abortSignal,\n });\n\n if (!response.ok) {\n return null;\n }\n\n const text = await response.text();\n if (text.trim().length === 0) {\n return { ok: true };\n }\n\n const parsed: unknown = JSON.parse(text);\n if (parsed === null || typeof parsed !== 'object') {\n return { ok: true };\n }\n\n return parsed as ServerCollectResponse;\n } catch {\n return null;\n }\n}\n","/**\n * SDK protocol/semver identifier sent on every collect request.\n * Collect protocol identifier sent on every collect request (`v: 1` remains the schema).\n */\nexport const SDK_VERSION = '1.0.0';\n","import { MemoryCache } from './cache/memory-cache';\nimport { AudioCollector } from './collectors/audio';\nimport { AutomationCollector } from './collectors/automation';\nimport { CanvasCollector } from './collectors/canvas';\nimport { CapabilitiesCollector } from './collectors/capabilities';\nimport { ClientHintsCollector } from './collectors/client-hints';\nimport { raceAbort } from './collectors/collector';\nimport { FontsCollector } from './collectors/fonts';\nimport { NavigatorCollector } from './collectors/navigator';\nimport { ScreenCollector } from './collectors/screen';\nimport { TimezoneCollector } from './collectors/timezone';\nimport { WebGlCollector } from './collectors/webgl';\nimport { postCollect } from './transport/fetch-transport';\nimport type {\n CachedObservation,\n CollectPayload,\n CollectResult,\n CollectSignalWire,\n Collector,\n CollectorContext,\n CollectorsConfig,\n DeviceIntelligenceOptions,\n EnhancementLevel,\n Signal,\n} from './types/index';\nimport { SDK_VERSION } from './version';\n\nconst DEFAULT_ENDPOINT = '/_device/collect';\nconst DEFAULT_TIMEOUT_MS = 1500;\nconst DEFAULT_CACHE_TTL = 3600;\n\nconst DEFAULT_COLLECTORS: Required = {\n audio: true,\n canvas: true,\n webgl: true,\n screen: true,\n timezone: true,\n navigator: true,\n clientHints: true,\n capabilities: true,\n automation: true,\n fonts: false,\n};\n\nconst COLLECTOR_LEVELS: Record = {\n navigator: 1,\n client_hints: 1,\n screen: 1,\n timezone: 1,\n capabilities: 1,\n automation: 3,\n canvas: 2,\n webgl: 2,\n audio: 3,\n fonts: 3,\n};\n\n/**\n * Browser Device Intelligence client.\n *\n * `collect()` never throws into application code. Failures resolve to\n * `{ ok: false, degraded: true }` and omit the failing collector.\n */\nexport class DeviceIntelligence {\n private readonly endpoint: string;\n private readonly timeout: number;\n private readonly cacheTtl: number;\n private readonly cacheEnabled: boolean;\n private readonly consent: { highEntropy: boolean };\n private readonly cache = new MemoryCache();\n private readonly collectors: Collector[] = [];\n\n /**\n * @param options - Optional endpoint, collector flags, cache, and timeout\n */\n constructor(options: DeviceIntelligenceOptions = {}) {\n this.endpoint = options.endpoint ?? DEFAULT_ENDPOINT;\n this.timeout = positiveTimeout(options.timeout);\n this.cacheEnabled = options.cache?.enabled ?? true;\n this.cacheTtl = options.cache?.ttl ?? DEFAULT_CACHE_TTL;\n this.consent = {\n highEntropy: options.consent?.highEntropy ?? true,\n };\n this.collectors = createBuiltInCollectors({\n ...DEFAULT_COLLECTORS,\n ...options.collectors,\n });\n }\n\n /**\n * Collect enabled signals and POST them to the configured endpoint.\n * Returns a cached observation when the TTL is still valid.\n *\n * @returns Collect result; never rejects — failures set `ok: false` and `degraded: true`.\n */\n async collect(): Promise {\n return this.runCollect(false);\n }\n\n /**\n * Force a new collection, ignoring any cached observation.\n *\n * @returns Collect result; never rejects.\n */\n async refresh(): Promise {\n return this.runCollect(true);\n }\n\n /**\n * Last cached observation, or `null` when empty / expired.\n */\n getCachedObservation(): CachedObservation | null {\n return this.cache.get();\n }\n\n /** Drop the in-memory cache. */\n clear(): void {\n this.cache.clear();\n }\n\n /**\n * Register an additional collector. It runs on the next `collect()` / `refresh()`.\n *\n * @param collector Collector implementation with `name` and `collect()`.\n */\n registerCollector(collector: Collector): void {\n this.collectors.push(collector);\n }\n\n private async runCollect(forceRefresh: boolean): Promise {\n try {\n if (!forceRefresh && this.cacheEnabled) {\n const cached = this.cache.get();\n if (cached) {\n return cached.result;\n }\n }\n\n const controller = new AbortController();\n const timer = globalThis.setTimeout(() => controller.abort(), this.timeout);\n const ctx: CollectorContext = {\n timeout: this.timeout,\n abortSignal: controller.signal,\n consent: this.consent,\n };\n\n let signals: Record = {};\n try {\n signals = await this.collectSignals(ctx);\n } finally {\n globalThis.clearTimeout(timer);\n }\n\n const enabledCount = this.collectors.length;\n const collectedCount = Object.keys(signals).length;\n const collectorsDegraded = collectedCount < enabledCount;\n\n const payload = this.toPayload(signals);\n const transportController = new AbortController();\n const transportTimer = globalThis.setTimeout(\n () => transportController.abort(),\n this.timeout,\n );\n\n let server = null;\n try {\n server = await postCollect(this.endpoint, payload, transportController.signal);\n } finally {\n globalThis.clearTimeout(transportTimer);\n }\n\n const transportFailed = server === null;\n const hasSignals = collectedCount > 0;\n const result: CollectResult = {\n ok: !transportFailed && hasSignals && server?.ok !== false,\n degraded: Boolean(server?.degraded) || collectorsDegraded || transportFailed || !hasSignals,\n signals,\n };\n\n if (server?.new !== undefined) {\n result.new = server.new;\n }\n if (server?.token !== undefined) {\n result.token = server.token;\n }\n if (server?.expiresAt !== undefined) {\n result.expiresAt = server.expiresAt;\n }\n if (server?.deviceId !== undefined) {\n result.deviceId = server.deviceId;\n }\n if (server?.confidence !== undefined) {\n result.confidence = server.confidence;\n }\n if (server?.risk !== undefined) {\n result.risk = server.risk;\n }\n\n if (transportFailed || !hasSignals) {\n result.ok = false;\n result.degraded = true;\n }\n\n const observation: CachedObservation = {\n timestamp: Date.now(),\n signals,\n result,\n };\n\n if (this.cacheEnabled) {\n this.cache.set(observation, this.cacheTtl);\n }\n\n return result;\n } catch {\n return { ok: false, degraded: true, signals: {} };\n }\n }\n\n /**\n * Run collectors in parallel. Each collector is raced against the shared\n * AbortSignal. Level-1 results are preferred if Level 2/3 still pending\n * when the timeout fires.\n */\n private async collectSignals(ctx: CollectorContext): Promise> {\n const signals: Record = {};\n const jobs = this.collectors.map(async (collector) => {\n try {\n const signal = await raceAbort(collector.collect(ctx), ctx.abortSignal);\n if (signal && typeof signal.name === 'string') {\n signals[signal.name] = signal;\n }\n } catch {\n // Omit failed / timed-out collectors.\n }\n });\n\n const allSettled = Promise.all(jobs);\n const timeoutDone = sleep(this.timeout, ctx.abortSignal);\n\n await Promise.race([allSettled, timeoutDone]);\n await Promise.allSettled(jobs);\n\n return signals;\n }\n\n private toPayload(signals: Record): CollectPayload {\n const wire: Record = {};\n for (const [name, signal] of Object.entries(signals)) {\n wire[name] = {\n value: signal.value,\n quality: signal.quality,\n collectedAt: signal.collectedAt,\n };\n }\n\n return {\n v: 1,\n sdkVersion: SDK_VERSION,\n timestamp: Math.floor(Date.now() / 1000),\n nonce: createNonce(),\n consent: this.consent,\n signals: wire,\n };\n }\n}\n\nfunction createBuiltInCollectors(enabled: Required): Collector[] {\n const list: Collector[] = [];\n if (enabled.navigator) {\n list.push(new NavigatorCollector());\n }\n if (enabled.clientHints) {\n list.push(new ClientHintsCollector());\n }\n if (enabled.screen) {\n list.push(new ScreenCollector());\n }\n if (enabled.timezone) {\n list.push(new TimezoneCollector());\n }\n if (enabled.capabilities) {\n list.push(new CapabilitiesCollector());\n }\n if (enabled.automation) {\n list.push(new AutomationCollector());\n }\n if (enabled.canvas) {\n list.push(new CanvasCollector());\n }\n if (enabled.webgl) {\n list.push(new WebGlCollector());\n }\n if (enabled.audio) {\n list.push(new AudioCollector());\n }\n if (enabled.fonts) {\n list.push(new FontsCollector());\n }\n return list;\n}\n\nfunction positiveTimeout(value: number | undefined): number {\n if (typeof value === 'number' && Number.isFinite(value) && value > 0) {\n return value;\n }\n return DEFAULT_TIMEOUT_MS;\n}\n\nfunction createNonce(): string {\n const bytes = new Uint8Array(16);\n if (globalThis.crypto?.getRandomValues) {\n globalThis.crypto.getRandomValues(bytes);\n } else {\n for (let i = 0; i < bytes.length; i += 1) {\n bytes[i] = Math.floor(Math.random() * 256);\n }\n }\n let hex = '';\n for (let i = 0; i < bytes.length; i += 1) {\n hex += (bytes[i] ?? 0).toString(16).padStart(2, '0');\n }\n return hex;\n}\n\nfunction sleep(ms: number, signal: AbortSignal): Promise {\n return new Promise((resolve) => {\n if (signal.aborted) {\n resolve();\n return;\n }\n const id = globalThis.setTimeout(resolve, ms);\n signal.addEventListener(\n 'abort',\n () => {\n globalThis.clearTimeout(id);\n resolve();\n },\n { once: true },\n );\n });\n}\n\n/** @internal Exported for tests that need collector level metadata. */\nexport function collectorLevel(name: string): EnhancementLevel {\n return COLLECTOR_LEVELS[name] ?? 2;\n}\n","/**\n * Bundle logger for Device Intelligence (same API as other Nowo bundles).\n *\n * `scriptLoaded()` always logs. `debug` / `info` / `warn` / `error` require\n * `setDebug(true)` unless `alwaysLog` is set.\n */\n\nexport type BundleLoggerOptions = {\n /** If set, scriptLoaded() includes this (Vite injects compile time). */\n buildTime?: string;\n /** When true, debug/info/warn/error always output. */\n alwaysLog?: boolean;\n};\n\nexport type BundleLogger = {\n /** Call once at startup. Logs \"script loaded\" and optional build time. */\n scriptLoaded: () => void;\n setDebug: (enabled: boolean) => void;\n debug: (...args: unknown[]) => void;\n info: (...args: unknown[]) => void;\n warn: (...args: unknown[]) => void;\n error: (...args: unknown[]) => void;\n};\n\nconst STYLES = {\n script: 'color:#0ea5e9;font-weight:bold',\n debug: 'color:#6b7280',\n info: 'color:#2563eb',\n warn: 'color:#d97706',\n error: 'color:#dc2626;font-weight:bold',\n} as const;\n\nconst EMOJI = {\n script: 'đŸ“Ļ',\n debug: '🔍',\n info: 'â„šī¸',\n warn: 'âš ī¸',\n error: '❌',\n} as const;\n\nfunction formatArgs(args: unknown[]): unknown[] {\n return args.map((a) =>\n typeof a === 'object' && a !== null && !(a instanceof Error) ? JSON.stringify(a) : a,\n );\n}\n\ntype ConsoleLevel = 'debug' | 'info' | 'warn' | 'error';\n\nfunction logScriptLoaded(prefix: string, buildTime: string | undefined): void {\n if (buildTime !== undefined && buildTime !== '') {\n console.log(\n `%c${EMOJI.script} ${prefix} script loaded, build time: %c${buildTime}`,\n STYLES.script,\n 'color:#059669',\n );\n return;\n }\n console.log(`%c${EMOJI.script} ${prefix} script loaded`, STYLES.script);\n}\n\nfunction emitLevelLog(level: ConsoleLevel, prefix: string, args: unknown[]): void {\n const emoji = EMOJI[level];\n const style = STYLES[level];\n const label = `%c${emoji} ${prefix}`;\n const logFn = console[level] as (...fnArgs: unknown[]) => void;\n if (args.length > 0) {\n logFn(label, style, ...formatArgs(args));\n return;\n }\n logFn(label, style);\n}\n\nfunction makeLevelMethod(\n isEnabled: () => boolean,\n prefix: string,\n level: ConsoleLevel,\n): (...args: unknown[]) => void {\n return (...args: unknown[]): void => {\n if (!isEnabled()) {\n return;\n }\n emitLevelLog(level, prefix, args);\n };\n}\n\nfunction noop(): void {}\n\nlet instance: BundleLogger | null = null;\n\n/**\n * Registers the bundle logger. Call once from the entry after createBundleLogger.\n *\n * @param log - Logger instance to register\n */\nexport function setBundleLogger(log: BundleLogger): void {\n instance = log;\n}\n\n/**\n * Clears the registered logger (tests only).\n */\nexport function clearBundleLoggerForTest(): void {\n instance = null;\n}\n\n/**\n * Returns the bundle logger, or a no-op logger when none is registered.\n *\n * @returns The registered logger or a silent fallback\n */\nexport function getLogger(): BundleLogger {\n if (instance !== null) {\n return instance;\n }\n return {\n scriptLoaded: noop,\n setDebug: noop,\n debug: noop,\n info: noop,\n warn: noop,\n error: noop,\n };\n}\n\n/**\n * Creates a Device Intelligence console logger.\n *\n * @param name - Short name for the log prefix (e.g. `device-intelligence`)\n * @param options - Optional buildTime and alwaysLog\n * @returns A BundleLogger\n */\nexport function createBundleLogger(name: string, options: BundleLoggerOptions = {}): BundleLogger {\n const prefix = `[${name}]`;\n const { buildTime, alwaysLog = false } = options;\n const logAlways = alwaysLog === true;\n let debugEnabled = logAlways;\n\n return {\n scriptLoaded(): void {\n logScriptLoaded(prefix, buildTime);\n },\n\n setDebug(enabled: boolean): void {\n debugEnabled = logAlways ? true : enabled;\n },\n\n debug: makeLevelMethod(() => debugEnabled, prefix, 'debug'),\n info: makeLevelMethod(() => debugEnabled, prefix, 'info'),\n warn: makeLevelMethod(() => debugEnabled, prefix, 'warn'),\n error: makeLevelMethod(() => debugEnabled, prefix, 'error'),\n };\n}\n","/**\n * Browser Device Intelligence client (shipped as Composer package assets).\n *\n * Collects compact, privacy-aware signals and POSTs them to a same-origin\n * collect endpoint. `collect()` never throws.\n */\n\nimport { DeviceIntelligence } from './client';\nimport { createBundleLogger, setBundleLogger } from './logger';\n\ndeclare const __DEVICE_INTELLIGENCE_BUILD_TIME__: string;\n\nconst log = createBundleLogger('device-intelligence', {\n buildTime:\n typeof __DEVICE_INTELLIGENCE_BUILD_TIME__ !== 'undefined'\n ? __DEVICE_INTELLIGENCE_BUILD_TIME__\n : undefined,\n});\nlog.scriptLoaded();\nsetBundleLogger(log);\n\nexport { DeviceIntelligence };\nexport { MemoryCache } from './cache/memory-cache';\nexport { SDK_VERSION } from './version';\nexport {\n normalizeBrowser,\n normalizeGpuFamily,\n normalizePlatform,\n normalizeScreenClass,\n} from './normalization/normalize';\n\nexport type { Collector } from './types/index';\nexport type { CollectorContext } from './types/index';\nexport type { Signal } from './types/index';\nexport type { DeviceIntelligenceOptions } from './types/index';\nexport type { CollectorsConfig } from './types/index';\nexport type { CacheConfig } from './types/index';\nexport type { CollectResult } from './types/index';\nexport type { CachedObservation } from './types/index';\nexport type { CollectPayload } from './types/index';\nexport type { EntropyCategory } from './types/index';\n"],"mappings":"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"} \ No newline at end of file