@grainql/analytics-web 3.0.4 → 3.1.1

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.
Files changed (40) hide show
  1. package/dist/cjs/heatmap-tracking.d.ts.map +1 -1
  2. package/dist/cjs/heatmap-tracking.js +14 -21
  3. package/dist/cjs/heatmap-tracking.js.map +1 -1
  4. package/dist/cjs/id-manager.d.ts +13 -0
  5. package/dist/cjs/id-manager.d.ts.map +1 -1
  6. package/dist/cjs/id-manager.js +83 -4
  7. package/dist/cjs/id-manager.js.map +1 -1
  8. package/dist/cjs/interaction-tracking.d.ts.map +1 -1
  9. package/dist/cjs/interaction-tracking.js +4 -4
  10. package/dist/cjs/interaction-tracking.js.map +1 -1
  11. package/dist/cjs/section-tracking.d.ts.map +1 -1
  12. package/dist/cjs/section-tracking.js +2 -4
  13. package/dist/cjs/section-tracking.js.map +1 -1
  14. package/dist/esm/heatmap-tracking.d.ts.map +1 -1
  15. package/dist/esm/heatmap-tracking.js +14 -21
  16. package/dist/esm/heatmap-tracking.js.map +1 -1
  17. package/dist/esm/id-manager.d.ts +13 -0
  18. package/dist/esm/id-manager.d.ts.map +1 -1
  19. package/dist/esm/id-manager.js +83 -4
  20. package/dist/esm/id-manager.js.map +1 -1
  21. package/dist/esm/interaction-tracking.d.ts.map +1 -1
  22. package/dist/esm/interaction-tracking.js +4 -4
  23. package/dist/esm/interaction-tracking.js.map +1 -1
  24. package/dist/esm/section-tracking.d.ts.map +1 -1
  25. package/dist/esm/section-tracking.js +2 -4
  26. package/dist/esm/section-tracking.js.map +1 -1
  27. package/dist/heatmap-tracking.d.ts.map +1 -1
  28. package/dist/heatmap-tracking.js +14 -21
  29. package/dist/id-manager.d.ts +13 -0
  30. package/dist/id-manager.d.ts.map +1 -1
  31. package/dist/id-manager.js +83 -4
  32. package/dist/index.global.dev.js +70 -32
  33. package/dist/index.global.dev.js.map +2 -2
  34. package/dist/index.global.js +3 -3
  35. package/dist/index.global.js.map +3 -3
  36. package/dist/interaction-tracking.d.ts.map +1 -1
  37. package/dist/interaction-tracking.js +4 -4
  38. package/dist/section-tracking.d.ts.map +1 -1
  39. package/dist/section-tracking.js +2 -4
  40. package/package.json +1 -1
