@datalyr/web 1.0.7 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/datalyr.cjs.js +33 -219
- package/dist/datalyr.cjs.js.map +1 -1
- package/dist/datalyr.esm.js +33 -219
- package/dist/datalyr.esm.js.map +1 -1
- package/dist/datalyr.esm.min.js +1 -1
- package/dist/datalyr.esm.min.js.map +1 -1
- package/dist/datalyr.js +33 -219
- package/dist/datalyr.js.map +1 -1
- package/dist/datalyr.min.js +1 -1
- package/dist/datalyr.min.js.map +1 -1
- package/dist/fingerprint.d.ts +6 -39
- package/dist/fingerprint.d.ts.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/types.d.ts +11 -27
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/datalyr.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @datalyr/web v1.0
|
|
2
|
+
* @datalyr/web v1.1.0
|
|
3
3
|
* Datalyr Web SDK - Modern attribution tracking for web applications
|
|
4
4
|
* (c) 2025 Datalyr Inc.
|
|
5
5
|
* Released under the MIT License
|
|
@@ -1626,24 +1626,40 @@ var Datalyr = (function () {
|
|
|
1626
1626
|
}
|
|
1627
1627
|
/**
|
|
1628
1628
|
* Collect minimal fingerprint data (privacy-friendly)
|
|
1629
|
+
* Matches browser tag minimal fingerprinting approach
|
|
1629
1630
|
*/
|
|
1630
1631
|
collectMinimal() {
|
|
1631
|
-
|
|
1632
|
+
const fp = {
|
|
1632
1633
|
timezone: this.getTimezone(),
|
|
1633
1634
|
language: navigator.language || null,
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
sessionStorageAvailable: this.testStorage('sessionStorage')
|
|
1635
|
+
screen_bucket: this.getScreenBucket(),
|
|
1636
|
+
dnt: (navigator.doNotTrack === '1' || window.globalPrivacyControl === true) || null,
|
|
1637
|
+
userAgent: navigator.userAgent || null
|
|
1638
1638
|
};
|
|
1639
|
+
// User-Agent Client Hints (modern browsers)
|
|
1640
|
+
if ('userAgentData' in navigator) {
|
|
1641
|
+
const uaData = navigator.userAgentData;
|
|
1642
|
+
fp.userAgentData = {
|
|
1643
|
+
brands: uaData.brands || [],
|
|
1644
|
+
mobile: uaData.mobile || false,
|
|
1645
|
+
platform: uaData.platform || null
|
|
1646
|
+
};
|
|
1647
|
+
}
|
|
1648
|
+
return fp;
|
|
1639
1649
|
}
|
|
1640
1650
|
/**
|
|
1641
1651
|
* Collect standard fingerprint data
|
|
1652
|
+
* PRIVACY: Minimal data collection matching browser tag approach
|
|
1653
|
+
* Only collects data necessary for basic analytics and attribution
|
|
1642
1654
|
*/
|
|
1643
1655
|
collectStandard() {
|
|
1644
1656
|
const fingerprint = {};
|
|
1645
1657
|
try {
|
|
1646
|
-
//
|
|
1658
|
+
// PRIVACY: Only collect minimal data needed for attribution
|
|
1659
|
+
fingerprint.timezone = this.getTimezone();
|
|
1660
|
+
fingerprint.language = navigator.language || null;
|
|
1661
|
+
fingerprint.screen_bucket = this.getScreenBucket();
|
|
1662
|
+
fingerprint.dnt = (navigator.doNotTrack === '1' || window.globalPrivacyControl === true) || null;
|
|
1647
1663
|
fingerprint.userAgent = navigator.userAgent || null;
|
|
1648
1664
|
// User-Agent Client Hints (modern browsers)
|
|
1649
1665
|
if ('userAgentData' in navigator) {
|
|
@@ -1654,125 +1670,14 @@ var Datalyr = (function () {
|
|
|
1654
1670
|
platform: uaData.platform || null
|
|
1655
1671
|
};
|
|
1656
1672
|
}
|
|
1657
|
-
// Language settings
|
|
1658
|
-
fingerprint.language = navigator.language || null;
|
|
1659
|
-
fingerprint.languages = navigator.languages ?
|
|
1660
|
-
navigator.languages.slice(0, 2) : null; // Limit to 2 for privacy
|
|
1661
|
-
// Platform and browser features
|
|
1662
|
-
fingerprint.platform = navigator.platform || null;
|
|
1663
|
-
fingerprint.cookieEnabled = navigator.cookieEnabled || null;
|
|
1664
|
-
fingerprint.doNotTrack = navigator.doNotTrack || null;
|
|
1665
|
-
// Hardware (coarsened for privacy)
|
|
1666
|
-
fingerprint.hardwareConcurrency = this.coarsenHardwareConcurrency();
|
|
1667
|
-
fingerprint.deviceMemory = this.coarsenDeviceMemory();
|
|
1668
|
-
fingerprint.maxTouchPoints = navigator.maxTouchPoints > 0 ? 'touch' : 'no-touch';
|
|
1669
|
-
// Screen (coarsened)
|
|
1670
|
-
fingerprint.screenResolution = this.getScreenResolution();
|
|
1671
|
-
fingerprint.colorDepth = screen.colorDepth || null;
|
|
1672
|
-
fingerprint.pixelRatio = this.coarsenPixelRatio();
|
|
1673
|
-
// Timezone
|
|
1674
|
-
fingerprint.timezone = this.getTimezone();
|
|
1675
|
-
fingerprint.timezoneOffset = this.coarsenTimezoneOffset();
|
|
1676
|
-
// Canvas fingerprinting disabled for privacy
|
|
1677
|
-
fingerprint.canvasEnabled = false;
|
|
1678
|
-
// Plugins count only (not details for privacy)
|
|
1679
|
-
fingerprint.pluginsCount = navigator.plugins ? navigator.plugins.length : null;
|
|
1680
|
-
// Storage availability
|
|
1681
|
-
fingerprint.localStorageAvailable = this.testStorage('localStorage');
|
|
1682
|
-
fingerprint.sessionStorageAvailable = this.testStorage('sessionStorage');
|
|
1683
|
-
fingerprint.indexedDBAvailable = this.testIndexedDB();
|
|
1684
|
-
// Add cached heavy fingerprint data if available
|
|
1685
|
-
if (this.heavyFingerprintDone) {
|
|
1686
|
-
Object.assign(fingerprint, this.fingerprintCache);
|
|
1687
|
-
}
|
|
1688
1673
|
}
|
|
1689
1674
|
catch (e) {
|
|
1690
1675
|
console.warn('[Datalyr] Error collecting fingerprint:', e);
|
|
1691
1676
|
}
|
|
1692
1677
|
return fingerprint;
|
|
1693
1678
|
}
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
* Called lazily on first event to improve page load performance
|
|
1697
|
-
*/
|
|
1698
|
-
collectHeavyFingerprint() {
|
|
1699
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
1700
|
-
if (this.heavyFingerprintDone || this.privacyMode === 'strict') {
|
|
1701
|
-
return;
|
|
1702
|
-
}
|
|
1703
|
-
try {
|
|
1704
|
-
// WebGL fingerprinting
|
|
1705
|
-
const webglData = this.getWebGLFingerprint();
|
|
1706
|
-
if (webglData) {
|
|
1707
|
-
this.fingerprintCache.webglVendor = webglData.vendor;
|
|
1708
|
-
this.fingerprintCache.webglRenderer = webglData.renderer;
|
|
1709
|
-
}
|
|
1710
|
-
// Audio fingerprinting
|
|
1711
|
-
const audioData = yield this.getAudioFingerprint();
|
|
1712
|
-
if (audioData) {
|
|
1713
|
-
this.fingerprintCache.audioSampleRate = audioData.sampleRate;
|
|
1714
|
-
this.fingerprintCache.audioState = audioData.state;
|
|
1715
|
-
this.fingerprintCache.audioMaxChannels = audioData.maxChannels;
|
|
1716
|
-
}
|
|
1717
|
-
this.heavyFingerprintDone = true;
|
|
1718
|
-
}
|
|
1719
|
-
catch (e) {
|
|
1720
|
-
console.warn('[Datalyr] Heavy fingerprinting failed:', e);
|
|
1721
|
-
}
|
|
1722
|
-
});
|
|
1723
|
-
}
|
|
1724
|
-
/**
|
|
1725
|
-
* Get WebGL fingerprint
|
|
1726
|
-
*/
|
|
1727
|
-
getWebGLFingerprint() {
|
|
1728
|
-
try {
|
|
1729
|
-
const canvas = document.createElement('canvas');
|
|
1730
|
-
const gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl');
|
|
1731
|
-
if (!gl)
|
|
1732
|
-
return null;
|
|
1733
|
-
const debugInfo = gl.getExtension('WEBGL_debug_renderer_info');
|
|
1734
|
-
if (!debugInfo) {
|
|
1735
|
-
return {
|
|
1736
|
-
vendor: gl.getParameter(gl.VENDOR) || 'unknown',
|
|
1737
|
-
renderer: gl.getParameter(gl.RENDERER) || 'unknown'
|
|
1738
|
-
};
|
|
1739
|
-
}
|
|
1740
|
-
return {
|
|
1741
|
-
vendor: gl.getParameter(debugInfo.UNMASKED_VENDOR_WEBGL) || 'unknown',
|
|
1742
|
-
renderer: gl.getParameter(debugInfo.UNMASKED_RENDERER_WEBGL) || 'unknown'
|
|
1743
|
-
};
|
|
1744
|
-
}
|
|
1745
|
-
catch (_a) {
|
|
1746
|
-
return null;
|
|
1747
|
-
}
|
|
1748
|
-
}
|
|
1749
|
-
/**
|
|
1750
|
-
* Get audio fingerprint
|
|
1751
|
-
*/
|
|
1752
|
-
getAudioFingerprint() {
|
|
1753
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
1754
|
-
var _a;
|
|
1755
|
-
try {
|
|
1756
|
-
const AudioContext = window.AudioContext || window.webkitAudioContext;
|
|
1757
|
-
if (!AudioContext)
|
|
1758
|
-
return null;
|
|
1759
|
-
const audioCtx = new AudioContext();
|
|
1760
|
-
const result = {
|
|
1761
|
-
sampleRate: audioCtx.sampleRate || null,
|
|
1762
|
-
state: audioCtx.state || null,
|
|
1763
|
-
maxChannels: ((_a = audioCtx.destination) === null || _a === void 0 ? void 0 : _a.maxChannelCount) || null
|
|
1764
|
-
};
|
|
1765
|
-
// Close context to free resources
|
|
1766
|
-
if (audioCtx.close) {
|
|
1767
|
-
yield audioCtx.close();
|
|
1768
|
-
}
|
|
1769
|
-
return result;
|
|
1770
|
-
}
|
|
1771
|
-
catch (_b) {
|
|
1772
|
-
return null;
|
|
1773
|
-
}
|
|
1774
|
-
});
|
|
1775
|
-
}
|
|
1679
|
+
// PRIVACY: Heavy fingerprinting (WebGL, Audio) removed
|
|
1680
|
+
// Minimal fingerprinting only for privacy compliance
|
|
1776
1681
|
/**
|
|
1777
1682
|
* Get timezone
|
|
1778
1683
|
*/
|
|
@@ -1785,10 +1690,13 @@ var Datalyr = (function () {
|
|
|
1785
1690
|
}
|
|
1786
1691
|
}
|
|
1787
1692
|
/**
|
|
1788
|
-
* Get screen
|
|
1693
|
+
* Get coarse screen bucket for basic device classification
|
|
1694
|
+
* Rounds to nearest 100px for privacy
|
|
1789
1695
|
*/
|
|
1790
|
-
|
|
1696
|
+
getScreenBucket() {
|
|
1791
1697
|
try {
|
|
1698
|
+
if (!window.screen)
|
|
1699
|
+
return null;
|
|
1792
1700
|
const width = Math.round(screen.width / 100) * 100;
|
|
1793
1701
|
const height = Math.round(screen.height / 100) * 100;
|
|
1794
1702
|
return `${width}x${height}`;
|
|
@@ -1797,96 +1705,8 @@ var Datalyr = (function () {
|
|
|
1797
1705
|
return null;
|
|
1798
1706
|
}
|
|
1799
1707
|
}
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
*/
|
|
1803
|
-
coarsenHardwareConcurrency() {
|
|
1804
|
-
try {
|
|
1805
|
-
const cores = navigator.hardwareConcurrency;
|
|
1806
|
-
if (!cores)
|
|
1807
|
-
return null;
|
|
1808
|
-
return cores > 8 ? '8+' : cores;
|
|
1809
|
-
}
|
|
1810
|
-
catch (_a) {
|
|
1811
|
-
return null;
|
|
1812
|
-
}
|
|
1813
|
-
}
|
|
1814
|
-
/**
|
|
1815
|
-
* Coarsen device memory for privacy
|
|
1816
|
-
*/
|
|
1817
|
-
coarsenDeviceMemory() {
|
|
1818
|
-
try {
|
|
1819
|
-
const memory = navigator.deviceMemory;
|
|
1820
|
-
if (!memory)
|
|
1821
|
-
return null;
|
|
1822
|
-
return memory > 4 ? '4+' : memory;
|
|
1823
|
-
}
|
|
1824
|
-
catch (_a) {
|
|
1825
|
-
return null;
|
|
1826
|
-
}
|
|
1827
|
-
}
|
|
1828
|
-
/**
|
|
1829
|
-
* Coarsen pixel ratio for privacy
|
|
1830
|
-
*/
|
|
1831
|
-
coarsenPixelRatio() {
|
|
1832
|
-
try {
|
|
1833
|
-
const ratio = window.devicePixelRatio;
|
|
1834
|
-
if (!ratio)
|
|
1835
|
-
return null;
|
|
1836
|
-
// Round to common values
|
|
1837
|
-
if (ratio <= 1)
|
|
1838
|
-
return '1';
|
|
1839
|
-
if (ratio <= 1.5)
|
|
1840
|
-
return '1.5';
|
|
1841
|
-
if (ratio <= 2)
|
|
1842
|
-
return '2';
|
|
1843
|
-
if (ratio <= 3)
|
|
1844
|
-
return '3';
|
|
1845
|
-
return '3+';
|
|
1846
|
-
}
|
|
1847
|
-
catch (_a) {
|
|
1848
|
-
return null;
|
|
1849
|
-
}
|
|
1850
|
-
}
|
|
1851
|
-
/**
|
|
1852
|
-
* Coarsen timezone offset for privacy
|
|
1853
|
-
*/
|
|
1854
|
-
coarsenTimezoneOffset() {
|
|
1855
|
-
try {
|
|
1856
|
-
const offset = new Date().getTimezoneOffset();
|
|
1857
|
-
// Round to nearest 30 minutes
|
|
1858
|
-
return Math.round(offset / 30) * 30;
|
|
1859
|
-
}
|
|
1860
|
-
catch (_a) {
|
|
1861
|
-
return null;
|
|
1862
|
-
}
|
|
1863
|
-
}
|
|
1864
|
-
/**
|
|
1865
|
-
* Test if storage is available
|
|
1866
|
-
*/
|
|
1867
|
-
testStorage(type) {
|
|
1868
|
-
try {
|
|
1869
|
-
const storage = window[type];
|
|
1870
|
-
const testKey = '__dl_test__';
|
|
1871
|
-
storage.setItem(testKey, '1');
|
|
1872
|
-
storage.removeItem(testKey);
|
|
1873
|
-
return true;
|
|
1874
|
-
}
|
|
1875
|
-
catch (_a) {
|
|
1876
|
-
return false;
|
|
1877
|
-
}
|
|
1878
|
-
}
|
|
1879
|
-
/**
|
|
1880
|
-
* Test if IndexedDB is available
|
|
1881
|
-
*/
|
|
1882
|
-
testIndexedDB() {
|
|
1883
|
-
try {
|
|
1884
|
-
return !!window.indexedDB;
|
|
1885
|
-
}
|
|
1886
|
-
catch (_a) {
|
|
1887
|
-
return false;
|
|
1888
|
-
}
|
|
1889
|
-
}
|
|
1708
|
+
// PRIVACY: Unused helper methods removed (coarsen functions, storage tests)
|
|
1709
|
+
// Minimal fingerprinting only
|
|
1890
1710
|
/**
|
|
1891
1711
|
* Generate fingerprint hash
|
|
1892
1712
|
*/
|
|
@@ -2526,13 +2346,7 @@ var Datalyr = (function () {
|
|
|
2526
2346
|
if (!this.shouldTrack())
|
|
2527
2347
|
return;
|
|
2528
2348
|
try {
|
|
2529
|
-
//
|
|
2530
|
-
if (!this.heavyFingerprintCollected && this.config.enableFingerprinting) {
|
|
2531
|
-
this.heavyFingerprintCollected = true;
|
|
2532
|
-
this.fingerprint.collectHeavyFingerprint().catch(err => {
|
|
2533
|
-
this.log('Heavy fingerprint collection failed:', err);
|
|
2534
|
-
});
|
|
2535
|
-
}
|
|
2349
|
+
// PRIVACY: Heavy fingerprinting removed - using minimal fingerprinting only
|
|
2536
2350
|
// Update session activity
|
|
2537
2351
|
this.session.updateActivity(eventName);
|
|
2538
2352
|
// Create event payload
|