@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,292 @@
1
+ "use strict";
2
+ /**
3
+ * Interaction Tracking Manager for Grain Analytics
4
+ * Automatically attaches click and focus listeners to detected interactive elements
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.InteractionTrackingManager = void 0;
8
+ class InteractionTrackingManager {
9
+ constructor(tracker, interactions, config = {}) {
10
+ this.isDestroyed = false;
11
+ this.attachedListeners = new Map();
12
+ this.xpathCache = new Map();
13
+ this.mutationObserver = null;
14
+ this.mutationDebounceTimer = null;
15
+ this.tracker = tracker;
16
+ this.interactions = interactions;
17
+ this.config = {
18
+ debug: config.debug ?? false,
19
+ enableMutationObserver: config.enableMutationObserver ?? true,
20
+ mutationDebounceDelay: config.mutationDebounceDelay ?? 500,
21
+ };
22
+ if (typeof window !== 'undefined' && typeof document !== 'undefined') {
23
+ // Attach listeners after DOM is ready
24
+ if (document.readyState === 'loading') {
25
+ document.addEventListener('DOMContentLoaded', () => this.attachAllListeners());
26
+ }
27
+ else {
28
+ // DOM already loaded
29
+ setTimeout(() => this.attachAllListeners(), 0);
30
+ }
31
+ // Setup mutation observer for dynamic content
32
+ if (this.config.enableMutationObserver) {
33
+ this.setupMutationObserver();
34
+ }
35
+ }
36
+ }
37
+ /**
38
+ * Attach listeners to all configured interactions
39
+ */
40
+ attachAllListeners() {
41
+ if (this.isDestroyed)
42
+ return;
43
+ this.log('Attaching interaction listeners for', this.interactions.length, 'interactions');
44
+ for (const interaction of this.interactions) {
45
+ this.attachInteractionListener(interaction);
46
+ }
47
+ }
48
+ /**
49
+ * Attach listener to a specific interaction
50
+ */
51
+ attachInteractionListener(interaction) {
52
+ if (this.isDestroyed)
53
+ return;
54
+ const element = this.findElementByXPath(interaction.selector);
55
+ if (!element) {
56
+ this.log('Element not found for interaction:', interaction.eventName, 'selector:', interaction.selector);
57
+ return;
58
+ }
59
+ // Check if we already attached listeners to this element for this interaction
60
+ if (this.attachedListeners.has(element)) {
61
+ this.log('Listeners already attached for element:', element);
62
+ return;
63
+ }
64
+ const handlers = [];
65
+ // Click handler
66
+ const clickHandler = (event) => this.handleInteractionClick(interaction, event);
67
+ element.addEventListener('click', clickHandler, { passive: true });
68
+ handlers.push({ event: 'click', handler: clickHandler });
69
+ // Focus handler (for form inputs)
70
+ if (element instanceof HTMLInputElement || element instanceof HTMLTextAreaElement || element instanceof HTMLSelectElement) {
71
+ const focusHandler = (event) => this.handleInteractionFocus(interaction, event);
72
+ element.addEventListener('focus', focusHandler, { passive: true });
73
+ handlers.push({ event: 'focus', handler: focusHandler });
74
+ }
75
+ this.attachedListeners.set(element, handlers);
76
+ this.log('Attached listeners to element for:', interaction.eventName);
77
+ }
78
+ /**
79
+ * Handle click event on interaction
80
+ */
81
+ handleInteractionClick(interaction, event) {
82
+ if (this.isDestroyed)
83
+ return;
84
+ if (!this.tracker.hasConsent('analytics'))
85
+ return;
86
+ const element = event.target;
87
+ // Check if this is a navigation link (has href attribute)
88
+ const isNavigationLink = element instanceof HTMLAnchorElement && element.href;
89
+ const eventProperties = {
90
+ interaction_type: 'click',
91
+ interaction_label: interaction.label,
92
+ interaction_description: interaction.description,
93
+ interaction_priority: interaction.priority,
94
+ element_tag: element.tagName?.toLowerCase(),
95
+ element_text: element.textContent?.trim().substring(0, 100),
96
+ element_id: element.id || undefined,
97
+ element_class: element.className || undefined,
98
+ ...(isNavigationLink && { href: element.href }),
99
+ timestamp: Date.now(),
100
+ };
101
+ // If it's a navigation link, flush immediately to ensure event is sent before navigation
102
+ if (isNavigationLink) {
103
+ // Use flush option to send immediately - handle promise if returned
104
+ const result = this.tracker.track(interaction.eventName, eventProperties, { flush: true });
105
+ if (result instanceof Promise) {
106
+ result.catch((error) => {
107
+ // Log error but don't block navigation
108
+ this.log('Failed to track navigation click:', error);
109
+ });
110
+ }
111
+ }
112
+ else {
113
+ this.tracker.track(interaction.eventName, eventProperties);
114
+ }
115
+ this.log('Tracked click interaction:', interaction.eventName);
116
+ }
117
+ /**
118
+ * Handle focus event on interaction (for form fields)
119
+ */
120
+ handleInteractionFocus(interaction, event) {
121
+ if (this.isDestroyed)
122
+ return;
123
+ if (!this.tracker.hasConsent('analytics'))
124
+ return;
125
+ const element = event.target;
126
+ this.tracker.track(interaction.eventName, {
127
+ interaction_type: 'focus',
128
+ interaction_label: interaction.label,
129
+ interaction_description: interaction.description,
130
+ interaction_priority: interaction.priority,
131
+ element_tag: element.tagName?.toLowerCase(),
132
+ element_id: element.id || undefined,
133
+ element_class: element.className || undefined,
134
+ timestamp: Date.now(),
135
+ });
136
+ this.log('Tracked focus interaction:', interaction.eventName);
137
+ }
138
+ /**
139
+ * Find element by XPath selector
140
+ */
141
+ findElementByXPath(xpath) {
142
+ // Check cache first
143
+ if (this.xpathCache.has(xpath)) {
144
+ const cached = this.xpathCache.get(xpath);
145
+ // Verify element is still in DOM
146
+ if (cached && document.contains(cached)) {
147
+ return cached;
148
+ }
149
+ // Clear invalid cache entry
150
+ this.xpathCache.delete(xpath);
151
+ }
152
+ try {
153
+ // Strip the xpath= prefix if present (from Stagehand selectors)
154
+ let cleanXpath = xpath;
155
+ if (xpath.startsWith('xpath=')) {
156
+ cleanXpath = xpath.substring(6); // Remove 'xpath=' prefix
157
+ }
158
+ const result = document.evaluate(cleanXpath, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null);
159
+ const element = result.singleNodeValue;
160
+ // Cache the result (use original xpath as key)
161
+ if (element) {
162
+ this.xpathCache.set(xpath, element);
163
+ }
164
+ return element;
165
+ }
166
+ catch (error) {
167
+ this.log('Error evaluating XPath:', xpath, error);
168
+ return null;
169
+ }
170
+ }
171
+ /**
172
+ * Setup mutation observer to handle dynamic content
173
+ */
174
+ setupMutationObserver() {
175
+ if (typeof MutationObserver === 'undefined') {
176
+ this.log('MutationObserver not supported');
177
+ return;
178
+ }
179
+ this.mutationObserver = new MutationObserver((mutations) => {
180
+ // Debounce the re-attachment
181
+ if (this.mutationDebounceTimer !== null) {
182
+ clearTimeout(this.mutationDebounceTimer);
183
+ }
184
+ this.mutationDebounceTimer = window.setTimeout(() => {
185
+ this.handleMutations(mutations);
186
+ this.mutationDebounceTimer = null;
187
+ }, this.config.mutationDebounceDelay);
188
+ });
189
+ this.mutationObserver.observe(document.body, {
190
+ childList: true,
191
+ subtree: true,
192
+ });
193
+ this.log('Mutation observer setup');
194
+ }
195
+ /**
196
+ * Handle DOM mutations
197
+ */
198
+ handleMutations(mutations) {
199
+ if (this.isDestroyed)
200
+ return;
201
+ // Clear XPath cache on mutations
202
+ this.xpathCache.clear();
203
+ // Check if any of our tracked elements were removed
204
+ const removedElements = new Set();
205
+ for (const mutation of mutations) {
206
+ mutation.removedNodes.forEach((node) => {
207
+ if (node instanceof Element) {
208
+ removedElements.add(node);
209
+ // Also check for child elements we were tracking
210
+ this.attachedListeners.forEach((handlers, element) => {
211
+ if (node.contains(element)) {
212
+ removedElements.add(element);
213
+ }
214
+ });
215
+ }
216
+ });
217
+ }
218
+ // Clean up removed elements
219
+ removedElements.forEach((element) => {
220
+ this.detachListeners(element);
221
+ });
222
+ // Try to re-attach listeners for any interactions that might now be available
223
+ this.attachAllListeners();
224
+ }
225
+ /**
226
+ * Detach listeners from an element
227
+ */
228
+ detachListeners(element) {
229
+ const handlers = this.attachedListeners.get(element);
230
+ if (!handlers)
231
+ return;
232
+ handlers.forEach(({ event, handler }) => {
233
+ element.removeEventListener(event, handler);
234
+ });
235
+ this.attachedListeners.delete(element);
236
+ this.log('Detached listeners from element');
237
+ }
238
+ /**
239
+ * Log debug messages
240
+ */
241
+ log(...args) {
242
+ if (this.config.debug) {
243
+ console.log('[InteractionTracking]', ...args);
244
+ }
245
+ }
246
+ /**
247
+ * Update interactions configuration
248
+ */
249
+ updateInteractions(interactions) {
250
+ if (this.isDestroyed)
251
+ return;
252
+ this.log('Updating interactions configuration');
253
+ // Detach all existing listeners
254
+ this.attachedListeners.forEach((handlers, element) => {
255
+ this.detachListeners(element);
256
+ });
257
+ // Clear cache
258
+ this.xpathCache.clear();
259
+ // Update configuration
260
+ this.interactions = interactions;
261
+ // Reattach listeners
262
+ this.attachAllListeners();
263
+ }
264
+ /**
265
+ * Cleanup and destroy
266
+ */
267
+ destroy() {
268
+ if (this.isDestroyed)
269
+ return;
270
+ this.log('Destroying interaction tracking manager');
271
+ this.isDestroyed = true;
272
+ // Clear debounce timer
273
+ if (this.mutationDebounceTimer !== null) {
274
+ clearTimeout(this.mutationDebounceTimer);
275
+ this.mutationDebounceTimer = null;
276
+ }
277
+ // Disconnect mutation observer
278
+ if (this.mutationObserver) {
279
+ this.mutationObserver.disconnect();
280
+ this.mutationObserver = null;
281
+ }
282
+ // Detach all listeners
283
+ this.attachedListeners.forEach((handlers, element) => {
284
+ this.detachListeners(element);
285
+ });
286
+ // Clear caches
287
+ this.attachedListeners.clear();
288
+ this.xpathCache.clear();
289
+ }
290
+ }
291
+ exports.InteractionTrackingManager = InteractionTrackingManager;
292
+ //# 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"}