@grainql/analytics-web 2.4.0 → 2.5.3

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 (47) hide show
  1. package/dist/cjs/index.d.ts +29 -1
  2. package/dist/cjs/index.d.ts.map +1 -1
  3. package/dist/cjs/index.js.map +1 -1
  4. package/dist/cjs/interaction-tracking.d.ts +74 -0
  5. package/dist/cjs/interaction-tracking.d.ts.map +1 -0
  6. package/dist/cjs/interaction-tracking.js +292 -0
  7. package/dist/cjs/interaction-tracking.js.map +1 -0
  8. package/dist/cjs/section-tracking.d.ts +101 -0
  9. package/dist/cjs/section-tracking.d.ts.map +1 -0
  10. package/dist/cjs/section-tracking.js +455 -0
  11. package/dist/cjs/section-tracking.js.map +1 -0
  12. package/dist/cjs/types/auto-tracking.d.ts +55 -0
  13. package/dist/cjs/types/auto-tracking.d.ts.map +1 -0
  14. package/dist/cjs/types/auto-tracking.js +6 -0
  15. package/dist/cjs/types/auto-tracking.js.map +1 -0
  16. package/dist/esm/index.d.ts +29 -1
  17. package/dist/esm/index.d.ts.map +1 -1
  18. package/dist/esm/index.js.map +1 -1
  19. package/dist/esm/interaction-tracking.d.ts +74 -0
  20. package/dist/esm/interaction-tracking.d.ts.map +1 -0
  21. package/dist/esm/interaction-tracking.js +288 -0
  22. package/dist/esm/interaction-tracking.js.map +1 -0
  23. package/dist/esm/section-tracking.d.ts +101 -0
  24. package/dist/esm/section-tracking.d.ts.map +1 -0
  25. package/dist/esm/section-tracking.js +451 -0
  26. package/dist/esm/section-tracking.js.map +1 -0
  27. package/dist/esm/types/auto-tracking.d.ts +55 -0
  28. package/dist/esm/types/auto-tracking.d.ts.map +1 -0
  29. package/dist/esm/types/auto-tracking.js +5 -0
  30. package/dist/esm/types/auto-tracking.js.map +1 -0
  31. package/dist/index.d.ts +29 -1
  32. package/dist/index.d.ts.map +1 -1
  33. package/dist/index.global.dev.js +821 -3
  34. package/dist/index.global.dev.js.map +4 -4
  35. package/dist/index.global.js +2 -2
  36. package/dist/index.global.js.map +4 -4
  37. package/dist/index.js +149 -4
  38. package/dist/index.mjs +116 -4
  39. package/dist/interaction-tracking.d.ts +74 -0
  40. package/dist/interaction-tracking.d.ts.map +1 -0
  41. package/dist/interaction-tracking.js +292 -0
  42. package/dist/section-tracking.d.ts +101 -0
  43. package/dist/section-tracking.d.ts.map +1 -0
  44. package/dist/section-tracking.js +455 -0
  45. package/dist/types/auto-tracking.d.ts +55 -0
  46. package/dist/types/auto-tracking.d.ts.map +1 -0
  47. package/package.json +1 -1