@@ -21,6 +21,7 @@ export declare class IdManager {
21
21
  private config;
22
22
  private cachedDailyId;
23
23
  private dailyIdDate;
24
+ private dailyRandomSeed;
24
25
  private permanentId;
25
26
  constructor(config: IdConfig);
26
27
  /**
@@ -54,6 +55,18 @@ export declare class IdManager {
54
55
  * Clear permanent ID from localStorage
55
56
  */
56
57
  private clearPermanentId;
58
+ /**
59
+ * Load daily random seed from sessionStorage
60
+ */
61
+ private loadDailySeed;
62
+ /**
63
+ * Save daily random seed to sessionStorage
64
+ */
65
+ private saveDailySeed;
66
+ /**
67
+ * Clear daily seed from sessionStorage
68
+ */
69
+ private clearDailySeed;
57
70
  /**
58
71
  * Get info about current ID for debugging
59
72
  */
@@ -1 +1 @@
1
- {"version":3,"file":"id-manager.d.ts","sourceRoot":"","sources":["../src/id-manager.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,MAAM,MAAM,MAAM,GAAG,YAAY,GAAG,WAAW,CAAC;AAEhD,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AA2DD;;;GAGG;AACH,qBAAa,SAAS;IACpB,OAAO,CAAC,MAAM,CAAW;IACzB,OAAO,CAAC,aAAa,CAAuB;IAC5C,OAAO,CAAC,WAAW,CAAuB;IAC1C,OAAO,CAAC,WAAW,CAAuB;gBAE9B,MAAM,EAAE,QAAQ;IAS5B;;;;OAIG;IACH,uBAAuB,IAAI,MAAM;IAoBjC;;;OAGG;IACH,mBAAmB,IAAI,MAAM;IAyB7B;;OAEG;IACH,gBAAgB,IAAI,MAAM;IAQ1B;;OAEG;IACH,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAkB3B;;OAEG;IACH,OAAO,CAAC,eAAe;IAiBvB;;OAEG;IACH,OAAO,CAAC,eAAe;IAWvB;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAWxB;;OAEG;IACH,SAAS,IAAI;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAC;QAAC,eAAe,EAAE,OAAO,CAAA;KAAE;CAQpE"}
1
+ {"version":3,"file":"id-manager.d.ts","sourceRoot":"","sources":["../src/id-manager.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,MAAM,MAAM,MAAM,GAAG,YAAY,GAAG,WAAW,CAAC;AAEhD,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AA2DD;;;GAGG;AACH,qBAAa,SAAS;IACpB,OAAO,CAAC,MAAM,CAAW;IACzB,OAAO,CAAC,aAAa,CAAuB;IAC5C,OAAO,CAAC,WAAW,CAAuB;IAC1C,OAAO,CAAC,eAAe,CAAuB;IAC9C,OAAO,CAAC,WAAW,CAAuB;gBAE9B,MAAM,EAAE,QAAQ;IAc5B;;;;OAIG;IACH,uBAAuB,IAAI,MAAM;IAmCjC;;;OAGG;IACH,mBAAmB,IAAI,MAAM;IAyB7B;;OAEG;IACH,gBAAgB,IAAI,MAAM;IAQ1B;;OAEG;IACH,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAsB3B;;OAEG;IACH,OAAO,CAAC,eAAe;IAiBvB;;OAEG;IACH,OAAO,CAAC,eAAe;IAWvB;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAWxB;;OAEG;IACH,OAAO,CAAC,aAAa;IA2BrB;;OAEG;IACH,OAAO,CAAC,aAAa;IAYrB;;OAEG;IACH,OAAO,CAAC,cAAc;IAWtB;;OAEG;IACH,SAAS,IAAI;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAC;QAAC,eAAe,EAAE,OAAO,CAAA;KAAE;CAQpE"}
@@ -69,12 +69,17 @@ class IdManager {
69
69
  constructor(config) {
70
70
  this.cachedDailyId = null;
71
71
  this.dailyIdDate = null;
72
+ this.dailyRandomSeed = null; // Random component for daily ID
72
73
  this.permanentId = null;
73
74
  this.config = config;
74
75
  // Load permanent ID from localStorage if in permanent mode
75
76
  if (config.mode === 'permanent' && config.useLocalStorage) {
76
77
  this.loadPermanentId();
77
78
  }
79
+ // Load daily random seed from sessionStorage if in cookieless mode
80
+ if (config.mode === 'cookieless') {
81
+ this.loadDailySeed();
82
+ }
78
83
  }
79
84
  /**
80
85
  * Generate a daily rotating ID
@@ -84,13 +89,25 @@ class IdManager {
84
89
  generateDailyRotatingId() {
85
90
  const currentDate = getLocalDateString();
86
91
  // Return cached ID if still the same day
87
- if (this.cachedDailyId && this.dailyIdDate === currentDate) {
92
+ if (this.cachedDailyId && this.dailyIdDate === currentDate && this.dailyRandomSeed) {
88
93
  return this.cachedDailyId;
89
94
  }
90
- // Generate new daily ID
95
+ // Load seed from sessionStorage if available
96
+ const storedSeed = this.loadDailySeed();
97
+ // If date changed, clear the random seed
98
+ if (this.dailyIdDate !== currentDate) {
99
+ this.dailyRandomSeed = null;
100
+ this.clearDailySeed();
101
+ }
102
+ // Generate new random seed for today if needed
103
+ if (!this.dailyRandomSeed) {
104
+ this.dailyRandomSeed = storedSeed || generateUUID();
105
+ this.saveDailySeed(this.dailyRandomSeed, currentDate);
106
+ }
107
+ // Generate new daily ID using fingerprint + random seed
91
108
  const fingerprint = getBrowserFingerprint();
92
- const seed = `${this.config.tenantId}|${currentDate}|${fingerprint}`;
93
- const dailyId = `daily_${simpleHash(seed)}_${simpleHash(Date.now().toString())}`;
109
+ const seed = `${this.config.tenantId}|${currentDate}|${fingerprint}|${this.dailyRandomSeed}`;
110
+ const dailyId = `daily_${simpleHash(seed)}`;
94
111
  // Cache for same-day requests
95
112
  this.cachedDailyId = dailyId;
96
113
  this.dailyIdDate = currentDate;
@@ -140,6 +157,8 @@ class IdManager {
140
157
  if (mode === 'permanent') {
141
158
  this.cachedDailyId = null;
142
159
  this.dailyIdDate = null;
160
+ this.dailyRandomSeed = null;
161
+ this.clearDailySeed();
143
162
  }
144
163
  // Clear permanent ID when switching to cookieless
145
164
  if (mode === 'cookieless') {
@@ -147,6 +166,8 @@ class IdManager {
147
166
  if (this.config.useLocalStorage) {
148
167
  this.clearPermanentId();
149
168
  }
169
+ // Load daily seed for cookieless mode
170
+ this.loadDailySeed();
150
171
  }
151
172
  }
152
173
  /**
@@ -196,6 +217,64 @@ class IdManager {
196
217
  // Silent failure
197
218
  }
198
219
  }
220
+ /**
221
+ * Load daily random seed from sessionStorage
222
+ */
223
+ loadDailySeed() {
224
+ if (typeof window === 'undefined')
225
+ return null;
226
+ try {
227
+ const storageKey = `grain_daily_seed_${this.config.tenantId}`;
228
+ const stored = sessionStorage.getItem(storageKey);
229
+ if (stored) {
230
+ const data = JSON.parse(stored);
231
+ const currentDate = getLocalDateString();
232
+ // Only use seed if it's from today
233
+ if (data.date === currentDate && data.seed) {
234
+ this.dailyRandomSeed = data.seed;
235
+ this.dailyIdDate = data.date;
236
+ return data.seed;
237
+ }
238
+ else {
239
+ // Clear stale seed
240
+ this.clearDailySeed();
241
+ }
242
+ }
243
+ }
244
+ catch (error) {
245
+ // Silent failure - sessionStorage might be disabled
246
+ }
247
+ return null;
248
+ }
249
+ /**
250
+ * Save daily random seed to sessionStorage
251
+ */
252
+ saveDailySeed(seed, date) {
253
+ if (typeof window === 'undefined')
254
+ return;
255
+ try {
256
+ const storageKey = `grain_daily_seed_${this.config.tenantId}`;
257
+ const data = { seed, date };
258
+ sessionStorage.setItem(storageKey, JSON.stringify(data));
259
+ }
260
+ catch (error) {
261
+ // Silent failure - sessionStorage might be disabled
262
+ }
263
+ }
264
+ /**
265
+ * Clear daily seed from sessionStorage
266
+ */
267
+ clearDailySeed() {
268
+ if (typeof window === 'undefined')
269
+ return;
270
+ try {
271
+ const storageKey = `grain_daily_seed_${this.config.tenantId}`;
272
+ sessionStorage.removeItem(storageKey);
273
+ }
274
+ catch (error) {
275
+ // Silent failure
276
+ }
277
+ }
199
278
  /**
200
279
  * Get info about current ID for debugging
201
280
  */
@@ -1,4 +1,4 @@
1
- /* Grain Analytics Web SDK v3.0.4 | MIT License | Development Build */
1
+ /* Grain Analytics Web SDK v3.1.1 | MIT License | Development Build */
2
2
  "use strict";
3
3
  var Grain = (() => {
4
4
  var __defProp = Object.defineProperty;
@@ -345,8 +345,6 @@ var Grain = (() => {
345
345
  const clickHandler = (event) => {
346
346
  if (this.isDestroyed)
347
347
  return;
348
- if (!this.tracker.hasConsent("analytics"))
349
- return;
350
348
  this.handleClick(event);
351
349
  };
352
350
  document.addEventListener("click", clickHandler, { passive: true, capture: true });
@@ -391,8 +389,6 @@ var Grain = (() => {
391
389
  this.periodicScrollTimer = window.setInterval(() => {
392
390
  if (this.isDestroyed || !this.currentScrollState)
393
391
  return;
394
- if (!this.tracker.hasConsent("analytics"))
395
- return;
396
392
  if (!this.attentionQuality.shouldTrack()) {
397
393
  this.log("Scroll tracking paused:", this.attentionQuality.getLastFilterReason());
398
394
  return;
@@ -474,8 +470,6 @@ var Grain = (() => {
474
470
  * Handle click event
475
471
  */
476
472
  handleClick(event) {
477
- if (!this.tracker.hasConsent("analytics"))
478
- return;
479
473
  const element = event.target;
480
474
  if (!element)
481
475
  return;
@@ -520,8 +514,6 @@ var Grain = (() => {
520
514
  * Handle scroll event
521
515
  */
522
516
  handleScroll() {
523
- if (!this.tracker.hasConsent("analytics"))
524
- return;
525
517
  this.updateScrollState();
526
518
  }
527
519
  /**
@@ -530,8 +522,6 @@ var Grain = (() => {
530
522
  updateScrollState() {
531
523
  if (typeof window === "undefined")
532
524
  return;
533
- if (!this.tracker.hasConsent("analytics"))
534
- return;
535
525
  const currentTime = Date.now();
536
526
  const scrollY = window.scrollY || window.pageYOffset;
537
527
  const viewportHeight = window.innerHeight;
@@ -615,11 +605,6 @@ var Grain = (() => {
615
605
  flushPendingEvents() {
616
606
  if (this.isDestroyed)
617
607
  return;
618
- if (!this.tracker.hasConsent("analytics")) {
619
- this.pendingClicks = [];
620
- this.pendingScrolls = [];
621
- return;
622
- }
623
608
  if (this.pendingClicks.length > 0) {
624
609
  for (const clickData of this.pendingClicks) {
625
610
  this.tracker.trackSystemEvent("_grain_heatmap_click", {
@@ -660,11 +645,6 @@ var Grain = (() => {
660
645
  * Flush pending events with beacon (for page unload)
661
646
  */
662
647
  flushPendingEventsWithBeacon() {
663
- if (!this.tracker.hasConsent("analytics")) {
664
- this.pendingClicks = [];
665
- this.pendingScrolls = [];
666
- return;
667
- }
668
648
  if (this.pendingClicks.length > 0) {
669
649
  for (const clickData of this.pendingClicks) {
670
650
  this.tracker.trackSystemEvent("_grain_heatmap_click", {
@@ -857,8 +837,6 @@ var Grain = (() => {
857
837
  handleInteractionClick(interaction, event) {
858
838
  if (this.isDestroyed)
859
839
  return;
860
- if (!this.tracker.hasConsent("analytics"))
861
- return;
862
840
  const element = event.target;
863
841
  const isNavigationLink = element instanceof HTMLAnchorElement && element.href;
864
842
  const eventProperties = {
@@ -886,8 +864,6 @@ var Grain = (() => {
886
864
  handleInteractionFocus(interaction, event) {
887
865
  if (this.isDestroyed)
888
866
  return;
889
- if (!this.tracker.hasConsent("analytics"))
890
- return;
891
867
  const element = event.target;
892
868
  this.tracker.track(interaction.eventName, {
893
869
  interaction_type: "focus",
@@ -1391,10 +1367,6 @@ var Grain = (() => {
1391
1367
  flushPendingEvents() {
1392
1368
  if (this.isDestroyed || this.pendingEvents.length === 0)
1393
1369
  return;
1394
- if (!this.tracker.hasConsent("analytics")) {
1395
- this.pendingEvents = [];
1396
- return;
1397
- }
1398
1370
  for (const viewData of this.pendingEvents) {
1399
1371
  this.tracker.trackSystemEvent("_grain_section_view", {
1400
1372
  section_name: viewData.sectionName,
@@ -6582,11 +6554,16 @@ var Grain = (() => {
6582
6554
  constructor(config) {
6583
6555
  this.cachedDailyId = null;
6584
6556
  this.dailyIdDate = null;
6557
+ this.dailyRandomSeed = null;
6558
+ // Random component for daily ID
6585
6559
  this.permanentId = null;
6586
6560
  this.config = config;
6587
6561
  if (config.mode === "permanent" && config.useLocalStorage) {
6588
6562
  this.loadPermanentId();
6589
6563
  }
6564
+ if (config.mode === "cookieless") {
6565
+ this.loadDailySeed();
6566
+ }
6590
6567
  }
6591
6568
  /**
6592
6569
  * Generate a daily rotating ID
@@ -6595,12 +6572,21 @@ var Grain = (() => {
6595
6572
  */
6596
6573
  generateDailyRotatingId() {
6597
6574
  const currentDate = getLocalDateString();
6598
- if (this.cachedDailyId && this.dailyIdDate === currentDate) {
6575
+ if (this.cachedDailyId && this.dailyIdDate === currentDate && this.dailyRandomSeed) {
6599
6576
  return this.cachedDailyId;
6600
6577
  }
6578
+ const storedSeed = this.loadDailySeed();
6579
+ if (this.dailyIdDate !== currentDate) {
6580
+ this.dailyRandomSeed = null;
6581
+ this.clearDailySeed();
6582
+ }
6583
+ if (!this.dailyRandomSeed) {
6584
+ this.dailyRandomSeed = storedSeed || generateUUID();
6585
+ this.saveDailySeed(this.dailyRandomSeed, currentDate);
6586
+ }
6601
6587
  const fingerprint = getBrowserFingerprint();
6602
- const seed = `${this.config.tenantId}|${currentDate}|${fingerprint}`;
6603
- const dailyId = `daily_${simpleHash(seed)}_${simpleHash(Date.now().toString())}`;
6588
+ const seed = `${this.config.tenantId}|${currentDate}|${fingerprint}|${this.dailyRandomSeed}`;
6589
+ const dailyId = `daily_${simpleHash(seed)}`;
6604
6590
  this.cachedDailyId = dailyId;
6605
6591
  this.dailyIdDate = currentDate;
6606
6592
  return dailyId;
@@ -6644,12 +6630,15 @@ var Grain = (() => {
6644
6630
  if (mode === "permanent") {
6645
6631
  this.cachedDailyId = null;
6646
6632
  this.dailyIdDate = null;
6633
+ this.dailyRandomSeed = null;
6634
+ this.clearDailySeed();
6647
6635
  }
6648
6636
  if (mode === "cookieless") {
6649
6637
  this.permanentId = null;
6650
6638
  if (this.config.useLocalStorage) {
6651
6639
  this.clearPermanentId();
6652
6640
  }
6641
+ this.loadDailySeed();
6653
6642
  }
6654
6643
  }
6655
6644
  /**
@@ -6693,6 +6682,55 @@ var Grain = (() => {
6693
6682
  } catch (error) {
6694
6683
  }
6695
6684
  }
6685
+ /**
6686
+ * Load daily random seed from sessionStorage
6687
+ */
6688
+ loadDailySeed() {
6689
+ if (typeof window === "undefined")
6690
+ return null;
6691
+ try {
6692
+ const storageKey = `grain_daily_seed_${this.config.tenantId}`;
6693
+ const stored = sessionStorage.getItem(storageKey);
6694
+ if (stored) {
6695
+ const data = JSON.parse(stored);
6696
+ const currentDate = getLocalDateString();
6697
+ if (data.date === currentDate && data.seed) {
6698
+ this.dailyRandomSeed = data.seed;
6699
+ this.dailyIdDate = data.date;
6700
+ return data.seed;
6701
+ } else {
6702
+ this.clearDailySeed();
6703
+ }
6704
+ }
6705
+ } catch (error) {
6706
+ }
6707
+ return null;
6708
+ }
6709
+ /**
6710
+ * Save daily random seed to sessionStorage
6711
+ */
6712
+ saveDailySeed(seed, date) {
6713
+ if (typeof window === "undefined")
6714
+ return;
6715
+ try {
6716
+ const storageKey = `grain_daily_seed_${this.config.tenantId}`;
6717
+ const data = { seed, date };
6718
+ sessionStorage.setItem(storageKey, JSON.stringify(data));
6719
+ } catch (error) {
6720
+ }
6721
+ }
6722
+ /**
6723
+ * Clear daily seed from sessionStorage
6724
+ */
6725
+ clearDailySeed() {
6726
+ if (typeof window === "undefined")
6727
+ return;
6728
+ try {
6729
+ const storageKey = `grain_daily_seed_${this.config.tenantId}`;
6730
+ sessionStorage.removeItem(storageKey);
6731
+ } catch (error) {
6732
+ }
6733
+ }
6696
6734
  /**
6697
6735
  * Get info about current ID for debugging
6698
6736
  */