@grainql/analytics-web 2.0.0 → 2.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.
- package/dist/activity.d.ts +59 -0
- package/dist/activity.d.ts.map +1 -0
- package/dist/activity.js +131 -0
- package/dist/cjs/activity.d.ts +59 -0
- package/dist/cjs/activity.d.ts.map +1 -0
- package/dist/cjs/activity.js +131 -0
- package/dist/cjs/activity.js.map +1 -0
- package/dist/cjs/consent.d.ts +68 -0
- package/dist/cjs/consent.d.ts.map +1 -0
- package/dist/cjs/consent.js +191 -0
- package/dist/cjs/consent.js.map +1 -0
- package/dist/cjs/cookies.d.ts +28 -0
- package/dist/cjs/cookies.d.ts.map +1 -0
- package/dist/cjs/cookies.js +95 -0
- package/dist/cjs/cookies.js.map +1 -0
- package/dist/cjs/heartbeat.d.ts +42 -0
- package/dist/cjs/heartbeat.d.ts.map +1 -0
- package/dist/cjs/heartbeat.js +92 -0
- package/dist/cjs/heartbeat.js.map +1 -0
- package/dist/cjs/index.d.ts +100 -3
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/page-tracking.d.ts +60 -0
- package/dist/cjs/page-tracking.d.ts.map +1 -0
- package/dist/cjs/page-tracking.js +180 -0
- package/dist/cjs/page-tracking.js.map +1 -0
- package/dist/cjs/react/components/ConsentBanner.d.ts +16 -0
- package/dist/cjs/react/components/ConsentBanner.d.ts.map +1 -0
- package/dist/cjs/react/components/ConsentBanner.js +112 -0
- package/dist/cjs/react/components/ConsentBanner.js.map +1 -0
- package/dist/cjs/react/components/CookieNotice.d.ts +12 -0
- package/dist/cjs/react/components/CookieNotice.d.ts.map +1 -0
- package/dist/cjs/react/components/CookieNotice.js +62 -0
- package/dist/cjs/react/components/CookieNotice.js.map +1 -0
- package/dist/cjs/react/components/PrivacyPreferenceCenter.d.ts +12 -0
- package/dist/cjs/react/components/PrivacyPreferenceCenter.d.ts.map +1 -0
- package/dist/cjs/react/components/PrivacyPreferenceCenter.js +120 -0
- package/dist/cjs/react/components/PrivacyPreferenceCenter.js.map +1 -0
- package/dist/cjs/react/hooks/useConsent.d.ts +13 -0
- package/dist/cjs/react/hooks/useConsent.d.ts.map +1 -0
- package/dist/cjs/react/hooks/useConsent.js +84 -0
- package/dist/cjs/react/hooks/useConsent.js.map +1 -0
- package/dist/cjs/react/hooks/useDataDeletion.d.ts +17 -0
- package/dist/cjs/react/hooks/useDataDeletion.d.ts.map +1 -0
- package/dist/cjs/react/hooks/useDataDeletion.js +117 -0
- package/dist/cjs/react/hooks/useDataDeletion.js.map +1 -0
- package/dist/cjs/react/hooks/usePrivacyPreferences.d.ts +15 -0
- package/dist/cjs/react/hooks/usePrivacyPreferences.d.ts.map +1 -0
- package/dist/cjs/react/hooks/usePrivacyPreferences.js +82 -0
- package/dist/cjs/react/hooks/usePrivacyPreferences.js.map +1 -0
- package/dist/cjs/react/index.d.ts +11 -0
- package/dist/cjs/react/index.d.ts.map +1 -1
- package/dist/cjs/react/index.js +15 -1
- package/dist/cjs/react/index.js.map +1 -1
- package/dist/consent.d.ts +68 -0
- package/dist/consent.d.ts.map +1 -0
- package/dist/consent.js +191 -0
- package/dist/cookies.d.ts +28 -0
- package/dist/cookies.d.ts.map +1 -0
- package/dist/cookies.js +95 -0
- package/dist/esm/activity.d.ts +59 -0
- package/dist/esm/activity.d.ts.map +1 -0
- package/dist/esm/activity.js +127 -0
- package/dist/esm/activity.js.map +1 -0
- package/dist/esm/consent.d.ts +68 -0
- package/dist/esm/consent.d.ts.map +1 -0
- package/dist/esm/consent.js +187 -0
- package/dist/esm/consent.js.map +1 -0
- package/dist/esm/cookies.d.ts +28 -0
- package/dist/esm/cookies.d.ts.map +1 -0
- package/dist/esm/cookies.js +89 -0
- package/dist/esm/cookies.js.map +1 -0
- package/dist/esm/heartbeat.d.ts +42 -0
- package/dist/esm/heartbeat.d.ts.map +1 -0
- package/dist/esm/heartbeat.js +88 -0
- package/dist/esm/heartbeat.js.map +1 -0
- package/dist/esm/index.d.ts +100 -3
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/page-tracking.d.ts +60 -0
- package/dist/esm/page-tracking.d.ts.map +1 -0
- package/dist/esm/page-tracking.js +176 -0
- package/dist/esm/page-tracking.js.map +1 -0
- package/dist/esm/react/components/ConsentBanner.d.ts +16 -0
- package/dist/esm/react/components/ConsentBanner.d.ts.map +1 -0
- package/dist/esm/react/components/ConsentBanner.js +76 -0
- package/dist/esm/react/components/ConsentBanner.js.map +1 -0
- package/dist/esm/react/components/CookieNotice.d.ts +12 -0
- package/dist/esm/react/components/CookieNotice.d.ts.map +1 -0
- package/dist/esm/react/components/CookieNotice.js +26 -0
- package/dist/esm/react/components/CookieNotice.js.map +1 -0
- package/dist/esm/react/components/PrivacyPreferenceCenter.d.ts +12 -0
- package/dist/esm/react/components/PrivacyPreferenceCenter.d.ts.map +1 -0
- package/dist/esm/react/components/PrivacyPreferenceCenter.js +84 -0
- package/dist/esm/react/components/PrivacyPreferenceCenter.js.map +1 -0
- package/dist/esm/react/hooks/useConsent.d.ts +13 -0
- package/dist/esm/react/hooks/useConsent.d.ts.map +1 -0
- package/dist/esm/react/hooks/useConsent.js +48 -0
- package/dist/esm/react/hooks/useConsent.js.map +1 -0
- package/dist/esm/react/hooks/useDataDeletion.d.ts +17 -0
- package/dist/esm/react/hooks/useDataDeletion.d.ts.map +1 -0
- package/dist/esm/react/hooks/useDataDeletion.js +81 -0
- package/dist/esm/react/hooks/useDataDeletion.js.map +1 -0
- package/dist/esm/react/hooks/usePrivacyPreferences.d.ts +15 -0
- package/dist/esm/react/hooks/usePrivacyPreferences.d.ts.map +1 -0
- package/dist/esm/react/hooks/usePrivacyPreferences.js +46 -0
- package/dist/esm/react/hooks/usePrivacyPreferences.js.map +1 -0
- package/dist/esm/react/index.d.ts +11 -0
- package/dist/esm/react/index.d.ts.map +1 -1
- package/dist/esm/react/index.js +8 -0
- package/dist/esm/react/index.js.map +1 -1
- package/dist/heartbeat.d.ts +42 -0
- package/dist/heartbeat.d.ts.map +1 -0
- package/dist/heartbeat.js +92 -0
- package/dist/index.d.ts +100 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.global.dev.js +903 -12
- package/dist/index.global.dev.js.map +3 -3
- package/dist/index.global.js +2 -2
- package/dist/index.global.js.map +4 -4
- package/dist/index.js +321 -11
- package/dist/index.mjs +321 -11
- package/dist/page-tracking.d.ts +60 -0
- package/dist/page-tracking.d.ts.map +1 -0
- package/dist/page-tracking.js +180 -0
- package/dist/react/activity.d.ts +59 -0
- package/dist/react/activity.d.ts.map +1 -0
- package/dist/react/activity.js +130 -0
- package/dist/react/activity.mjs +126 -0
- package/dist/react/consent.d.ts +68 -0
- package/dist/react/consent.d.ts.map +1 -0
- package/dist/react/consent.js +190 -0
- package/dist/react/consent.mjs +186 -0
- package/dist/react/cookies.d.ts +28 -0
- package/dist/react/cookies.d.ts.map +1 -0
- package/dist/react/cookies.js +94 -0
- package/dist/react/cookies.mjs +88 -0
- package/dist/react/heartbeat.d.ts +42 -0
- package/dist/react/heartbeat.d.ts.map +1 -0
- package/dist/react/heartbeat.js +91 -0
- package/dist/react/heartbeat.mjs +87 -0
- package/dist/react/index.d.ts +100 -3
- package/dist/react/index.d.ts.map +1 -1
- package/dist/react/index.js +321 -11
- package/dist/react/index.mjs +321 -11
- package/dist/react/page-tracking.d.ts +60 -0
- package/dist/react/page-tracking.d.ts.map +1 -0
- package/dist/react/page-tracking.js +179 -0
- package/dist/react/page-tracking.mjs +175 -0
- package/dist/react/react/components/ConsentBanner.d.ts +16 -0
- package/dist/react/react/components/ConsentBanner.d.ts.map +1 -0
- package/dist/react/react/components/ConsentBanner.js +78 -0
- package/dist/react/react/components/ConsentBanner.mjs +75 -0
- package/dist/react/react/components/CookieNotice.d.ts +12 -0
- package/dist/react/react/components/CookieNotice.d.ts.map +1 -0
- package/dist/react/react/components/CookieNotice.js +28 -0
- package/dist/react/react/components/CookieNotice.mjs +25 -0
- package/dist/react/react/components/PrivacyPreferenceCenter.d.ts +12 -0
- package/dist/react/react/components/PrivacyPreferenceCenter.d.ts.map +1 -0
- package/dist/react/react/components/PrivacyPreferenceCenter.js +86 -0
- package/dist/react/react/components/PrivacyPreferenceCenter.mjs +83 -0
- package/dist/react/react/hooks/useConsent.d.ts +13 -0
- package/dist/react/react/hooks/useConsent.d.ts.map +1 -0
- package/dist/react/react/hooks/useConsent.js +50 -0
- package/dist/react/react/hooks/useConsent.mjs +47 -0
- package/dist/react/react/hooks/useDataDeletion.d.ts +17 -0
- package/dist/react/react/hooks/useDataDeletion.d.ts.map +1 -0
- package/dist/react/react/hooks/useDataDeletion.js +83 -0
- package/dist/react/react/hooks/useDataDeletion.mjs +80 -0
- package/dist/react/react/hooks/usePrivacyPreferences.d.ts +15 -0
- package/dist/react/react/hooks/usePrivacyPreferences.d.ts.map +1 -0
- package/dist/react/react/hooks/usePrivacyPreferences.js +48 -0
- package/dist/react/react/hooks/usePrivacyPreferences.mjs +45 -0
- package/dist/react/react/index.d.ts +11 -0
- package/dist/react/react/index.d.ts.map +1 -1
- package/dist/react/react/index.js +15 -1
- package/dist/react/react/index.mjs +8 -0
- package/package.json +3 -3
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Page Tracking for Grain Analytics
|
|
4
|
+
* Automatically tracks page views with consent-aware behavior
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.PageTrackingManager = void 0;
|
|
8
|
+
class PageTrackingManager {
|
|
9
|
+
constructor(tracker, config) {
|
|
10
|
+
this.isDestroyed = false;
|
|
11
|
+
this.currentPath = null;
|
|
12
|
+
this.originalPushState = null;
|
|
13
|
+
this.originalReplaceState = null;
|
|
14
|
+
/**
|
|
15
|
+
* Handle popstate event (back/forward navigation)
|
|
16
|
+
*/
|
|
17
|
+
this.handlePopState = () => {
|
|
18
|
+
if (this.isDestroyed)
|
|
19
|
+
return;
|
|
20
|
+
this.trackCurrentPage();
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Handle hash change event
|
|
24
|
+
*/
|
|
25
|
+
this.handleHashChange = () => {
|
|
26
|
+
if (this.isDestroyed)
|
|
27
|
+
return;
|
|
28
|
+
this.trackCurrentPage();
|
|
29
|
+
};
|
|
30
|
+
this.tracker = tracker;
|
|
31
|
+
this.config = config;
|
|
32
|
+
// Track initial page load
|
|
33
|
+
this.trackCurrentPage();
|
|
34
|
+
// Setup listeners
|
|
35
|
+
this.setupHistoryListeners();
|
|
36
|
+
this.setupHashChangeListener();
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Setup History API listeners (pushState, replaceState, popstate)
|
|
40
|
+
*/
|
|
41
|
+
setupHistoryListeners() {
|
|
42
|
+
if (typeof window === 'undefined' || typeof history === 'undefined')
|
|
43
|
+
return;
|
|
44
|
+
// Wrap pushState
|
|
45
|
+
this.originalPushState = history.pushState;
|
|
46
|
+
history.pushState = (state, title, url) => {
|
|
47
|
+
this.originalPushState?.call(history, state, title, url);
|
|
48
|
+
this.trackCurrentPage();
|
|
49
|
+
};
|
|
50
|
+
// Wrap replaceState
|
|
51
|
+
this.originalReplaceState = history.replaceState;
|
|
52
|
+
history.replaceState = (state, title, url) => {
|
|
53
|
+
this.originalReplaceState?.call(history, state, title, url);
|
|
54
|
+
this.trackCurrentPage();
|
|
55
|
+
};
|
|
56
|
+
// Listen to popstate (back/forward buttons)
|
|
57
|
+
window.addEventListener('popstate', this.handlePopState);
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Setup hash change listener
|
|
61
|
+
*/
|
|
62
|
+
setupHashChangeListener() {
|
|
63
|
+
if (typeof window === 'undefined')
|
|
64
|
+
return;
|
|
65
|
+
window.addEventListener('hashchange', this.handleHashChange);
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Track the current page
|
|
69
|
+
*/
|
|
70
|
+
trackCurrentPage() {
|
|
71
|
+
if (this.isDestroyed || typeof window === 'undefined')
|
|
72
|
+
return;
|
|
73
|
+
const page = this.extractPath(window.location.href);
|
|
74
|
+
// Don't track if it's the same page
|
|
75
|
+
if (page === this.currentPath) {
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
this.currentPath = page;
|
|
79
|
+
const hasConsent = this.tracker.hasConsent('analytics');
|
|
80
|
+
// Base properties (always included)
|
|
81
|
+
const properties = {
|
|
82
|
+
page,
|
|
83
|
+
timestamp: Date.now(),
|
|
84
|
+
};
|
|
85
|
+
// Enhanced properties when consent is granted
|
|
86
|
+
if (hasConsent) {
|
|
87
|
+
properties.referrer = document.referrer || '';
|
|
88
|
+
properties.title = document.title || '';
|
|
89
|
+
properties.full_url = window.location.href;
|
|
90
|
+
}
|
|
91
|
+
// Track the page view event
|
|
92
|
+
this.tracker.trackSystemEvent('page_view', properties);
|
|
93
|
+
if (this.config.debug) {
|
|
94
|
+
console.log('[Page Tracking] Tracked page view:', properties);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Extract path from URL, optionally stripping query parameters
|
|
99
|
+
*/
|
|
100
|
+
extractPath(url) {
|
|
101
|
+
try {
|
|
102
|
+
const urlObj = new URL(url);
|
|
103
|
+
let path = urlObj.pathname + urlObj.hash;
|
|
104
|
+
if (!this.config.stripQueryParams && urlObj.search) {
|
|
105
|
+
path += urlObj.search;
|
|
106
|
+
}
|
|
107
|
+
return path;
|
|
108
|
+
}
|
|
109
|
+
catch (error) {
|
|
110
|
+
// If URL parsing fails, return the raw string
|
|
111
|
+
if (this.config.debug) {
|
|
112
|
+
console.warn('[Page Tracking] Failed to parse URL:', url, error);
|
|
113
|
+
}
|
|
114
|
+
return url;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Get the current page path
|
|
119
|
+
*/
|
|
120
|
+
getCurrentPage() {
|
|
121
|
+
return this.currentPath;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Manually track a page view (for custom navigation)
|
|
125
|
+
*/
|
|
126
|
+
trackPage(page, properties) {
|
|
127
|
+
if (this.isDestroyed)
|
|
128
|
+
return;
|
|
129
|
+
const hasConsent = this.tracker.hasConsent('analytics');
|
|
130
|
+
// Base properties
|
|
131
|
+
const baseProperties = {
|
|
132
|
+
page,
|
|
133
|
+
timestamp: Date.now(),
|
|
134
|
+
...properties,
|
|
135
|
+
};
|
|
136
|
+
// Enhanced properties when consent is granted
|
|
137
|
+
if (hasConsent && typeof document !== 'undefined') {
|
|
138
|
+
if (!baseProperties.referrer) {
|
|
139
|
+
baseProperties.referrer = document.referrer || '';
|
|
140
|
+
}
|
|
141
|
+
if (!baseProperties.title) {
|
|
142
|
+
baseProperties.title = document.title || '';
|
|
143
|
+
}
|
|
144
|
+
if (!baseProperties.full_url && typeof window !== 'undefined') {
|
|
145
|
+
baseProperties.full_url = window.location.href;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
this.tracker.trackSystemEvent('page_view', baseProperties);
|
|
149
|
+
if (this.config.debug) {
|
|
150
|
+
console.log('[Page Tracking] Manually tracked page:', baseProperties);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Destroy the page tracker
|
|
155
|
+
*/
|
|
156
|
+
destroy() {
|
|
157
|
+
if (this.isDestroyed)
|
|
158
|
+
return;
|
|
159
|
+
// Restore original history methods
|
|
160
|
+
if (typeof history !== 'undefined') {
|
|
161
|
+
if (this.originalPushState) {
|
|
162
|
+
history.pushState = this.originalPushState;
|
|
163
|
+
}
|
|
164
|
+
if (this.originalReplaceState) {
|
|
165
|
+
history.replaceState = this.originalReplaceState;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
// Remove event listeners
|
|
169
|
+
if (typeof window !== 'undefined') {
|
|
170
|
+
window.removeEventListener('popstate', this.handlePopState);
|
|
171
|
+
window.removeEventListener('hashchange', this.handleHashChange);
|
|
172
|
+
}
|
|
173
|
+
this.isDestroyed = true;
|
|
174
|
+
if (this.config.debug) {
|
|
175
|
+
console.log('[Page Tracking] Destroyed');
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
exports.PageTrackingManager = PageTrackingManager;
|
|
180
|
+
//# sourceMappingURL=page-tracking.js.map
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Activity Detection for Grain Analytics
|
|
3
|
+
* Tracks user activity (mouse, keyboard, touch, scroll) to determine if user is active
|
|
4
|
+
*/
|
|
5
|
+
export declare class ActivityDetector {
|
|
6
|
+
private lastActivityTime;
|
|
7
|
+
private activityThreshold;
|
|
8
|
+
private listeners;
|
|
9
|
+
private boundActivityHandler;
|
|
10
|
+
private isDestroyed;
|
|
11
|
+
private readonly activityEvents;
|
|
12
|
+
constructor();
|
|
13
|
+
/**
|
|
14
|
+
* Setup event listeners for activity detection
|
|
15
|
+
*/
|
|
16
|
+
private setupListeners;
|
|
17
|
+
/**
|
|
18
|
+
* Handle activity event
|
|
19
|
+
*/
|
|
20
|
+
private handleActivity;
|
|
21
|
+
/**
|
|
22
|
+
* Debounce function to limit how often activity handler is called
|
|
23
|
+
*/
|
|
24
|
+
private debounce;
|
|
25
|
+
/**
|
|
26
|
+
* Check if user is currently active
|
|
27
|
+
* @param threshold Time in ms to consider user inactive (default: 30s)
|
|
28
|
+
*/
|
|
29
|
+
isActive(threshold?: number): boolean;
|
|
30
|
+
/**
|
|
31
|
+
* Get time since last activity in milliseconds
|
|
32
|
+
*/
|
|
33
|
+
getTimeSinceLastActivity(): number;
|
|
34
|
+
/**
|
|
35
|
+
* Get last activity timestamp
|
|
36
|
+
*/
|
|
37
|
+
getLastActivityTime(): number;
|
|
38
|
+
/**
|
|
39
|
+
* Set activity threshold
|
|
40
|
+
*/
|
|
41
|
+
setActivityThreshold(threshold: number): void;
|
|
42
|
+
/**
|
|
43
|
+
* Add listener for activity changes
|
|
44
|
+
*/
|
|
45
|
+
addListener(listener: () => void): void;
|
|
46
|
+
/**
|
|
47
|
+
* Remove listener
|
|
48
|
+
*/
|
|
49
|
+
removeListener(listener: () => void): void;
|
|
50
|
+
/**
|
|
51
|
+
* Notify all listeners
|
|
52
|
+
*/
|
|
53
|
+
private notifyListeners;
|
|
54
|
+
/**
|
|
55
|
+
* Cleanup and remove listeners
|
|
56
|
+
*/
|
|
57
|
+
destroy(): void;
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=activity.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"activity.d.ts","sourceRoot":"","sources":["../../src/activity.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,gBAAgB,CAAS;IACjC,OAAO,CAAC,iBAAiB,CAAiB;IAC1C,OAAO,CAAC,SAAS,CAAyB;IAC1C,OAAO,CAAC,oBAAoB,CAAa;IACzC,OAAO,CAAC,WAAW,CAAS;IAG5B,OAAO,CAAC,QAAQ,CAAC,cAAc,CAOpB;;IAQX;;OAEG;IACH,OAAO,CAAC,cAAc;IAQtB;;OAEG;IACH,OAAO,CAAC,cAAc;IAMtB;;OAEG;IACH,OAAO,CAAC,QAAQ;IAehB;;;OAGG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO;IAMrC;;OAEG;IACH,wBAAwB,IAAI,MAAM;IAIlC;;OAEG;IACH,mBAAmB,IAAI,MAAM;IAI7B;;OAEG;IACH,oBAAoB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAI7C;;OAEG;IACH,WAAW,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,IAAI;IAIvC;;OAEG;IACH,cAAc,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,IAAI;IAO1C;;OAEG;IACH,OAAO,CAAC,eAAe;IAUvB;;OAEG;IACH,OAAO,IAAI,IAAI;CAYhB"}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Activity Detection for Grain Analytics
|
|
4
|
+
* Tracks user activity (mouse, keyboard, touch, scroll) to determine if user is active
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.ActivityDetector = void 0;
|
|
8
|
+
class ActivityDetector {
|
|
9
|
+
constructor() {
|
|
10
|
+
this.activityThreshold = 30000; // 30 seconds
|
|
11
|
+
this.listeners = [];
|
|
12
|
+
this.isDestroyed = false;
|
|
13
|
+
// Events that indicate user activity
|
|
14
|
+
this.activityEvents = [
|
|
15
|
+
'mousemove',
|
|
16
|
+
'mousedown',
|
|
17
|
+
'keydown',
|
|
18
|
+
'scroll',
|
|
19
|
+
'touchstart',
|
|
20
|
+
'click',
|
|
21
|
+
];
|
|
22
|
+
this.lastActivityTime = Date.now();
|
|
23
|
+
this.boundActivityHandler = this.debounce(this.handleActivity.bind(this), 500);
|
|
24
|
+
this.setupListeners();
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Setup event listeners for activity detection
|
|
28
|
+
*/
|
|
29
|
+
setupListeners() {
|
|
30
|
+
if (typeof window === 'undefined')
|
|
31
|
+
return;
|
|
32
|
+
for (const event of this.activityEvents) {
|
|
33
|
+
window.addEventListener(event, this.boundActivityHandler, { passive: true });
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Handle activity event
|
|
38
|
+
*/
|
|
39
|
+
handleActivity() {
|
|
40
|
+
if (this.isDestroyed)
|
|
41
|
+
return;
|
|
42
|
+
this.lastActivityTime = Date.now();
|
|
43
|
+
this.notifyListeners();
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Debounce function to limit how often activity handler is called
|
|
47
|
+
*/
|
|
48
|
+
debounce(func, wait) {
|
|
49
|
+
let timeout = null;
|
|
50
|
+
return () => {
|
|
51
|
+
if (timeout !== null) {
|
|
52
|
+
clearTimeout(timeout);
|
|
53
|
+
}
|
|
54
|
+
timeout = window.setTimeout(() => {
|
|
55
|
+
func();
|
|
56
|
+
timeout = null;
|
|
57
|
+
}, wait);
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Check if user is currently active
|
|
62
|
+
* @param threshold Time in ms to consider user inactive (default: 30s)
|
|
63
|
+
*/
|
|
64
|
+
isActive(threshold) {
|
|
65
|
+
const thresholdToUse = threshold ?? this.activityThreshold;
|
|
66
|
+
const now = Date.now();
|
|
67
|
+
return (now - this.lastActivityTime) < thresholdToUse;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Get time since last activity in milliseconds
|
|
71
|
+
*/
|
|
72
|
+
getTimeSinceLastActivity() {
|
|
73
|
+
return Date.now() - this.lastActivityTime;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Get last activity timestamp
|
|
77
|
+
*/
|
|
78
|
+
getLastActivityTime() {
|
|
79
|
+
return this.lastActivityTime;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Set activity threshold
|
|
83
|
+
*/
|
|
84
|
+
setActivityThreshold(threshold) {
|
|
85
|
+
this.activityThreshold = threshold;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Add listener for activity changes
|
|
89
|
+
*/
|
|
90
|
+
addListener(listener) {
|
|
91
|
+
this.listeners.push(listener);
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Remove listener
|
|
95
|
+
*/
|
|
96
|
+
removeListener(listener) {
|
|
97
|
+
const index = this.listeners.indexOf(listener);
|
|
98
|
+
if (index > -1) {
|
|
99
|
+
this.listeners.splice(index, 1);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Notify all listeners
|
|
104
|
+
*/
|
|
105
|
+
notifyListeners() {
|
|
106
|
+
for (const listener of this.listeners) {
|
|
107
|
+
try {
|
|
108
|
+
listener();
|
|
109
|
+
}
|
|
110
|
+
catch (error) {
|
|
111
|
+
console.error('[Activity Detector] Listener error:', error);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Cleanup and remove listeners
|
|
117
|
+
*/
|
|
118
|
+
destroy() {
|
|
119
|
+
if (this.isDestroyed)
|
|
120
|
+
return;
|
|
121
|
+
if (typeof window !== 'undefined') {
|
|
122
|
+
for (const event of this.activityEvents) {
|
|
123
|
+
window.removeEventListener(event, this.boundActivityHandler);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
this.listeners = [];
|
|
127
|
+
this.isDestroyed = true;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
exports.ActivityDetector = ActivityDetector;
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Activity Detection for Grain Analytics
|
|
3
|
+
* Tracks user activity (mouse, keyboard, touch, scroll) to determine if user is active
|
|
4
|
+
*/
|
|
5
|
+
export class ActivityDetector {
|
|
6
|
+
constructor() {
|
|
7
|
+
this.activityThreshold = 30000; // 30 seconds
|
|
8
|
+
this.listeners = [];
|
|
9
|
+
this.isDestroyed = false;
|
|
10
|
+
// Events that indicate user activity
|
|
11
|
+
this.activityEvents = [
|
|
12
|
+
'mousemove',
|
|
13
|
+
'mousedown',
|
|
14
|
+
'keydown',
|
|
15
|
+
'scroll',
|
|
16
|
+
'touchstart',
|
|
17
|
+
'click',
|
|
18
|
+
];
|
|
19
|
+
this.lastActivityTime = Date.now();
|
|
20
|
+
this.boundActivityHandler = this.debounce(this.handleActivity.bind(this), 500);
|
|
21
|
+
this.setupListeners();
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Setup event listeners for activity detection
|
|
25
|
+
*/
|
|
26
|
+
setupListeners() {
|
|
27
|
+
if (typeof window === 'undefined')
|
|
28
|
+
return;
|
|
29
|
+
for (const event of this.activityEvents) {
|
|
30
|
+
window.addEventListener(event, this.boundActivityHandler, { passive: true });
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Handle activity event
|
|
35
|
+
*/
|
|
36
|
+
handleActivity() {
|
|
37
|
+
if (this.isDestroyed)
|
|
38
|
+
return;
|
|
39
|
+
this.lastActivityTime = Date.now();
|
|
40
|
+
this.notifyListeners();
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Debounce function to limit how often activity handler is called
|
|
44
|
+
*/
|
|
45
|
+
debounce(func, wait) {
|
|
46
|
+
let timeout = null;
|
|
47
|
+
return () => {
|
|
48
|
+
if (timeout !== null) {
|
|
49
|
+
clearTimeout(timeout);
|
|
50
|
+
}
|
|
51
|
+
timeout = window.setTimeout(() => {
|
|
52
|
+
func();
|
|
53
|
+
timeout = null;
|
|
54
|
+
}, wait);
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Check if user is currently active
|
|
59
|
+
* @param threshold Time in ms to consider user inactive (default: 30s)
|
|
60
|
+
*/
|
|
61
|
+
isActive(threshold) {
|
|
62
|
+
const thresholdToUse = threshold ?? this.activityThreshold;
|
|
63
|
+
const now = Date.now();
|
|
64
|
+
return (now - this.lastActivityTime) < thresholdToUse;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Get time since last activity in milliseconds
|
|
68
|
+
*/
|
|
69
|
+
getTimeSinceLastActivity() {
|
|
70
|
+
return Date.now() - this.lastActivityTime;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Get last activity timestamp
|
|
74
|
+
*/
|
|
75
|
+
getLastActivityTime() {
|
|
76
|
+
return this.lastActivityTime;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Set activity threshold
|
|
80
|
+
*/
|
|
81
|
+
setActivityThreshold(threshold) {
|
|
82
|
+
this.activityThreshold = threshold;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Add listener for activity changes
|
|
86
|
+
*/
|
|
87
|
+
addListener(listener) {
|
|
88
|
+
this.listeners.push(listener);
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Remove listener
|
|
92
|
+
*/
|
|
93
|
+
removeListener(listener) {
|
|
94
|
+
const index = this.listeners.indexOf(listener);
|
|
95
|
+
if (index > -1) {
|
|
96
|
+
this.listeners.splice(index, 1);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Notify all listeners
|
|
101
|
+
*/
|
|
102
|
+
notifyListeners() {
|
|
103
|
+
for (const listener of this.listeners) {
|
|
104
|
+
try {
|
|
105
|
+
listener();
|
|
106
|
+
}
|
|
107
|
+
catch (error) {
|
|
108
|
+
console.error('[Activity Detector] Listener error:', error);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Cleanup and remove listeners
|
|
114
|
+
*/
|
|
115
|
+
destroy() {
|
|
116
|
+
if (this.isDestroyed)
|
|
117
|
+
return;
|
|
118
|
+
if (typeof window !== 'undefined') {
|
|
119
|
+
for (const event of this.activityEvents) {
|
|
120
|
+
window.removeEventListener(event, this.boundActivityHandler);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
this.listeners = [];
|
|
124
|
+
this.isDestroyed = true;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Consent management for Grain Analytics
|
|
3
|
+
* Handles GDPR-compliant consent tracking and state management
|
|
4
|
+
*/
|
|
5
|
+
export type ConsentMode = 'opt-in' | 'opt-out' | 'disabled';
|
|
6
|
+
export interface ConsentState {
|
|
7
|
+
granted: boolean;
|
|
8
|
+
categories: string[];
|
|
9
|
+
timestamp: Date;
|
|
10
|
+
version: string;
|
|
11
|
+
}
|
|
12
|
+
export declare const DEFAULT_CONSENT_CATEGORIES: string[];
|
|
13
|
+
export declare const CONSENT_VERSION = "1.0.0";
|
|
14
|
+
/**
|
|
15
|
+
* Consent manager for handling user consent state
|
|
16
|
+
*/
|
|
17
|
+
export declare class ConsentManager {
|
|
18
|
+
private consentState;
|
|
19
|
+
private consentMode;
|
|
20
|
+
private storageKey;
|
|
21
|
+
private listeners;
|
|
22
|
+
constructor(tenantId: string, consentMode?: ConsentMode);
|
|
23
|
+
/**
|
|
24
|
+
* Load consent state from localStorage
|
|
25
|
+
*/
|
|
26
|
+
private loadConsentState;
|
|
27
|
+
/**
|
|
28
|
+
* Save consent state to localStorage
|
|
29
|
+
*/
|
|
30
|
+
private saveConsentState;
|
|
31
|
+
/**
|
|
32
|
+
* Grant consent with optional categories
|
|
33
|
+
*/
|
|
34
|
+
grantConsent(categories?: string[]): void;
|
|
35
|
+
/**
|
|
36
|
+
* Revoke consent (opt-out)
|
|
37
|
+
*/
|
|
38
|
+
revokeConsent(categories?: string[]): void;
|
|
39
|
+
/**
|
|
40
|
+
* Get current consent state
|
|
41
|
+
*/
|
|
42
|
+
getConsentState(): ConsentState | null;
|
|
43
|
+
/**
|
|
44
|
+
* Check if user has granted consent
|
|
45
|
+
*/
|
|
46
|
+
hasConsent(category?: string): boolean;
|
|
47
|
+
/**
|
|
48
|
+
* Check if we should wait for consent before tracking
|
|
49
|
+
*/
|
|
50
|
+
shouldWaitForConsent(): boolean;
|
|
51
|
+
/**
|
|
52
|
+
* Add consent change listener
|
|
53
|
+
*/
|
|
54
|
+
addListener(listener: (state: ConsentState) => void): void;
|
|
55
|
+
/**
|
|
56
|
+
* Remove consent change listener
|
|
57
|
+
*/
|
|
58
|
+
removeListener(listener: (state: ConsentState) => void): void;
|
|
59
|
+
/**
|
|
60
|
+
* Notify all listeners of consent state change
|
|
61
|
+
*/
|
|
62
|
+
private notifyListeners;
|
|
63
|
+
/**
|
|
64
|
+
* Clear all consent data
|
|
65
|
+
*/
|
|
66
|
+
clearConsent(): void;
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=consent.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"consent.d.ts","sourceRoot":"","sources":["../../src/consent.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG,SAAS,GAAG,UAAU,CAAC;AAE5D,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,SAAS,EAAE,IAAI,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,eAAO,MAAM,0BAA0B,UAA2C,CAAC;AACnF,eAAO,MAAM,eAAe,UAAU,CAAC;AAEvC;;GAEG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,YAAY,CAA6B;IACjD,OAAO,CAAC,WAAW,CAAc;IACjC,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,SAAS,CAA4C;gBAEjD,QAAQ,EAAE,MAAM,EAAE,WAAW,GAAE,WAAuB;IAMlE;;OAEG;IACH,OAAO,CAAC,gBAAgB;IA0BxB;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAUxB;;OAEG;IACH,YAAY,CAAC,UAAU,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI;IAczC;;OAEG;IACH,aAAa,CAAC,UAAU,CAAC,EAAE,MAAM,EAAE,GAAG,IAAI;IA8B1C;;OAEG;IACH,eAAe,IAAI,YAAY,GAAG,IAAI;IAItC;;OAEG;IACH,UAAU,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO;IAwBtC;;OAEG;IACH,oBAAoB,IAAI,OAAO;IAI/B;;OAEG;IACH,WAAW,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,GAAG,IAAI;IAI1D;;OAEG;IACH,cAAc,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,GAAG,IAAI;IAO7D;;OAEG;IACH,OAAO,CAAC,eAAe;IAYvB;;OAEG;IACH,YAAY,IAAI,IAAI;CAUrB"}
|