diff --git a/package.json b/package.json index dd34e57..833b329 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,7 @@ "jsdom": "^25.0.1", "typescript": "^5.7.2", "typescript-eslint": "^8.19.0", - "vite": "^6.0.7", + "vite": "^8.2.2", "vitest": "^3.0.4" }, "pnpm": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d6a2f12..c13684d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -16,7 +16,7 @@ importers: version: 22.20.1 '@vitest/coverage-v8': specifier: ^3.2.6 - version: 3.2.7(vitest@3.2.7(@types/node@22.20.1)(jsdom@25.0.1)) + version: 3.2.7(vitest@3.2.7(@types/node@22.20.1)(jsdom@25.0.1)(lightningcss@1.33.0)) eslint: specifier: ^9.17.0 version: 9.39.5 @@ -30,11 +30,11 @@ importers: specifier: ^8.19.0 version: 8.67.0(eslint@9.39.5)(typescript@5.9.3) vite: - specifier: ^6.0.7 - version: 6.4.3(@types/node@22.20.1) + specifier: ^8.2.2 + version: 8.2.2(@types/node@22.20.1) vitest: specifier: ^3.0.4 - version: 3.2.7(@types/node@22.20.1)(jsdom@25.0.1) + version: 3.2.7(@types/node@22.20.1)(jsdom@25.0.1)(lightningcss@1.33.0) packages: @@ -336,10 +336,112 @@ packages: os: [linux] libc: [glibc] + '@oxc-project/types@0.146.0': + resolution: {integrity: sha512-XC0QsnnhVe7sLIWmYmdPw7x5P0h4W8vUU3Nv1ySgWXtvCz8NizoAEpGXA0sOYoJQV2Rl13LgURAHQ5cI5ILCSA==} + '@pkgjs/parseargs@0.11.0': resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} + '@rolldown/binding-android-arm-eabi@1.2.5': + resolution: {integrity: sha512-DLe/i+l8ynIBY7XEQ191TeZvCoowIGa18R+dIV30GW7DiOtp74i/xX8hs8GUjW5ARV7VZuie3d6AumSmCwbeRA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [android] + + '@rolldown/binding-android-arm64@1.2.5': + resolution: {integrity: sha512-zXcwKlQApYAOELHd8PwKDFkagYF9Wy4e0RJ+0qnzl9Pjnpj75TEG8ufv40p2J7kCEfwZAsNiuzRIyNNMWT38ig==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [android] + + '@rolldown/binding-darwin-arm64@1.2.5': + resolution: {integrity: sha512-dK4QakI42nzWgJT5sm4y4y/O//D4OxM75/cH28RLV+nzIN9AY+YsbuUVrUTjlLjXR6vpyxFbSsbmNuJ6BP9sww==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [darwin] + + '@rolldown/binding-darwin-x64@1.2.5': + resolution: {integrity: sha512-fqSALaUu1Wjd1nK2uW2kJDWdLCc8lx1IcY+MTY26Aurfdx19anlzhqXOgCFbBFQnlFDTn4TC1/7Nz4Bl2mLP3A==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [darwin] + + '@rolldown/binding-freebsd-x64@1.2.5': + resolution: {integrity: sha512-/vCnNxlkxs9tKxNDcyWUePpJ/PgTzxIaVhoM5SmG8UV+GR/IcPam4VYxi7GIMo7PSDuNqlJqvprqii9NqqVCMw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [freebsd] + + '@rolldown/binding-linux-arm-gnueabihf@1.2.5': + resolution: {integrity: sha512-abk0NLA519LxRCszmbE0jYKuQ9YPocOXTiOXOo6Yr+YAT95VH+PtqYAjOJvGKt3viEd/x4qzabAlwd5bHOOARg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + + '@rolldown/binding-linux-arm64-gnu@1.2.5': + resolution: {integrity: sha512-Y7eALiJ8lr0M2HH103Js+g7V34wf6snlpZLAsHI90uLhr3PVlNsbFVAXJC9d/V6BnPyKtpSwI+NcB/RLxsQxuA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-arm64-musl@1.2.5': + resolution: {integrity: sha512-xMvZgnbZg4YVnR/AX2b3oOPDTFYJvUVaJg5FedA/LuvexAtXibZQej4cnTkw3rjsJ/ggUROB64TdtETiim+FYA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@rolldown/binding-linux-ppc64-gnu@1.2.5': + resolution: {integrity: sha512-GRjeqTUDHTo5GwntsLaAMcBahG3nlpjftXWZLN73HiYQlhwEowvarFgQnRnQZtIp4keXX7quXFbG38uPZBa2EA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-s390x-gnu@1.2.5': + resolution: {integrity: sha512-vLNTR45F2Uwc8AufkNXPmB4VliaXs+FvcheEogIzOXzO4l+LzieXF5A/TWxLy5HtqpsRCHUfd0lPVrrdgXdLHQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-x64-gnu@1.2.5': + resolution: {integrity: sha512-Mgj59/HTuYeK9Gz2MA+mBWKnHsAgkBSec15ZMb1st3oIfFbX7gCjOae7GydHhzcyQi9Z/7M1QuN9bR3oFqF0jQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-x64-musl@1.2.5': + resolution: {integrity: sha512-mY8AP0/ichsbhAxGnLa3d3+MwV0EfgrPND2bplI3Ym8T6R2pJ0N87bvrKVwNXmdy3jnr6eQBecdqx/HMknBmpA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [musl] + + '@rolldown/binding-openharmony-arm64@1.2.5': + resolution: {integrity: sha512-8SLssA2oweAxyRgDp789ACfRb/3P+zNRJpzZxSizxF9m8NUDQ4+3xjo8ttjhVGGw6Qxb70oZiEtIjaKikCO7Yw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [openharmony] + + '@rolldown/binding-win32-arm64-msvc@1.2.5': + resolution: {integrity: sha512-vGbruD5zquhoc8D9SViXgN2FBJtNdTyQ4DtG+SWiEGlJiAzoKcZ2xp+xuXCffhubVdt0NJlTZqkeRuERy7g8Cw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [win32] + + '@rolldown/binding-win32-x64-msvc@1.2.5': + resolution: {integrity: sha512-e/SXpgISz+IoqVcSSI0rx/d/he8zqLex+/rCWpnHpmVfmPIUjag9H6P7zotf0gJHwPUhQxZ/mF8tr6acebT9yw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [win32] + + '@rolldown/pluginutils@1.0.1': + resolution: {integrity: sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==} + '@rollup/rollup-android-arm-eabi@4.62.5': resolution: {integrity: sha512-jfkGfTwhQpsiSckPF8r9bU3pn3vyd72NlWaO+TgEO6WPSDnUhXzrNYCHBMOYj0ACaUgjm6eERLF+XV9a6RstoA==} cpu: [arm] @@ -726,6 +828,10 @@ packages: resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} engines: {node: '>=0.4.0'} + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + engines: {node: '>=8'} + dunder-proto@1.0.1: resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} engines: {node: '>= 0.4'} @@ -1022,6 +1128,80 @@ packages: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} + lightningcss-android-arm64@1.33.0: + resolution: {integrity: sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [android] + + lightningcss-darwin-arm64@1.33.0: + resolution: {integrity: sha512-Sciaz8eenNTKn9b3t7+xr0ipTp9YxKQY4npwQ3mrRuL0BAVHBLyZxofhaKBAVtzmtRZ/zTyo0/to4B1uWG/Djg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + + lightningcss-darwin-x64@1.33.0: + resolution: {integrity: sha512-Z5UPAxzrjlWNNyGy6i65cJzzvgJ5D3T6wMvs+gWpY9d7qRhANrxqAp6LhxIgZhWEw18RfJTGcRxjuLIBr+m8XQ==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + + lightningcss-freebsd-x64@1.33.0: + resolution: {integrity: sha512-QQM/Ti/hQajJwCY+RiWuCZ9sdtI/XQk7nDK5vC8kkdwixezOlDgvDx7+RT+QjK6FcFT4MpsuoBnHIo/O3StRRg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + + lightningcss-linux-arm-gnueabihf@1.33.0: + resolution: {integrity: sha512-N7FVBe6iS24MlM6R/4RBTxGhQheZGs7tiQ9U32UtF75NzP5Q7xWPRqLBCKxlRQRk3rY1jCIPLzx7WzOhuUIRLQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + + lightningcss-linux-arm64-gnu@1.33.0: + resolution: {integrity: sha512-j2v/itmy4HlNxlc6voKXYgBqNi0Ng2LShg4z7GufpEgs05P+2suBVyi9I6YHq5uoVFx9ETin3eCEhLVyXGQnKg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + lightningcss-linux-arm64-musl@1.33.0: + resolution: {integrity: sha512-yiO5ROMuYQgXbC60yjZU5CYSFZGKXL0HFATXt9mHJn1+zW55oCtMI9NfcVhYLMFDL7gV7oBPon/EmMMGg2OvtQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [musl] + + lightningcss-linux-x64-gnu@1.33.0: + resolution: {integrity: sha512-ar+Ju7LmcN0Jo4FpL4hpFybwNG9/3A/Br5KW2n2jyODg3MEZXaDYADdemoNS+BDNfMgKvylJLj4S5tyRActuAg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [glibc] + + lightningcss-linux-x64-musl@1.33.0: + resolution: {integrity: sha512-RYiYbkokw0trfKqqzfF55lginwEPrD3OJDfTuJzFs1MK6iFnDenaz1fqLLtX4ITG3OktJQXOeTaw1awrBAlZPw==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [musl] + + lightningcss-win32-arm64-msvc@1.33.0: + resolution: {integrity: sha512-1K+MPfLSFVpphzpdbfkhlWk6wBrTObBzS2T6db10PNOZgR9GoVsAWzwNyuhUYYbTp23j+4RrncfujZ4uAzXvwA==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] + + lightningcss-win32-x64-msvc@1.33.0: + resolution: {integrity: sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + + lightningcss@1.33.0: + resolution: {integrity: sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==} + engines: {node: '>= 12.0.0'} + locate-path@6.0.0: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} @@ -1150,6 +1330,11 @@ packages: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} + rolldown@1.2.5: + resolution: {integrity: sha512-VD2IE5PUG4Oj8zz2VGykiYd5wbnjdIiSsNQb8Qu5B+noEp+A78mu2iVvpp27g8es14Tk9rofNs5Tku9iQCS4fA==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + rollup@4.62.5: resolution: {integrity: sha512-/tqMfgP7GPA3PHhCmuiS4vIjrSVhHLgY++i+dhbG462euyAj7FpM4D9uq1X3BgjlqRdpcOrYhcQtfiQLNc8tqw==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} @@ -1342,6 +1527,49 @@ packages: yaml: optional: true + vite@8.2.2: + resolution: {integrity: sha512-cFKLV/PRgAUlIRm5WjMjJ86jrftzpqcgH+Us+DS8mI3CDNiH30Whrz8uHL3+MOLPAgqbMBAqWdAHAphOAM+z/Q==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + '@types/node': ^20.19.0 || >=22.12.0 + '@vitejs/devtools': ^0.4.0 || ^0.5.0 + esbuild: ^0.27.0 || ^0.28.0 + jiti: '>=1.21.0' + less: ^4.0.0 + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: '>=0.54.8' + sugarss: ^5.0.0 + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + '@vitejs/devtools': + optional: true + esbuild: + optional: true + jiti: + optional: true + less: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + vitest@3.2.7: resolution: {integrity: sha512-KrxIJ62Fd89gfysR4WotlgZABiz2dqFPgqGzX7s+CwsqLFomRH7777ZcrOD6+WVAh7khPQP41A+BKbpcJFrdEg==} engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} @@ -1654,9 +1882,58 @@ snapshots: '@napi-rs/lzma-linux-x64-gnu@1.5.1': optional: true + '@oxc-project/types@0.146.0': {} + '@pkgjs/parseargs@0.11.0': optional: true + '@rolldown/binding-android-arm-eabi@1.2.5': + optional: true + + '@rolldown/binding-android-arm64@1.2.5': + optional: true + + '@rolldown/binding-darwin-arm64@1.2.5': + optional: true + + '@rolldown/binding-darwin-x64@1.2.5': + optional: true + + '@rolldown/binding-freebsd-x64@1.2.5': + optional: true + + '@rolldown/binding-linux-arm-gnueabihf@1.2.5': + optional: true + + '@rolldown/binding-linux-arm64-gnu@1.2.5': + optional: true + + '@rolldown/binding-linux-arm64-musl@1.2.5': + optional: true + + '@rolldown/binding-linux-ppc64-gnu@1.2.5': + optional: true + + '@rolldown/binding-linux-s390x-gnu@1.2.5': + optional: true + + '@rolldown/binding-linux-x64-gnu@1.2.5': + optional: true + + '@rolldown/binding-linux-x64-musl@1.2.5': + optional: true + + '@rolldown/binding-openharmony-arm64@1.2.5': + optional: true + + '@rolldown/binding-win32-arm64-msvc@1.2.5': + optional: true + + '@rolldown/binding-win32-x64-msvc@1.2.5': + optional: true + + '@rolldown/pluginutils@1.0.1': {} + '@rollup/rollup-android-arm-eabi@4.62.5': optional: true @@ -1838,7 +2115,7 @@ snapshots: '@typescript-eslint/types': 8.67.0 eslint-visitor-keys: 5.0.1 - '@vitest/coverage-v8@3.2.7(vitest@3.2.7(@types/node@22.20.1)(jsdom@25.0.1))': + '@vitest/coverage-v8@3.2.7(vitest@3.2.7(@types/node@22.20.1)(jsdom@25.0.1)(lightningcss@1.33.0))': dependencies: '@ampproject/remapping': 2.3.0 '@bcoe/v8-coverage': 1.0.2 @@ -1853,7 +2130,7 @@ snapshots: std-env: 3.10.0 test-exclude: 7.0.2 tinyrainbow: 2.0.0 - vitest: 3.2.7(@types/node@22.20.1)(jsdom@25.0.1) + vitest: 3.2.7(@types/node@22.20.1)(jsdom@25.0.1)(lightningcss@1.33.0) transitivePeerDependencies: - supports-color @@ -1865,13 +2142,13 @@ snapshots: chai: 5.3.3 tinyrainbow: 2.0.0 - '@vitest/mocker@3.2.7(vite@6.4.3(@types/node@22.20.1))': + '@vitest/mocker@3.2.7(vite@6.4.3(@types/node@22.20.1)(lightningcss@1.33.0))': dependencies: '@vitest/spy': 3.2.7 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 6.4.3(@types/node@22.20.1) + vite: 6.4.3(@types/node@22.20.1)(lightningcss@1.33.0) '@vitest/pretty-format@3.2.7': dependencies: @@ -2017,6 +2294,8 @@ snapshots: delayed-stream@1.0.0: {} + detect-libc@2.1.2: {} + dunder-proto@1.0.1: dependencies: call-bind-apply-helpers: 1.0.2 @@ -2369,6 +2648,55 @@ snapshots: prelude-ls: 1.2.1 type-check: 0.4.0 + lightningcss-android-arm64@1.33.0: + optional: true + + lightningcss-darwin-arm64@1.33.0: + optional: true + + lightningcss-darwin-x64@1.33.0: + optional: true + + lightningcss-freebsd-x64@1.33.0: + optional: true + + lightningcss-linux-arm-gnueabihf@1.33.0: + optional: true + + lightningcss-linux-arm64-gnu@1.33.0: + optional: true + + lightningcss-linux-arm64-musl@1.33.0: + optional: true + + lightningcss-linux-x64-gnu@1.33.0: + optional: true + + lightningcss-linux-x64-musl@1.33.0: + optional: true + + lightningcss-win32-arm64-msvc@1.33.0: + optional: true + + lightningcss-win32-x64-msvc@1.33.0: + optional: true + + lightningcss@1.33.0: + dependencies: + detect-libc: 2.1.2 + optionalDependencies: + lightningcss-android-arm64: 1.33.0 + lightningcss-darwin-arm64: 1.33.0 + lightningcss-darwin-x64: 1.33.0 + lightningcss-freebsd-x64: 1.33.0 + lightningcss-linux-arm-gnueabihf: 1.33.0 + lightningcss-linux-arm64-gnu: 1.33.0 + lightningcss-linux-arm64-musl: 1.33.0 + lightningcss-linux-x64-gnu: 1.33.0 + lightningcss-linux-x64-musl: 1.33.0 + lightningcss-win32-arm64-msvc: 1.33.0 + lightningcss-win32-x64-msvc: 1.33.0 + locate-path@6.0.0: dependencies: p-locate: 5.0.0 @@ -2479,6 +2807,27 @@ snapshots: resolve-from@4.0.0: {} + rolldown@1.2.5: + dependencies: + '@oxc-project/types': 0.146.0 + '@rolldown/pluginutils': 1.0.1 + optionalDependencies: + '@rolldown/binding-android-arm-eabi': 1.2.5 + '@rolldown/binding-android-arm64': 1.2.5 + '@rolldown/binding-darwin-arm64': 1.2.5 + '@rolldown/binding-darwin-x64': 1.2.5 + '@rolldown/binding-freebsd-x64': 1.2.5 + '@rolldown/binding-linux-arm-gnueabihf': 1.2.5 + '@rolldown/binding-linux-arm64-gnu': 1.2.5 + '@rolldown/binding-linux-arm64-musl': 1.2.5 + '@rolldown/binding-linux-ppc64-gnu': 1.2.5 + '@rolldown/binding-linux-s390x-gnu': 1.2.5 + '@rolldown/binding-linux-x64-gnu': 1.2.5 + '@rolldown/binding-linux-x64-musl': 1.2.5 + '@rolldown/binding-openharmony-arm64': 1.2.5 + '@rolldown/binding-win32-arm64-msvc': 1.2.5 + '@rolldown/binding-win32-x64-msvc': 1.2.5 + rollup@4.62.5: dependencies: '@types/estree': 1.0.9 @@ -2633,13 +2982,13 @@ snapshots: dependencies: punycode: 2.3.1 - vite-node@3.2.4(@types/node@22.20.1): + vite-node@3.2.4(@types/node@22.20.1)(lightningcss@1.33.0): dependencies: cac: 6.7.14 debug: 4.4.3 es-module-lexer: 1.7.0 pathe: 2.0.3 - vite: 6.4.3(@types/node@22.20.1) + vite: 6.4.3(@types/node@22.20.1)(lightningcss@1.33.0) transitivePeerDependencies: - '@types/node' - jiti @@ -2654,7 +3003,7 @@ snapshots: - tsx - yaml - vite@6.4.3(@types/node@22.20.1): + vite@6.4.3(@types/node@22.20.1)(lightningcss@1.33.0): dependencies: esbuild: 0.25.12 fdir: 6.5.0(picomatch@4.0.5) @@ -2665,12 +3014,24 @@ snapshots: optionalDependencies: '@types/node': 22.20.1 fsevents: 2.3.3 + lightningcss: 1.33.0 + + vite@8.2.2(@types/node@22.20.1): + dependencies: + lightningcss: 1.33.0 + picomatch: 4.0.5 + postcss: 8.5.26 + rolldown: 1.2.5 + tinyglobby: 0.2.17 + optionalDependencies: + '@types/node': 22.20.1 + fsevents: 2.3.3 - vitest@3.2.7(@types/node@22.20.1)(jsdom@25.0.1): + vitest@3.2.7(@types/node@22.20.1)(jsdom@25.0.1)(lightningcss@1.33.0): dependencies: '@types/chai': 5.2.3 '@vitest/expect': 3.2.7 - '@vitest/mocker': 3.2.7(vite@6.4.3(@types/node@22.20.1)) + '@vitest/mocker': 3.2.7(vite@6.4.3(@types/node@22.20.1)(lightningcss@1.33.0)) '@vitest/pretty-format': 3.2.7 '@vitest/runner': 3.2.7 '@vitest/snapshot': 3.2.7 @@ -2688,8 +3049,8 @@ snapshots: tinyglobby: 0.2.17 tinypool: 1.1.1 tinyrainbow: 2.0.0 - vite: 6.4.3(@types/node@22.20.1) - vite-node: 3.2.4(@types/node@22.20.1) + vite: 6.4.3(@types/node@22.20.1)(lightningcss@1.33.0) + vite-node: 3.2.4(@types/node@22.20.1)(lightningcss@1.33.0) why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 22.20.1 diff --git a/src/Resources/public/js/device-intelligence.min.js b/src/Resources/public/js/device-intelligence.min.js index 74e8f9f..fb2371f 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(m){"use strict";const S={script:"color:#0ea5e9;font-weight:bold",debug:"color:#6b7280",info:"color:#2563eb",warn:"color:#d97706",error:"color:#dc2626;font-weight:bold"},A={script:"đŸ“Ļ",debug:"🔍",info:"â„šī¸",warn:"âš ī¸",error:"❌"};function W(n){return n.map(t=>typeof t=="object"&&t!==null&&!(t instanceof Error)?JSON.stringify(t):t)}function q(n,t){if(t!==void 0&&t!==""){console.log(`%c${A.script} ${n} script loaded, build time: %c${t}`,S.script,"color:#059669");return}console.log(`%c${A.script} ${n} script loaded`,S.script)}function U(n,t,e){const r=A[n],o=S[n],i=`%c${r} ${t}`,a=console[n];if(e.length>0){a(i,o,...W(e));return}a(i,o)}function w(n,t,e){return(...r)=>{n()&&U(e,t,r)}}function $(n,t={}){const e=`[${n}]`,{buildTime:r,alwaysLog:o=!1}=t,i=o===!0;let a=i;return{scriptLoaded(){q(e,r)},setDebug(s){a=i?!0:s},debug:w(()=>a,e,"debug"),info:w(()=>a,e,"info"),warn:w(()=>a,e,"warn"),error:w(()=>a,e,"error")}}class I{entry=null;get(){return this.entry===null?null:Date.now()>=this.entry.expiresAt?(this.entry=null,null):this.entry.value}set(t,e){const r=e*1e3;this.entry={value:t,expiresAt:Date.now()+r},r<=0&&(this.entry=null)}clear(){this.entry=null}has(){return this.get()!==null}}const j=16;async function G(n){const t=globalThis.crypto?.subtle;if(!t)throw new Error("WebCrypto SubtleCrypto is not available");const e=typeof n=="string"?new TextEncoder().encode(n):n,r=await t.digest("SHA-256",e),o=new Uint8Array(r);let i="";for(let a=0;a1?1:n}function d(n){return{name:n.name,value:n.value,normalizedValue:n.normalizedValue,quality:D(n.quality),stability:D(n.stability),entropyCategory:n.entropyCategory,collectedAt:n.collectedAt??Date.now()}}function X(n){return new Promise((t,e)=>{const r=()=>{e(new DOMException("The operation was aborted.","AbortError"))};if(n.aborted){r();return}n.addEventListener("abort",r,{once:!0})})}function x(n,t){return Promise.race([n,X(t)])}function f(n){if(n.abortSignal.aborted)throw new DOMException("The operation was aborted.","AbortError")}const Z=44100,J=44100,K=256;class Y{name="audio";async collect(t){f(t);const e=Q();if(!e)throw new Error("OfflineAudioContext is not available");const r=new e(1,J,Z),o=r.createOscillator();o.type="triangle",o.frequency.value=1e4;const i=r.createDynamicsCompressor();i.threshold.value=-50,i.knee.value=40,i.ratio.value=12,i.attack.value=0,i.release.value=.25,o.connect(i),i.connect(r.destination),o.start(0);const s=(await x(r.startRendering(),t.abortSignal)).getChannelData(0),u=ee(s,K),c=await T(u.join(","));return d({name:this.name,value:c,normalizedValue:c,quality:.85,stability:.9,entropyCategory:"high"})}}function Q(){const n=globalThis;return n.OfflineAudioContext??n.webkitOfflineAudioContext??null}function ee(n,t){const e=Math.max(1,Math.floor(n.length/t)),r=[];for(let o=0;o"u"?null:navigator,o=r?.userAgent??"";r&&r.webdriver===!0&&e.push("webdriver"),!r||!Array.isArray(r.languages)||r.languages.length===0?e.push("missing-languages"):r.language&&r.languages[0]&&r.language!==r.languages[0]&&e.push("language-mismatch"),!r||typeof r.hardwareConcurrency!="number"?e.push("missing-hardware-concurrency"):(r.hardwareConcurrency<=0||r.hardwareConcurrency>128)&&e.push("implausible-hardware-concurrency"),/headless/i.test(o)&&e.push("headless-ua"),/HeadlessChrome/i.test(o)&&e.push("headless-chrome"),typeof window<"u"&&window.outerWidth===0&&window.outerHeight===0&&e.push("zero-outer-size");const i=D(e.reduce((s,u)=>s+(te[u]??.15),0)),a={indicators:e,confidence:i};return d({name:this.name,value:a,normalizedValue:a,quality:.8,stability:.5,entropyCategory:"low"})}}const _=280,M=80;class re{name="canvas";async collect(t){if(f(t),typeof document>"u")throw new Error("document is not available");const e=document.createElement("canvas");e.width=_,e.height=M,e.style.display="none";const r=e.getContext("2d",{willReadFrequently:!0});if(!r)throw new Error("CanvasRenderingContext2D is not available");oe(r);const o=r.getImageData(0,0,_,M),i=await T(o.data);return d({name:this.name,value:i,normalizedValue:i,quality:.92,stability:.95,entropyCategory:"high"})}}function oe(n){n.fillStyle="#f60",n.fillRect(8,8,90,48),n.fillStyle="#069",n.fillRect(108,12,70,40),n.strokeStyle="#111827",n.lineWidth=2,n.beginPath(),n.arc(220,36,26,0,Math.PI*2),n.stroke(),n.beginPath(),n.arc(248,52,14,.25*Math.PI,1.6*Math.PI),n.stroke(),n.fillStyle="#111827",n.font="16px Arial, sans-serif",n.textBaseline="top",n.fillText("DeviceIntelligence",12,58),n.fillStyle="rgba(16, 185, 129, 0.45)",n.fillRect(40,20,36,18)}class ie{name="capabilities";async collect(t){f(t);const e=typeof navigator>"u"?null:navigator,r=typeof window>"u"?null:window,o={cookieEnabled:e?.cookieEnabled??!1,pdfViewerEnabled:!!e?.pdfViewerEnabled,serviceWorker:!!(e&&"serviceWorker"in e),webgl:ae(),webgpu:!!(e&&"gpu"in e),wasm:typeof WebAssembly<"u",sharedArrayBuffer:typeof SharedArrayBuffer<"u",touch:(e?.maxTouchPoints??0)>0,matchMedia:typeof r?.matchMedia=="function",localStorage:V("localStorage"),sessionStorage:V("sessionStorage"),indexedDB:typeof indexedDB<"u"},i=Object.entries(o).filter(([,a])=>a).map(([a])=>a).sort();return d({name:this.name,value:o,normalizedValue:i,quality:.9,stability:.9,entropyCategory:"medium"})}}function ae(){if(typeof document>"u"||typeof navigator<"u"&&/jsdom/i.test(navigator.userAgent))return!1;try{const n=document.createElement("canvas");return!!(n.getContext("webgl")||n.getContext("experimental-webgl"))}catch{return!1}}function V(n){try{const t=globalThis[n],e="__di_cap__";return t.setItem(e,"1"),t.removeItem(e),!0}catch{return!1}}function v(n){const t=n.trim();return t.length===0?"other":/Edg(?:e|A|iOS)?\/|\bEdge\//i.test(t)||/^Edge\s/i.test(t)?y(t,"Edge",/(?:Edg(?:e|A|iOS)?|Edge)[/\s](\d+)/i):/\bOPR\/|\bOpera\//i.test(t)||/^Opera\s/i.test(t)?y(t,"Opera",/(?:OPR|Opera)[/\s](\d+)/i):/\bFirefox\/|\bFxiOS\//i.test(t)||/^Firefox\s/i.test(t)?y(t,"Firefox",/(?:Firefox|FxiOS)[/\s](\d+)/i):/^Chrome\s+\d+/i.test(t)?y(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)?y(t,"Safari",/(?:Version|Safari)[/\s](\d+)/i):/\b(Chrome|Chromium|CriOS)\//i.test(t)?y(t,"Chrome",/(?:Chrome|Chromium|CriOS)\/(\d+)/i):"other"}function y(n,t,e){const o=n.match(e)?.[1];return o?`${t} ${o}`:t}function E(n){const t=n.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 P(n,t){const e=Math.max(n,t);return!Number.isFinite(e)||e<=0?"other":e<=480?"mobile-s":e<=767?"mobile-l":e<=1280?"tablet":e<=1920?"hd":e<=2560?"qhd":e<=3840?"uhd":"other"}function N(n,t){const e=`${n} ${t}`.toLowerCase();return e.includes("apple")||e.includes("metal")?"apple":e.includes("nvidia")||e.includes("geforce")||e.includes("quadro")?"nvidia":e.includes("amd")||e.includes("radeon")||e.includes("ati")?"amd":e.includes("intel")?"intel":e.includes("mali")?"mali":e.includes("adreno")?"adreno":"other"}const se=["architecture","bitness","model","platformVersion","uaFullVersion","fullVersionList"];class le{name="client_hints";async collect(t){if(f(t),typeof navigator>"u")throw new Error("navigator is not available");const e=navigator.userAgentData;if(!e)return d({name:this.name,value:{brands:[],mobile:null,platform:"",highEntropy:!1,available:!1},normalizedValue:{browser:v(navigator.userAgent??""),platform:E(navigator.platform??navigator.userAgent??""),highEntropy:!1},quality:.35,stability:.7,entropyCategory:"medium"});const r={brands:Array.isArray(e.brands)?e.brands:[],mobile:typeof e.mobile=="boolean"?e.mobile:null,platform:e.platform??"",highEntropy:!1,available:!0};let o={},i=!1;if(t.consent.highEntropy&&typeof e.getHighEntropyValues=="function")try{o=await x(e.getHighEntropyValues([...se]),t.abortSignal),i=!0}catch{i=!1}const a={...r,...o,highEntropy:i},s=ce(r.brands),u=typeof o.uaFullVersion=="string"?String(o.uaFullVersion):s?.version??"",c=s?`${s.brand} ${u}`:navigator.userAgent;return d({name:this.name,value:a,normalizedValue:{browser:v(c),platform:E(r.platform||navigator.platform||""),highEntropy:i},quality:i?.95:.7,stability:.75,entropyCategory:"medium"})}}function ce(n){return n.find(e=>{const r=e.brand.toLowerCase();return r!=="not?a;brand"&&r!=="not a;brand"&&!r.includes("not:")})??n[0]??null}const z="mmmmmmmmmmlli",F="monospace",ue=["Arial","Times New Roman","Courier New","Georgia","Verdana","Roboto"];class de{name="fonts";async collect(t){if(f(t),typeof document>"u"||!document.body)throw new Error("document.body is not available");const e=L(z,F),r=ue.filter(o=>L(z,`${o}, ${F}`)!==e);return d({name:this.name,value:r,normalizedValue:[...r].sort(),quality:.7,stability:.8,entropyCategory:"high"})}}function L(n,t){const e=document.createElement("span");e.style.cssText=["position:absolute","left:-9999px","top:0","visibility:hidden","white-space:nowrap",`font:72px ${t}`].join(";"),e.textContent=n,document.body.appendChild(e);const r=e.offsetWidth;return document.body.removeChild(e),r}class fe{name="navigator";async collect(t){if(f(t),typeof navigator>"u")throw new Error("navigator is not available");const e=navigator.userAgent??"",r=navigator.platform??"",o=Array.isArray(navigator.languages)?[...navigator.languages]:[],i=navigator,a={userAgent:e,platform:r,language:navigator.language??"",languages:o,hardwareConcurrency:navigator.hardwareConcurrency??null,deviceMemory:typeof i.deviceMemory=="number"?i.deviceMemory:null,maxTouchPoints:navigator.maxTouchPoints??0,vendor:navigator.vendor??""},s=v(e),u=E(r||e);return d({name:this.name,value:a,normalizedValue:{browser:s,platform:u,hardwareConcurrency:a.hardwareConcurrency},quality:e.length>0?.9:.4,stability:.8,entropyCategory:"medium"})}}class he{name="screen";async collect(t){f(t);const e=typeof screen>"u"?null:screen;if(!e)throw new Error("screen is not available");const r=g(e.width),o=g(e.height),i={width:r,height:o,availWidth:g(e.availWidth),availHeight:g(e.availHeight),colorDepth:g(e.colorDepth),pixelDepth:g(e.pixelDepth),pixelRatio:g(typeof devicePixelRatio=="number"?devicePixelRatio:1)},a=P(r,o);return d({name:this.name,value:i,normalizedValue:{screenClass:a,width:r,height:o},quality:r>0&&o>0?.95:.4,stability:.7,entropyCategory:"low"})}}function g(n){return Number.isFinite(n)?n:0}class me{name="timezone";async collect(t){f(t);let e="UTC";try{e=Intl.DateTimeFormat().resolvedOptions().timeZone||"UTC"}catch{e="UTC"}const r=new Date().getTimezoneOffset(),o={timeZone:e,offsetMinutes:r};return d({name:this.name,value:o,normalizedValue:e,quality:e.length>0?.99:.3,stability:.85,entropyCategory:"low"})}}class ge{name="webgl";async collect(t){if(f(t),typeof document>"u")throw new Error("document is not available");const e=document.createElement("canvas");e.width=1,e.height=1;const r=ye(e);if(!r)throw new Error("WebGL is not available");try{const o=r.getExtension("WEBGL_debug_renderer_info"),i=k(r,o?o.UNMASKED_VENDOR_WEBGL:r.VENDOR),a=k(r,o?o.UNMASKED_RENDERER_WEBGL:r.RENDERER),s=r.getSupportedExtensions()??[],u=await T([...s].sort().join(",")),c=r.getParameter(r.MAX_VIEWPORT_DIMS),p={maxTextureSize:C(r,r.MAX_TEXTURE_SIZE),maxViewportDims:Array.isArray(c)?[Number(c[0]),Number(c[1])]:c instanceof Int32Array?[c[0]??0,c[1]??0]:null,maxRenderbufferSize:C(r,r.MAX_RENDERBUFFER_SIZE),maxVertexAttribs:C(r,r.MAX_VERTEX_ATTRIBS),maxFragmentUniformVectors:C(r,r.MAX_FRAGMENT_UNIFORM_VECTORS)},O={vendor:i,renderer:a,extensionsHash:u,limits:p},l=typeof a=="string"&&a.length>0,b=l&&o?.88:l?.7:.45;return d({name:this.name,value:O,normalizedValue:{gpuFamily:N(i??"",a??""),extensionsHash:u,maxTextureSize:p.maxTextureSize},quality:b,stability:.95,entropyCategory:"high"})}finally{r.getExtension("WEBGL_lose_context")?.loseContext()}}}function ye(n){const t={alpha:!0,antialias:!1,depth:!1,failIfMajorPerformanceCaveat:!1,preserveDrawingBuffer:!1},e=n.getContext("webgl",t);return e||n.getContext("experimental-webgl",t)}function k(n,t){try{const e=n.getParameter(t);return typeof e=="string"&&e.length>0?e:null}catch{return null}}function C(n,t){try{const e=n.getParameter(t);return typeof e=="number"&&Number.isFinite(e)?e:null}catch{return null}}async function pe(n,t,e){try{const r=await fetch(n,{method:"POST",credentials:"same-origin",headers:{"Content-Type":"application/json"},body:JSON.stringify(t),signal:e});if(!r.ok)return null;const o=await r.text();if(o.trim().length===0)return{ok:!0};const i=JSON.parse(o);return i===null||typeof i!="object"?{ok:!0}:i}catch{return null}}const B="1.0.0",be="/_device/collect",we=1500,ve=3600,Ee={audio:!0,canvas:!0,webgl:!0,screen:!0,timezone:!0,navigator:!0,clientHints:!0,capabilities:!0,automation:!0,fonts:!1};class Ce{endpoint;timeout;cacheTtl;cacheEnabled;consent;cache=new I;collectors=[];constructor(t={}){this.endpoint=t.endpoint??be,this.timeout=Ae(t.timeout),this.cacheEnabled=t.cache?.enabled??!0,this.cacheTtl=t.cache?.ttl??ve,this.consent={highEntropy:t.consent?.highEntropy??!0},this.collectors=Se({...Ee,...t.collectors})}async collect(){return this.runCollect(!1)}async refresh(){return this.runCollect(!0)}getCachedObservation(){return this.cache.get()}clear(){this.cache.clear()}registerCollector(t){this.collectors.push(t)}async runCollect(t){try{if(!t&&this.cacheEnabled){const H=this.cache.get();if(H)return H.result}const e=new AbortController,r=globalThis.setTimeout(()=>e.abort(),this.timeout),o={timeout:this.timeout,abortSignal:e.signal,consent:this.consent};let i={};try{i=await this.collectSignals(o)}finally{globalThis.clearTimeout(r)}const a=this.collectors.length,s=Object.keys(i).length,u=sp.abort(),this.timeout);let l=null;try{l=await pe(this.endpoint,c,p.signal)}finally{globalThis.clearTimeout(O)}const b=l===null,R=s>0,h={ok:!b&&R&&l?.ok!==!1,degraded:!!l?.degraded||u||b||!R,signals:i};l?.new!==void 0&&(h.new=l.new),l?.token!==void 0&&(h.token=l.token),l?.expiresAt!==void 0&&(h.expiresAt=l.expiresAt),l?.deviceId!==void 0&&(h.deviceId=l.deviceId),l?.confidence!==void 0&&(h.confidence=l.confidence),l?.risk!==void 0&&(h.risk=l.risk),(b||!R)&&(h.ok=!1,h.degraded=!0);const xe={timestamp:Date.now(),signals:i,result:h};return this.cacheEnabled&&this.cache.set(xe,this.cacheTtl),h}catch{return{ok:!1,degraded:!0,signals:{}}}}async collectSignals(t){const e={},r=this.collectors.map(async a=>{try{const s=await x(a.collect(t),t.abortSignal);s&&typeof s.name=="string"&&(e[s.name]=s)}catch{}}),o=Promise.all(r),i=De(this.timeout,t.abortSignal);return await Promise.race([o,i]),await Promise.allSettled(r),e}toPayload(t){const e={};for(const[r,o]of Object.entries(t))e[r]={value:o.value,quality:o.quality,collectedAt:o.collectedAt};return{v:1,sdkVersion:B,timestamp:Math.floor(Date.now()/1e3),nonce:Te(),consent:this.consent,signals:e}}}function Se(n){const t=[];return n.navigator&&t.push(new fe),n.clientHints&&t.push(new le),n.screen&&t.push(new he),n.timezone&&t.push(new me),n.capabilities&&t.push(new ie),n.automation&&t.push(new ne),n.canvas&&t.push(new re),n.webgl&&t.push(new ge),n.audio&&t.push(new Y),n.fonts&&t.push(new de),t}function Ae(n){return typeof n=="number"&&Number.isFinite(n)&&n>0?n:we}function Te(){const n=new Uint8Array(16);if(globalThis.crypto?.getRandomValues)globalThis.crypto.getRandomValues(n);else for(let e=0;e{if(t.aborted){e();return}const r=globalThis.setTimeout(e,n);t.addEventListener("abort",()=>{globalThis.clearTimeout(r),e()},{once:!0})})}return $("device-intelligence",{buildTime:"2026-08-23T10:43:26.599Z"}).scriptLoaded(),m.DeviceIntelligence=Ce,m.MemoryCache=I,m.SDK_VERSION=B,m.normalizeBrowser=v,m.normalizeGpuFamily=N,m.normalizePlatform=E,m.normalizeScreenClass=P,Object.defineProperty(m,Symbol.toStringTag,{value:"Module"}),m})({});globalThis.DeviceIntelligence=DeviceIntelligence.DeviceIntelligence; -//# sourceMappingURL=device-intelligence.min.js.map +var DeviceIntelligence=(function(e){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});var t={script:`color:#0ea5e9;font-weight:bold`,debug:`color:#6b7280`,info:`color:#2563eb`,warn:`color:#d97706`,error:`color:#dc2626;font-weight:bold`},n={script:`đŸ“Ļ`,debug:`🔍`,info:`â„šī¸`,warn:`âš ī¸`,error:`❌`};function r(e){return e.map(e=>typeof e==`object`&&e&&!(e instanceof Error)?JSON.stringify(e):e)}function i(e,r){if(r!==void 0&&r!==``){console.log(`%c${n.script} ${e} script loaded, build time: %c${r}`,t.script,`color:#059669`);return}console.log(`%c${n.script} ${e} script loaded`,t.script)}function a(e,i,a){let o=n[e],s=t[e],c=`%c${o} ${i}`,l=console[e];if(a.length>0){l(c,s,...r(a));return}l(c,s)}function o(e,t,n){return(...r)=>{e()&&a(n,t,r)}}function s(e,t={}){let n=`[${e}]`,{buildTime:r,alwaysLog:a=!1}=t,s=a===!0,c=s;return{scriptLoaded(){i(n,r)},setDebug(e){c=s?!0:e},debug:o(()=>c,n,`debug`),info:o(()=>c,n,`info`),warn:o(()=>c,n,`warn`),error:o(()=>c,n,`error`)}}var c=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}},l=16;async function u(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 p(e){return{name:e.name,value:e.value,normalizedValue:e.normalizedValue,quality:f(e.quality),stability:f(e.stability),entropyCategory:e.entropyCategory,collectedAt:e.collectedAt??Date.now()}}function m(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 h(e,t){return Promise.race([e,m(t)])}function g(e){if(e.abortSignal.aborted)throw new DOMException(`The operation was aborted.`,`AbortError`)}var ee=44100,_=44100,v=256,y=class{name=`audio`;async collect(e){g(e);let t=b();if(!t)throw Error(`OfflineAudioContext is not available`);let n=new t(1,_,ee),r=n.createOscillator();r.type=`triangle`,r.frequency.value=1e4;let i=n.createDynamicsCompressor();i.threshold.value=-50,i.knee.value=40,i.ratio.value=12,i.attack.value=0,i.release.value=.25,r.connect(i),i.connect(n.destination),r.start(0);let a=await d(x((await h(n.startRendering(),e.abortSignal)).getChannelData(0),v).join(`,`));return p({name:this.name,value:a,normalizedValue:a,quality:.85,stability:.9,entropyCategory:`high`})}};function b(){let e=globalThis;return e.OfflineAudioContext??e.webkitOfflineAudioContext??null}function x(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:f(t.reduce((e,t)=>e+(S[t]??.15),0))};return p({name:this.name,value:i,normalizedValue:i,quality:.8,stability:.5,entropyCategory:`low`})}},w=280,T=80,E=class{name=`canvas`;async collect(e){if(g(e),typeof document>`u`)throw Error(`document is not available`);let t=document.createElement(`canvas`);t.width=w,t.height=T,t.style.display=`none`;let n=t.getContext(`2d`,{willReadFrequently:!0});if(!n)throw Error(`CanvasRenderingContext2D is not available`);D(n);let r=await d(n.getImageData(0,0,w,T).data);return p({name:this.name,value:r,normalizedValue:r,quality:.92,stability:.95,entropyCategory:`high`})}};function D(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 O=class{name=`capabilities`;async collect(e){g(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:k(),webgpu:!!(t&&`gpu`in t),wasm:typeof WebAssembly<`u`,sharedArrayBuffer:typeof SharedArrayBuffer<`u`,touch:(t?.maxTouchPoints??0)>0,matchMedia:typeof n?.matchMedia==`function`,localStorage:A(`localStorage`),sessionStorage:A(`sessionStorage`),indexedDB:typeof indexedDB<`u`},i=Object.entries(r).filter(([,e])=>e).map(([e])=>e).sort();return p({name:this.name,value:r,normalizedValue:i,quality:.9,stability:.9,entropyCategory:`medium`})}};function k(){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 A(e){try{let t=globalThis[e],n=`__di_cap__`;return t.setItem(n,`1`),t.removeItem(n),!0}catch{return!1}}function j(e){let t=e.trim();return t.length===0?`other`:/Edg(?:e|A|iOS)?\/|\bEdge\//i.test(t)||/^Edge\s/i.test(t)?M(t,`Edge`,/(?:Edg(?:e|A|iOS)?|Edge)[/\s](\d+)/i):/\bOPR\/|\bOpera\//i.test(t)||/^Opera\s/i.test(t)?M(t,`Opera`,/(?:OPR|Opera)[/\s](\d+)/i):/\bFirefox\/|\bFxiOS\//i.test(t)||/^Firefox\s/i.test(t)?M(t,`Firefox`,/(?:Firefox|FxiOS)[/\s](\d+)/i):/^Chrome\s+\d+/i.test(t)?M(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)?M(t,`Safari`,/(?:Version|Safari)[/\s](\d+)/i):/\b(Chrome|Chromium|CriOS)\//i.test(t)?M(t,`Chrome`,/(?:Chrome|Chromium|CriOS)\/(\d+)/i):`other`}function M(e,t,n){let r=e.match(n)?.[1];return r?`${t} ${r}`:t}function N(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 P(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 F(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 I=[`architecture`,`bitness`,`model`,`platformVersion`,`uaFullVersion`,`fullVersionList`],L=class{name=`client_hints`;async collect(e){if(g(e),typeof navigator>`u`)throw Error(`navigator is not available`);let t=navigator.userAgentData;if(!t)return p({name:this.name,value:{brands:[],mobile:null,platform:``,highEntropy:!1,available:!1},normalizedValue:{browser:j(navigator.userAgent??``),platform:N(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 h(t.getHighEntropyValues([...I]),e.abortSignal),i=!0}catch{i=!1}let a={...n,...r,highEntropy:i},o=R(n.brands),s=typeof r.uaFullVersion==`string`?String(r.uaFullVersion):o?.version??``,c=o?`${o.brand} ${s}`:navigator.userAgent;return p({name:this.name,value:a,normalizedValue:{browser:j(c),platform:N(n.platform||navigator.platform||``),highEntropy:i},quality:i?.95:.7,stability:.75,entropyCategory:`medium`})}};function R(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 z=`mmmmmmmmmmlli`,B=`monospace`,V=[`Arial`,`Times New Roman`,`Courier New`,`Georgia`,`Verdana`,`Roboto`],H=class{name=`fonts`;async collect(e){if(g(e),typeof document>`u`||!document.body)throw Error(`document.body is not available`);let t=U(z,B),n=V.filter(e=>U(z,`${e}, ${B}`)!==t);return p({name:this.name,value:n,normalizedValue:[...n].sort(),quality:.7,stability:.8,entropyCategory:`high`})}};function U(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 W=class{name=`navigator`;async collect(e){if(g(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??``},o=j(t),s=N(n||t);return p({name:this.name,value:a,normalizedValue:{browser:o,platform:s,hardwareConcurrency:a.hardwareConcurrency},quality:t.length>0?.9:.4,stability:.8,entropyCategory:`medium`})}},G=class{name=`screen`;async collect(e){g(e);let t=typeof screen>`u`?null:screen;if(!t)throw Error(`screen is not available`);let n=K(t.width),r=K(t.height),i={width:n,height:r,availWidth:K(t.availWidth),availHeight:K(t.availHeight),colorDepth:K(t.colorDepth),pixelDepth:K(t.pixelDepth),pixelRatio:K(typeof devicePixelRatio==`number`?devicePixelRatio:1)},a=P(n,r);return p({name:this.name,value:i,normalizedValue:{screenClass:a,width:n,height:r},quality:n>0&&r>0?.95:.4,stability:.7,entropyCategory:`low`})}};function K(e){return Number.isFinite(e)?e:0}var q=class{name=`timezone`;async collect(e){g(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 p({name:this.name,value:r,normalizedValue:t,quality:t.length>0?.99:.3,stability:.85,entropyCategory:`low`})}},J=class{name=`webgl`;async collect(e){if(g(e),typeof document>`u`)throw Error(`document is not available`);let t=document.createElement(`canvas`);t.width=1,t.height=1;let n=Y(t);if(!n)throw Error(`WebGL is not available`);try{let e=n.getExtension(`WEBGL_debug_renderer_info`),t=X(n,e?e.UNMASKED_VENDOR_WEBGL:n.VENDOR),r=X(n,e?e.UNMASKED_RENDERER_WEBGL:n.RENDERER),i=await d([...n.getSupportedExtensions()??[]].sort().join(`,`)),a=n.getParameter(n.MAX_VIEWPORT_DIMS),o={maxTextureSize:Z(n,n.MAX_TEXTURE_SIZE),maxViewportDims:Array.isArray(a)?[Number(a[0]),Number(a[1])]:a instanceof Int32Array?[a[0]??0,a[1]??0]:null,maxRenderbufferSize:Z(n,n.MAX_RENDERBUFFER_SIZE),maxVertexAttribs:Z(n,n.MAX_VERTEX_ATTRIBS),maxFragmentUniformVectors:Z(n,n.MAX_FRAGMENT_UNIFORM_VECTORS)},s={vendor:t,renderer:r,extensionsHash:i,limits:o},c=typeof r==`string`&&r.length>0,l=c&&e?.88:c?.7:.45;return p({name:this.name,value:s,normalizedValue:{gpuFamily:F(t??``,r??``),extensionsHash:i,maxTextureSize:o.maxTextureSize},quality:l,stability:.95,entropyCategory:`high`})}finally{n.getExtension(`WEBGL_lose_context`)?.loseContext()}}};function Y(e){let t={alpha:!0,antialias:!1,depth:!1,failIfMajorPerformanceCaveat:!1,preserveDrawingBuffer:!1};return e.getContext(`webgl`,t)||e.getContext(`experimental-webgl`,t)}function X(e,t){try{let n=e.getParameter(t);return typeof n==`string`&&n.length>0?n:null}catch{return null}}function Z(e,t){try{let n=e.getParameter(t);return typeof n==`number`&&Number.isFinite(n)?n:null}catch{return null}}async function Q(e,t,n){try{let r=await fetch(e,{method:`POST`,credentials:`same-origin`,headers:{"Content-Type":`application/json`},body:JSON.stringify(t),signal:n});if(!r.ok)return null;let i=await r.text();if(i.trim().length===0)return{ok:!0};let a=JSON.parse(i);return typeof a!=`object`||!a?{ok:!0}:a}catch{return null}}var $=`1.0.0`,te=`/_device/collect`,ne=1500,re=3600,ie={audio:!0,canvas:!0,webgl:!0,screen:!0,timezone:!0,navigator:!0,clientHints:!0,capabilities:!0,automation:!0,fonts:!1},ae=class{endpoint;timeout;cacheTtl;cacheEnabled;consent;cache=new c;collectors=[];constructor(e={}){this.endpoint=e.endpoint??te,this.timeout=se(e.timeout),this.cacheEnabled=e.cache?.enabled??!0,this.cacheTtl=e.cache?.ttl??re,this.consent={highEntropy:e.consent?.highEntropy??!0},this.collectors=oe({...ie,...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 Q(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 h(n.collect(e),e.abortSignal);r&&typeof r.name==`string`&&(t[r.name]=r)}catch{}}),r=Promise.all(n),i=le(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:$,timestamp:Math.floor(Date.now()/1e3),nonce:ce(),consent:this.consent,signals:t}}};function oe(e){let t=[];return e.navigator&&t.push(new W),e.clientHints&&t.push(new L),e.screen&&t.push(new G),e.timezone&&t.push(new q),e.capabilities&&t.push(new O),e.automation&&t.push(new C),e.canvas&&t.push(new E),e.webgl&&t.push(new J),e.audio&&t.push(new y),e.fonts&&t.push(new H),t}function se(e){return typeof e==`number`&&Number.isFinite(e)&&e>0?e:ne}function ce(){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})})}return s(`device-intelligence`,{buildTime:`2026-08-24T08:02:34.524Z`}).scriptLoaded(),e.DeviceIntelligence=ae,e.MemoryCache=c,e.SDK_VERSION=$,e.normalizeBrowser=j,e.normalizeGpuFamily=F,e.normalizePlatform=N,e.normalizeScreenClass=P,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 95f0c10..bbbe589 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","sources":["../../assets/src/logger.ts","../../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/index.ts"],"sourcesContent":["/**\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 * 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\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 response = await fetch(endpoint, {\n method: 'POST',\n credentials: 'same-origin',\n headers: {\n 'Content-Type': 'application/json',\n },\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 * 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 { 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 } from './client';\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"],"names":["STYLES","EMOJI","formatArgs","args","a","logScriptLoaded","prefix","buildTime","emitLevelLog","level","emoji","style","label","logFn","makeLevelMethod","isEnabled","createBundleLogger","name","options","alwaysLog","logAlways","debugEnabled","enabled","MemoryCache","value","ttlSeconds","ttlMs","HEX","sha256Hex","data","subtle","bytes","hash","view","hex","i","compactDigest","length","clamp01","createSignal","input","rejectedWhenAborted","signal","_resolve","reject","abort","raceAbort","promise","throwIfAborted","ctx","SAMPLE_RATE","DURATION_SAMPLES","SNAPSHOT_BINS","AudioCollector","Ctor","resolveOfflineAudioContext","offline","oscillator","compressor","channel","snapshot","downsample","digest","root","bins","step","values","sample","WEIGHTS","AutomationCollector","indicators","nav","userAgent","confidence","sum","WIDTH","HEIGHT","CanvasCollector","canvas","context","paintScene","image","CapabilitiesCollector","win","hasWebGl","hasStorage","flags","key","storage","normalizeBrowser","text","labeledFamily","family","majorPattern","major","normalizePlatform","normalizeScreenClass","width","height","max","normalizeGpuFamily","vendor","renderer","HIGH_ENTROPY_HINTS","ClientHintsCollector","uaData","base","highEntropy","gotHighEntropy","brandLabel","firstBrand","versionHint","browserInput","brands","item","brand","SAMPLE","BASELINE","CANDIDATES","FontsCollector","baseline","measureWidth","detected","font","fontFamily","span","NavigatorCollector","platform","languages","browser","platformFamily","ScreenCollector","screenRef","finiteOrZero","screenClass","TimezoneCollector","timeZone","offsetMinutes","WebGlCollector","gl","getWebGlContext","debugInfo","readParameter","extensions","extensionsHash","maxViewport","limits","readNumeric","hasRenderer","quality","standard","pname","postCollect","endpoint","payload","abortSignal","response","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","ms","resolve","id"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"device-intelligence.min.js","names":[],"sources":["../../assets/src/logger.ts","../../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/index.ts"],"sourcesContent":["/**\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 * 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\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 response = await fetch(endpoint, {\n method: 'POST',\n credentials: 'same-origin',\n headers: {\n 'Content-Type': 'application/json',\n },\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 * 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 { 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 } from './client';\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