@@ -0,0 +1,288 @@
1
+ /**
2
+ * Interaction Tracking Manager for Grain Analytics
3
+ * Automatically attaches click and focus listeners to detected interactive elements
4
+ */
5
+ export class InteractionTrackingManager {
6
+ constructor(tracker, interactions, config = {}) {
7
+ this.isDestroyed = false;
8
+ this.attachedListeners = new Map();
9
+ this.xpathCache = new Map();
10
+ this.mutationObserver = null;
11
+ this.mutationDebounceTimer = null;
12
+ this.tracker = tracker;
13
+ this.interactions = interactions;
14
+ this.config = {
15
+ debug: config.debug ?? false,
16
+ enableMutationObserver: config.enableMutationObserver ?? true,
17
+ mutationDebounceDelay: config.mutationDebounceDelay ?? 500,
18
+ };
19
+ if (typeof window !== 'undefined' && typeof document !== 'undefined') {
20
+ // Attach listeners after DOM is ready
21
+ if (document.readyState === 'loading') {
22
+ document.addEventListener('DOMContentLoaded', () => this.attachAllListeners());
23
+ }
24
+ else {
25
+ // DOM already loaded
26
+ setTimeout(() => this.attachAllListeners(), 0);
27
+ }
28
+ // Setup mutation observer for dynamic content
29
+ if (this.config.enableMutationObserver) {
30
+ this.setupMutationObserver();
31
+ }
32
+ }
33
+ }
34
+ /**
35
+ * Attach listeners to all configured interactions
36
+ */
37
+ attachAllListeners() {
38
+ if (this.isDestroyed)
39
+ return;
40
+ this.log('Attaching interaction listeners for', this.interactions.length, 'interactions');
41
+ for (const interaction of this.interactions) {
42
+ this.attachInteractionListener(interaction);
43
+ }
44
+ }
45
+ /**
46
+ * Attach listener to a specific interaction
47
+ */
48
+ attachInteractionListener(interaction) {
49
+ if (this.isDestroyed)
50
+ return;
51
+ const element = this.findElementByXPath(interaction.selector);
52
+ if (!element) {
53
+ this.log('Element not found for interaction:', interaction.eventName, 'selector:', interaction.selector);
54
+ return;
55
+ }
56
+ // Check if we already attached listeners to this element for this interaction
57
+ if (this.attachedListeners.has(element)) {
58
+ this.log('Listeners already attached for element:', element);
59
+ return;
60
+ }
61
+ const handlers = [];
62
+ // Click handler
63
+ const clickHandler = (event) => this.handleInteractionClick(interaction, event);
64
+ element.addEventListener('click', clickHandler, { passive: true });
65
+ handlers.push({ event: 'click', handler: clickHandler });
66
+ // Focus handler (for form inputs)
67
+ if (element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement || element instanceof HTMLSelectElement) {
68
+ const focusHandler = (event) => this.handleInteractionFocus(interaction, event);
69
+ element.addEventListener('focus', focusHandler, { passive: true });
70
+ handlers.push({ event: 'focus', handler: focusHandler });
71
+ }
72
+ this.attachedListeners.set(element, handlers);
73
+ this.log('Attached listeners to element for:', interaction.eventName);
74
+ }
75
+ /**
76
+ * Handle click event on interaction
77
+ */
78
+ handleInteractionClick(interaction, event) {
79
+ if (this.isDestroyed)
80
+ return;
81
+ if (!this.tracker.hasConsent('analytics'))
82
+ return;
83
+ const element = event.target;
84
+ // Check if this is a navigation link (has href attribute)
85
+ const isNavigationLink = element instanceof HTMLAnchorElement && element.href;
86
+ const eventProperties = {
87
+ interaction_type: 'click',
88
+ interaction_label: interaction.label,
89
+ interaction_description: interaction.description,
90
+ interaction_priority: interaction.priority,
91
+ element_tag: element.tagName?.toLowerCase(),
92
+ element_text: element.textContent?.trim().substring(0, 100),
93
+ element_id: element.id || undefined,
94
+ element_class: element.className || undefined,
95
+ ...(isNavigationLink && { href: element.href }),
96
+ timestamp: Date.now(),
97
+ };
98
+ // If it's a navigation link, flush immediately to ensure event is sent before navigation
99
+ if (isNavigationLink) {
100
+ // Use flush option to send immediately - handle promise if returned
101
+ const result = this.tracker.track(interaction.eventName, eventProperties, { flush: true });
102
+ if (result instanceof Promise) {
103
+ result.catch((error) => {
104
+ // Log error but don't block navigation
105
+ this.log('Failed to track navigation click:', error);
106
+ });
107
+ }
108
+ }
109
+ else {
110
+ this.tracker.track(interaction.eventName, eventProperties);
111
+ }
112
+ this.log('Tracked click interaction:', interaction.eventName);
113
+ }
114
+ /**
115
+ * Handle focus event on interaction (for form fields)
116
+ */
117
+ handleInteractionFocus(interaction, event) {
118
+ if (this.isDestroyed)
119
+ return;
120
+ if (!this.tracker.hasConsent('analytics'))
121
+ return;
122
+ const element = event.target;
123
+ this.tracker.track(interaction.eventName, {
124
+ interaction_type: 'focus',
125
+ interaction_label: interaction.label,
126
+ interaction_description: interaction.description,
127
+ interaction_priority: interaction.priority,
128
+ element_tag: element.tagName?.toLowerCase(),
129
+ element_id: element.id || undefined,
130
+ element_class: element.className || undefined,
131
+ timestamp: Date.now(),
132
+ });
133
+ this.log('Tracked focus interaction:', interaction.eventName);
134
+ }
135
+ /**
136
+ * Find element by XPath selector
137
+ */
138
+ findElementByXPath(xpath) {
139
+ // Check cache first
140
+ if (this.xpathCache.has(xpath)) {
141
+ const cached = this.xpathCache.get(xpath);
142
+ // Verify element is still in DOM
143
+ if (cached && document.contains(cached)) {
144
+ return cached;
145
+ }
146
+ // Clear invalid cache entry
147
+ this.xpathCache.delete(xpath);
148
+ }
149
+ try {
150
+ // Strip the xpath= prefix if present (from Stagehand selectors)
151
+ let cleanXpath = xpath;
152
+ if (xpath.startsWith('xpath=')) {
153
+ cleanXpath = xpath.substring(6); // Remove 'xpath=' prefix
154
+ }
155
+ const result = document.evaluate(cleanXpath, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null);
156
+ const element = result.singleNodeValue;
157
+ // Cache the result (use original xpath as key)
158
+ if (element) {
159
+ this.xpathCache.set(xpath, element);
160
+ }
161
+ return element;
162
+ }
163
+ catch (error) {
164
+ this.log('Error evaluating XPath:', xpath, error);
165
+ return null;
166
+ }
167
+ }
168
+ /**
169
+ * Setup mutation observer to handle dynamic content
170
+ */
171
+ setupMutationObserver() {
172
+ if (typeof MutationObserver === 'undefined') {
173
+ this.log('MutationObserver not supported');
174
+ return;
175
+ }
176
+ this.mutationObserver = new MutationObserver((mutations) => {
177
+ // Debounce the re-attachment
178
+ if (this.mutationDebounceTimer !== null) {
179
+ clearTimeout(this.mutationDebounceTimer);
180
+ }
181
+ this.mutationDebounceTimer = window.setTimeout(() => {
182
+ this.handleMutations(mutations);
183
+ this.mutationDebounceTimer = null;
184
+ }, this.config.mutationDebounceDelay);
185
+ });
186
+ this.mutationObserver.observe(document.body, {
187
+ childList: true,
188
+ subtree: true,
189
+ });
190
+ this.log('Mutation observer setup');
191
+ }
192
+ /**
193
+ * Handle DOM mutations
194
+ */
195
+ handleMutations(mutations) {
196
+ if (this.isDestroyed)
197
+ return;
198
+ // Clear XPath cache on mutations
199
+ this.xpathCache.clear();
200
+ // Check if any of our tracked elements were removed
201
+ const removedElements = new Set();
202
+ for (const mutation of mutations) {
203
+ mutation.removedNodes.forEach((node) => {
204
+ if (node instanceof Element) {
205
+ removedElements.add(node);
206
+ // Also check for child elements we were tracking
207
+ this.attachedListeners.forEach((handlers, element) => {
208
+ if (node.contains(element)) {
209
+ removedElements.add(element);
210
+ }
211
+ });
212
+ }
213
+ });
214
+ }
215
+ // Clean up removed elements
216
+ removedElements.forEach((element) => {
217
+ this.detachListeners(element);
218
+ });
219
+ // Try to re-attach listeners for any interactions that might now be available
220
+ this.attachAllListeners();
221
+ }
222
+ /**
223
+ * Detach listeners from an element
224
+ */
225
+ detachListeners(element) {
226
+ const handlers = this.attachedListeners.get(element);
227
+ if (!handlers)
228
+ return;
229
+ handlers.forEach(({ event, handler }) => {
230
+ element.removeEventListener(event, handler);
231
+ });
232
+ this.attachedListeners.delete(element);
233
+ this.log('Detached listeners from element');
234
+ }
235
+ /**
236
+ * Log debug messages
237
+ */
238
+ log(...args) {
239
+ if (this.config.debug) {
240
+ console.log('[InteractionTracking]', ...args);
241
+ }
242
+ }
243
+ /**
244
+ * Update interactions configuration
245
+ */
246
+ updateInteractions(interactions) {
247
+ if (this.isDestroyed)
248
+ return;
249
+ this.log('Updating interactions configuration');
250
+ // Detach all existing listeners
251
+ this.attachedListeners.forEach((handlers, element) => {
252
+ this.detachListeners(element);
253
+ });
254
+ // Clear cache
255
+ this.xpathCache.clear();
256
+ // Update configuration
257
+ this.interactions = interactions;
258
+ // Reattach listeners
259
+ this.attachAllListeners();
260
+ }
261
+ /**
262
+ * Cleanup and destroy
263
+ */
264
+ destroy() {
265
+ if (this.isDestroyed)
266
+ return;
267
+ this.log('Destroying interaction tracking manager');
268
+ this.isDestroyed = true;
269
+ // Clear debounce timer
270
+ if (this.mutationDebounceTimer !== null) {
271
+ clearTimeout(this.mutationDebounceTimer);
272
+ this.mutationDebounceTimer = null;
273
+ }
274
+ // Disconnect mutation observer
275
+ if (this.mutationObserver) {
276
+ this.mutationObserver.disconnect();
277
+ this.mutationObserver = null;
278
+ }
279
+ // Detach all listeners
280
+ this.attachedListeners.forEach((handlers, element) => {
281
+ this.detachListeners(element);
282
+ });
283
+ // Clear caches
284
+ this.attachedListeners.clear();
285
+ this.xpathCache.clear();
286
+ }
287
+ }
288
+ //# sourceMappingURL=interaction-tracking.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interaction-tracking.js","sourceRoot":"","sources":["../../src/interaction-tracking.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,101 @@
1
+ /**
2
+ * Section Tracking Manager for Grain Analytics
3
+ * Intelligent scroll tracking with viewport metrics, visible sections, and engagement analysis
4
+ */
5
+ import type { SectionConfig, SectionTrackingOptions } from './types/auto-tracking';
6
+ export interface SectionTracker {
7
+ trackSystemEvent(eventName: string, properties: Record<string, unknown>): void;
8
+ hasConsent(category: 'analytics' | 'marketing' | 'functional'): boolean;
9
+ log(...args: unknown[]): void;
10
+ }
11
+ export declare class SectionTrackingManager {
12
+ private tracker;
13
+ private sections;
14
+ private options;
15
+ private isDestroyed;
16
+ private sectionStates;
17
+ private intersectionObserver;
18
+ private xpathCache;
19
+ private lastScrollPosition;
20
+ private lastScrollTime;
21
+ private scrollVelocity;
22
+ private scrollDebounceTimer;
23
+ private pendingEvents;
24
+ private batchTimer;
25
+ private sectionTimers;
26
+ private readonly SPLIT_DURATION;
27
+ constructor(tracker: SectionTracker, sections: SectionConfig[], options?: Partial<SectionTrackingOptions>);
28
+ /**
29
+ * Initialize section tracking
30
+ */
31
+ private initialize;
32
+ /**
33
+ * Setup IntersectionObserver for section visibility
34
+ */
35
+ private setupIntersectionObserver;
36
+ /**
37
+ * Setup scroll listener for velocity calculation
38
+ */
39
+ private setupScrollListener;
40
+ /**
41
+ * Initialize sections and start observing
42
+ */
43
+ private initializeSections;
44
+ /**
45
+ * Handle intersection observer entry
46
+ */
47
+ private handleIntersection;
48
+ /**
49
+ * Handle section entry (became visible)
50
+ */
51
+ private handleSectionEntry;
52
+ /**
53
+ * Start periodic tracking for a section (sends events every 3 seconds)
54
+ */
55
+ private startPeriodicTracking;
56
+ /**
57
+ * Stop periodic tracking for a section
58
+ */
59
+ private stopPeriodicTracking;
60
+ /**
61
+ * Handle section exit (became invisible)
62
+ */
63
+ private handleSectionExit;
64
+ /**
65
+ * Update scroll velocity
66
+ */
67
+ private updateScrollVelocity;
68
+ /**
69
+ * Calculate current scroll depth as percentage
70
+ */
71
+ private calculateScrollDepth;
72
+ /**
73
+ * Determine if section view should be tracked (sanitization)
74
+ */
75
+ private shouldTrackSection;
76
+ /**
77
+ * Queue section view for batching
78
+ */
79
+ private queueSectionView;
80
+ /**
81
+ * Flush pending section view events
82
+ */
83
+ private flushPendingEvents;
84
+ /**
85
+ * Find element by XPath selector
86
+ */
87
+ private findElementByXPath;
88
+ /**
89
+ * Log debug messages
90
+ */
91
+ private log;
92
+ /**
93
+ * Update sections configuration
94
+ */
95
+ updateSections(sections: SectionConfig[]): void;
96
+ /**
97
+ * Cleanup and destroy
98
+ */
99
+ destroy(): void;
100
+ }
101
+ //# sourceMappingURL=section-tracking.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"section-tracking.d.ts","sourceRoot":"","sources":["../../src/section-tracking.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAmB,sBAAsB,EAAwB,MAAM,uBAAuB,CAAC;AAE1H,MAAM,WAAW,cAAc;IAC7B,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IAC/E,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;AAWD,qBAAa,sBAAsB;IACjC,OAAO,CAAC,OAAO,CAAiB;IAChC,OAAO,CAAC,QAAQ,CAAkB;IAClC,OAAO,CAAC,OAAO,CAAyB;IACxC,OAAO,CAAC,WAAW,CAAS;IAG5B,OAAO,CAAC,aAAa,CAAgD;IACrE,OAAO,CAAC,oBAAoB,CAAqC;IACjE,OAAO,CAAC,UAAU,CAA0C;IAG5D,OAAO,CAAC,kBAAkB,CAAK;IAC/B,OAAO,CAAC,cAAc,CAAc;IACpC,OAAO,CAAC,cAAc,CAAK;IAC3B,OAAO,CAAC,mBAAmB,CAAuB;IAGlD,OAAO,CAAC,aAAa,CAAyB;IAC9C,OAAO,CAAC,UAAU,CAAuB;IAGzC,OAAO,CAAC,aAAa,CAAkC;IACvD,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAQ;gBAGrC,OAAO,EAAE,cAAc,EACvB,QAAQ,EAAE,aAAa,EAAE,EACzB,OAAO,GAAE,OAAO,CAAC,sBAAsB,CAAM;IAgB/C;;OAEG;IACH,OAAO,CAAC,UAAU;IAelB;;OAEG;IACH,OAAO,CAAC,yBAAyB;IAqBjC;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAkB3B;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAkC1B;;OAEG;IACH,OAAO,CAAC,kBAAkB;IA8B1B;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAa1B;;OAEG;IACH,OAAO,CAAC,qBAAqB;IA2D7B;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAQ5B;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAuCzB;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAe5B;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAoB5B;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAqB1B;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAYxB;;OAEG;IACH,OAAO,CAAC,kBAAkB;IA+B1B;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAuC1B;;OAEG;IACH,OAAO,CAAC,GAAG;IAMX;;OAEG;IACH,cAAc,CAAC,QAAQ,EAAE,aAAa,EAAE,GAAG,IAAI;IAsB/C;;OAEG;IACH,OAAO,IAAI,IAAI;CAsChB"}