@grainql/analytics-web 2.7.1 → 2.8.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.
Files changed (37) hide show
  1. package/dist/cjs/debug-agent.d.ts +171 -0
  2. package/dist/cjs/debug-agent.d.ts.map +1 -0
  3. package/dist/cjs/debug-agent.js +1219 -0
  4. package/dist/cjs/debug-agent.js.map +1 -0
  5. package/dist/cjs/index.d.ts +14 -0
  6. package/dist/cjs/index.d.ts.map +1 -1
  7. package/dist/cjs/index.js.map +1 -1
  8. package/dist/cjs/interaction-tracking.d.ts +6 -0
  9. package/dist/cjs/interaction-tracking.d.ts.map +1 -1
  10. package/dist/cjs/interaction-tracking.js +55 -5
  11. package/dist/cjs/interaction-tracking.js.map +1 -1
  12. package/dist/debug-agent.d.ts +171 -0
  13. package/dist/debug-agent.d.ts.map +1 -0
  14. package/dist/debug-agent.js +1219 -0
  15. package/dist/esm/debug-agent.d.ts +171 -0
  16. package/dist/esm/debug-agent.d.ts.map +1 -0
  17. package/dist/esm/debug-agent.js +1215 -0
  18. package/dist/esm/debug-agent.js.map +1 -0
  19. package/dist/esm/index.d.ts +14 -0
  20. package/dist/esm/index.d.ts.map +1 -1
  21. package/dist/esm/index.js.map +1 -1
  22. package/dist/esm/interaction-tracking.d.ts +6 -0
  23. package/dist/esm/interaction-tracking.d.ts.map +1 -1
  24. package/dist/esm/interaction-tracking.js +55 -5
  25. package/dist/esm/interaction-tracking.js.map +1 -1
  26. package/dist/index.d.ts +14 -0
  27. package/dist/index.d.ts.map +1 -1
  28. package/dist/index.global.dev.js +1326 -6
  29. package/dist/index.global.dev.js.map +4 -4
  30. package/dist/index.global.js +506 -2
  31. package/dist/index.global.js.map +4 -4
  32. package/dist/index.js +99 -0
  33. package/dist/index.mjs +99 -0
  34. package/dist/interaction-tracking.d.ts +6 -0
  35. package/dist/interaction-tracking.d.ts.map +1 -1
  36. package/dist/interaction-tracking.js +55 -5
  37. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -79,6 +79,9 @@ class GrainAnalytics {
79
79
  // Session tracking
80
80
  this.sessionStartTime = Date.now();
81
81
  this.sessionEventCount = 0;
82
+ // Debug mode properties
83
+ this.debugAgent = null;
84
+ this.isDebugMode = false;
82
85
  this.config = {
83
86
  apiUrl: 'https://api.grainql.com',
84
87
  authStrategy: 'NONE',
@@ -132,6 +135,8 @@ class GrainAnalytics {
132
135
  this.ephemeralSessionId = this.generateUUID();
133
136
  // Initialize automatic tracking (browser only)
134
137
  if (typeof window !== 'undefined') {
138
+ // Check for debug mode before initializing tracking
139
+ this.checkAndInitializeDebugMode();
135
140
  this.initializeAutomaticTracking();
136
141
  // Track session start
137
142
  this.trackSessionStart();
@@ -760,6 +765,8 @@ class GrainAnalytics {
760
765
  debug: this.config.debug,
761
766
  enableMutationObserver: true,
762
767
  mutationDebounceDelay: 500,
768
+ tenantId: this.config.tenantId,
769
+ apiUrl: this.config.apiUrl,
763
770
  });
764
771
  this.log('Interaction tracking initialized');
765
772
  }
@@ -1818,6 +1825,93 @@ class GrainAnalytics {
1818
1825
  offConsentChange(listener) {
1819
1826
  this.consentManager.removeListener(listener);
1820
1827
  }
1828
+ /**
1829
+ * Check for debug mode parameters and initialize debug agent if valid
1830
+ */
1831
+ checkAndInitializeDebugMode() {
1832
+ if (typeof window === 'undefined')
1833
+ return;
1834
+ try {
1835
+ const urlParams = new URLSearchParams(window.location.search);
1836
+ const isDebug = urlParams.get('grain_debug') === '1';
1837
+ const sessionId = urlParams.get('grain_session');
1838
+ if (!isDebug || !sessionId) {
1839
+ return;
1840
+ }
1841
+ this.log('Debug mode detected, verifying session:', sessionId);
1842
+ // Verify session with API
1843
+ this.verifyDebugSession(sessionId, window.location.hostname)
1844
+ .then((valid) => {
1845
+ if (valid) {
1846
+ this.log('Debug session verified, initializing debug agent');
1847
+ this.isDebugMode = true;
1848
+ this.initializeDebugAgent(sessionId);
1849
+ }
1850
+ else {
1851
+ this.log('Debug session verification failed');
1852
+ }
1853
+ })
1854
+ .catch((error) => {
1855
+ this.log('Failed to verify debug session:', error);
1856
+ });
1857
+ }
1858
+ catch (error) {
1859
+ this.log('Error checking debug mode:', error);
1860
+ }
1861
+ }
1862
+ /**
1863
+ * Verify debug session with API
1864
+ */
1865
+ async verifyDebugSession(sessionId, domain) {
1866
+ try {
1867
+ const url = `${this.config.apiUrl}/v1/tenant/${encodeURIComponent(this.config.tenantId)}/debug-sessions/verify`;
1868
+ const response = await fetch(url, {
1869
+ method: 'POST',
1870
+ headers: {
1871
+ 'Content-Type': 'application/json',
1872
+ },
1873
+ body: JSON.stringify({
1874
+ sessionId,
1875
+ domain,
1876
+ }),
1877
+ });
1878
+ if (!response.ok) {
1879
+ return false;
1880
+ }
1881
+ const result = await response.json();
1882
+ return result.valid === true;
1883
+ }
1884
+ catch (error) {
1885
+ this.log('Debug session verification error:', error);
1886
+ return false;
1887
+ }
1888
+ }
1889
+ /**
1890
+ * Initialize debug agent
1891
+ */
1892
+ initializeDebugAgent(sessionId) {
1893
+ if (typeof window === 'undefined')
1894
+ return;
1895
+ try {
1896
+ this.log('Loading debug agent module');
1897
+ Promise.resolve().then(() => __importStar(require('./debug-agent'))).then(({ DebugAgent }) => {
1898
+ try {
1899
+ this.debugAgent = new DebugAgent(this, sessionId, this.config.tenantId, this.config.apiUrl, {
1900
+ debug: this.config.debug,
1901
+ });
1902
+ this.log('Debug agent initialized');
1903
+ }
1904
+ catch (error) {
1905
+ this.log('Failed to initialize debug agent:', error);
1906
+ }
1907
+ }).catch((error) => {
1908
+ this.log('Failed to load debug agent module:', error);
1909
+ });
1910
+ }
1911
+ catch (error) {
1912
+ this.log('Error initializing debug agent:', error);
1913
+ }
1914
+ }
1821
1915
  /**
1822
1916
  * Destroy the client and clean up resources
1823
1917
  */
@@ -1857,6 +1951,11 @@ class GrainAnalytics {
1857
1951
  this.heatmapTrackingManager.destroy();
1858
1952
  this.heatmapTrackingManager = null;
1859
1953
  }
1954
+ // Destroy debug agent
1955
+ if (this.debugAgent) {
1956
+ this.debugAgent.destroy();
1957
+ this.debugAgent = null;
1958
+ }
1860
1959
  // Send any remaining events (in chunks if necessary)
1861
1960
  if (this.eventQueue.length > 0) {
1862
1961
  const eventsToSend = [...this.eventQueue];
package/dist/index.mjs CHANGED
@@ -38,6 +38,9 @@ export class GrainAnalytics {
38
38
  // Session tracking
39
39
  this.sessionStartTime = Date.now();
40
40
  this.sessionEventCount = 0;
41
+ // Debug mode properties
42
+ this.debugAgent = null;
43
+ this.isDebugMode = false;
41
44
  this.config = {
42
45
  apiUrl: 'https://api.grainql.com',
43
46
  authStrategy: 'NONE',
@@ -91,6 +94,8 @@ export class GrainAnalytics {
91
94
  this.ephemeralSessionId = this.generateUUID();
92
95
  // Initialize automatic tracking (browser only)
93
96
  if (typeof window !== 'undefined') {
97
+ // Check for debug mode before initializing tracking
98
+ this.checkAndInitializeDebugMode();
94
99
  this.initializeAutomaticTracking();
95
100
  // Track session start
96
101
  this.trackSessionStart();
@@ -719,6 +724,8 @@ export class GrainAnalytics {
719
724
  debug: this.config.debug,
720
725
  enableMutationObserver: true,
721
726
  mutationDebounceDelay: 500,
727
+ tenantId: this.config.tenantId,
728
+ apiUrl: this.config.apiUrl,
722
729
  });
723
730
  this.log('Interaction tracking initialized');
724
731
  }
@@ -1777,6 +1784,93 @@ export class GrainAnalytics {
1777
1784
  offConsentChange(listener) {
1778
1785
  this.consentManager.removeListener(listener);
1779
1786
  }
1787
+ /**
1788
+ * Check for debug mode parameters and initialize debug agent if valid
1789
+ */
1790
+ checkAndInitializeDebugMode() {
1791
+ if (typeof window === 'undefined')
1792
+ return;
1793
+ try {
1794
+ const urlParams = new URLSearchParams(window.location.search);
1795
+ const isDebug = urlParams.get('grain_debug') === '1';
1796
+ const sessionId = urlParams.get('grain_session');
1797
+ if (!isDebug || !sessionId) {
1798
+ return;
1799
+ }
1800
+ this.log('Debug mode detected, verifying session:', sessionId);
1801
+ // Verify session with API
1802
+ this.verifyDebugSession(sessionId, window.location.hostname)
1803
+ .then((valid) => {
1804
+ if (valid) {
1805
+ this.log('Debug session verified, initializing debug agent');
1806
+ this.isDebugMode = true;
1807
+ this.initializeDebugAgent(sessionId);
1808
+ }
1809
+ else {
1810
+ this.log('Debug session verification failed');
1811
+ }
1812
+ })
1813
+ .catch((error) => {
1814
+ this.log('Failed to verify debug session:', error);
1815
+ });
1816
+ }
1817
+ catch (error) {
1818
+ this.log('Error checking debug mode:', error);
1819
+ }
1820
+ }
1821
+ /**
1822
+ * Verify debug session with API
1823
+ */
1824
+ async verifyDebugSession(sessionId, domain) {
1825
+ try {
1826
+ const url = `${this.config.apiUrl}/v1/tenant/${encodeURIComponent(this.config.tenantId)}/debug-sessions/verify`;
1827
+ const response = await fetch(url, {
1828
+ method: 'POST',
1829
+ headers: {
1830
+ 'Content-Type': 'application/json',
1831
+ },
1832
+ body: JSON.stringify({
1833
+ sessionId,
1834
+ domain,
1835
+ }),
1836
+ });
1837
+ if (!response.ok) {
1838
+ return false;
1839
+ }
1840
+ const result = await response.json();
1841
+ return result.valid === true;
1842
+ }
1843
+ catch (error) {
1844
+ this.log('Debug session verification error:', error);
1845
+ return false;
1846
+ }
1847
+ }
1848
+ /**
1849
+ * Initialize debug agent
1850
+ */
1851
+ initializeDebugAgent(sessionId) {
1852
+ if (typeof window === 'undefined')
1853
+ return;
1854
+ try {
1855
+ this.log('Loading debug agent module');
1856
+ import('./debug-agent').then(({ DebugAgent }) => {
1857
+ try {
1858
+ this.debugAgent = new DebugAgent(this, sessionId, this.config.tenantId, this.config.apiUrl, {
1859
+ debug: this.config.debug,
1860
+ });
1861
+ this.log('Debug agent initialized');
1862
+ }
1863
+ catch (error) {
1864
+ this.log('Failed to initialize debug agent:', error);
1865
+ }
1866
+ }).catch((error) => {
1867
+ this.log('Failed to load debug agent module:', error);
1868
+ });
1869
+ }
1870
+ catch (error) {
1871
+ this.log('Error initializing debug agent:', error);
1872
+ }
1873
+ }
1780
1874
  /**
1781
1875
  * Destroy the client and clean up resources
1782
1876
  */
@@ -1816,6 +1910,11 @@ export class GrainAnalytics {
1816
1910
  this.heatmapTrackingManager.destroy();
1817
1911
  this.heatmapTrackingManager = null;
1818
1912
  }
1913
+ // Destroy debug agent
1914
+ if (this.debugAgent) {
1915
+ this.debugAgent.destroy();
1916
+ this.debugAgent = null;
1917
+ }
1819
1918
  // Send any remaining events (in chunks if necessary)
1820
1919
  if (this.eventQueue.length > 0) {
1821
1920
  const eventsToSend = [...this.eventQueue];
@@ -15,6 +15,8 @@ export interface InteractionTrackingConfig {
15
15
  debug?: boolean;
16
16
  enableMutationObserver?: boolean;
17
17
  mutationDebounceDelay?: number;
18
+ tenantId?: string;
19
+ apiUrl?: string;
18
20
  }
19
21
  export declare class InteractionTrackingManager {
20
22
  private tracker;
@@ -26,6 +28,10 @@ export declare class InteractionTrackingManager {
26
28
  private mutationObserver;
27
29
  private mutationDebounceTimer;
28
30
  constructor(tracker: InteractionTracker, interactions: InteractionConfig[], config?: InteractionTrackingConfig);
31
+ /**
32
+ * Fetch trackers from API and merge with existing interactions
33
+ */
34
+ private fetchAndMergeTrackers;
29
35
  /**
30
36
  * Attach listeners to all configured interactions
31
37
  */
@@ -1 +1 @@
1
- {"version":3,"file":"interaction-tracking.d.ts","sourceRoot":"","sources":["../src/interaction-tracking.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAG/D,MAAM,WAAW,gBAAgB;IAC/B,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,kBAAkB;IACjC,KAAK,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACjH,UAAU,CAAC,QAAQ,EAAE,WAAW,GAAG,WAAW,GAAG,YAAY,GAAG,OAAO,CAAC;IACxE,GAAG,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;CAC/B;AAED,MAAM,WAAW,yBAAyB;IACxC,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC,qBAAqB,CAAC,EAAE,MAAM,CAAC;CAChC;AAED,qBAAa,0BAA0B;IACrC,OAAO,CAAC,OAAO,CAAqB;IACpC,OAAO,CAAC,YAAY,CAAsB;IAC1C,OAAO,CAAC,MAAM,CAA4B;IAC1C,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,iBAAiB,CAA6E;IACtG,OAAO,CAAC,UAAU,CAA0C;IAC5D,OAAO,CAAC,gBAAgB,CAAiC;IACzD,OAAO,CAAC,qBAAqB,CAAuB;gBAGlD,OAAO,EAAE,kBAAkB,EAC3B,YAAY,EAAE,iBAAiB,EAAE,EACjC,MAAM,GAAE,yBAA8B;IA0BxC;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAU1B;;OAEG;IACH,OAAO,CAAC,yBAAyB;IAiCjC;;OAEG;IACH,OAAO,CAAC,sBAAsB;IAiC9B;;OAEG;IACH,OAAO,CAAC,sBAAsB;IAkB9B;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAyC1B;;OAEG;IACH,OAAO,CAAC,qBAAqB;IA0B7B;;OAEG;IACH,OAAO,CAAC,eAAe;IA+BvB;;OAEG;IACH,OAAO,CAAC,eAAe;IAWvB;;OAEG;IACH,OAAO,CAAC,GAAG;IAMX;;OAEG;IACH,kBAAkB,CAAC,YAAY,EAAE,iBAAiB,EAAE,GAAG,IAAI;IAoB3D;;OAEG;IACH,OAAO,IAAI,IAAI;CA4BhB"}
1
+ {"version":3,"file":"interaction-tracking.d.ts","sourceRoot":"","sources":["../src/interaction-tracking.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAG/D,MAAM,WAAW,gBAAgB;IAC/B,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,kBAAkB;IACjC,KAAK,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACjH,UAAU,CAAC,QAAQ,EAAE,WAAW,GAAG,WAAW,GAAG,YAAY,GAAG,OAAO,CAAC;IACxE,GAAG,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;CAC/B;AAED,MAAM,WAAW,yBAAyB;IACxC,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,qBAAa,0BAA0B;IACrC,OAAO,CAAC,OAAO,CAAqB;IACpC,OAAO,CAAC,YAAY,CAAsB;IAC1C,OAAO,CAAC,MAAM,CAA4B;IAC1C,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,iBAAiB,CAA6E;IACtG,OAAO,CAAC,UAAU,CAA0C;IAC5D,OAAO,CAAC,gBAAgB,CAAiC;IACzD,OAAO,CAAC,qBAAqB,CAAuB;gBAGlD,OAAO,EAAE,kBAAkB,EAC3B,YAAY,EAAE,iBAAiB,EAAE,EACjC,MAAM,GAAE,yBAA8B;IAmCxC;;OAEG;YACW,qBAAqB;IA6CnC;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAU1B;;OAEG;IACH,OAAO,CAAC,yBAAyB;IAiCjC;;OAEG;IACH,OAAO,CAAC,sBAAsB;IAiC9B;;OAEG;IACH,OAAO,CAAC,sBAAsB;IAkB9B;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAyC1B;;OAEG;IACH,OAAO,CAAC,qBAAqB;IA0B7B;;OAEG;IACH,OAAO,CAAC,eAAe;IA+BvB;;OAEG;IACH,OAAO,CAAC,eAAe;IAWvB;;OAEG;IACH,OAAO,CAAC,GAAG;IAMX;;OAEG;IACH,kBAAkB,CAAC,YAAY,EAAE,iBAAiB,EAAE,GAAG,IAAI;IAoB3D;;OAEG;IACH,OAAO,IAAI,IAAI;CA4BhB"}
@@ -19,15 +19,25 @@ class InteractionTrackingManager {
19
19
  debug: config.debug ?? false,
20
20
  enableMutationObserver: config.enableMutationObserver ?? true,
21
21
  mutationDebounceDelay: config.mutationDebounceDelay ?? 500,
22
+ tenantId: config.tenantId,
23
+ apiUrl: config.apiUrl,
22
24
  };
23
25
  if (typeof window !== 'undefined' && typeof document !== 'undefined') {
24
- // Attach listeners after DOM is ready
25
- if (document.readyState === 'loading') {
26
- document.addEventListener('DOMContentLoaded', () => this.attachAllListeners());
26
+ // Fetch and merge trackers if configured
27
+ if (this.config.tenantId && this.config.apiUrl) {
28
+ this.fetchAndMergeTrackers().then(() => {
29
+ this.attachAllListeners();
30
+ });
27
31
  }
28
32
  else {
29
- // DOM already loaded
30
- setTimeout(() => this.attachAllListeners(), 0);
33
+ // Attach listeners after DOM is ready
34
+ if (document.readyState === 'loading') {
35
+ document.addEventListener('DOMContentLoaded', () => this.attachAllListeners());
36
+ }
37
+ else {
38
+ // DOM already loaded
39
+ setTimeout(() => this.attachAllListeners(), 0);
40
+ }
31
41
  }
32
42
  // Setup mutation observer for dynamic content
33
43
  if (this.config.enableMutationObserver) {
@@ -35,6 +45,46 @@ class InteractionTrackingManager {
35
45
  }
36
46
  }
37
47
  }
48
+ /**
49
+ * Fetch trackers from API and merge with existing interactions
50
+ */
51
+ async fetchAndMergeTrackers() {
52
+ if (!this.config.tenantId || !this.config.apiUrl)
53
+ return;
54
+ try {
55
+ const currentUrl = typeof window !== 'undefined' ? window.location.href : '';
56
+ const url = `${this.config.apiUrl}/v1/client/${encodeURIComponent(this.config.tenantId)}/trackers?url=${encodeURIComponent(currentUrl)}`;
57
+ this.log('Fetching trackers from:', url);
58
+ const response = await fetch(url, {
59
+ method: 'GET',
60
+ headers: {
61
+ 'Content-Type': 'application/json',
62
+ },
63
+ });
64
+ if (!response.ok) {
65
+ this.log('Failed to fetch trackers:', response.status);
66
+ return;
67
+ }
68
+ const result = await response.json();
69
+ if (result.trackers && Array.isArray(result.trackers)) {
70
+ this.log('Fetched', result.trackers.length, 'trackers');
71
+ // Convert trackers to InteractionConfig format
72
+ const trackerInteractions = result.trackers.map((tracker) => ({
73
+ eventName: tracker.eventName,
74
+ selector: tracker.selector,
75
+ priority: 5, // High priority for manually created trackers
76
+ label: tracker.eventName,
77
+ description: `Tracker: ${tracker.eventName}`,
78
+ }));
79
+ // Merge with existing interactions (trackers take precedence)
80
+ this.interactions = [...trackerInteractions, ...this.interactions];
81
+ this.log('Merged trackers, total interactions:', this.interactions.length);
82
+ }
83
+ }
84
+ catch (error) {
85
+ this.log('Error fetching trackers:', error);
86
+ }
87
+ }
38
88
  /**
39
89
  * Attach listeners to all configured interactions
40
90
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@grainql/analytics-web",
3
- "version": "2.7.1",
3
+ "version": "2.8.0",
4
4
  "description": "Lightweight TypeScript SDK for sending analytics events and managing remote configurations via Grain's REST API",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",