@dotcms/analytics 1.1.1 → 1.2.0-next.10
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/README.md +475 -72
- package/lib/core/{dot-content-analytics.d.ts → dot-analytics.content.d.ts} +8 -1
- package/lib/core/dot-analytics.content.js +63 -0
- package/lib/core/plugin/click/dot-analytics.click-tracker.d.ts +108 -0
- package/lib/core/plugin/click/dot-analytics.click-tracker.js +144 -0
- package/lib/core/plugin/click/dot-analytics.click.plugin.d.ts +36 -0
- package/lib/core/plugin/click/dot-analytics.click.plugin.js +27 -0
- package/lib/core/plugin/click/dot-analytics.click.utils.d.ts +12 -0
- package/lib/core/plugin/click/dot-analytics.click.utils.js +55 -0
- package/lib/core/plugin/enricher/dot-analytics.enricher.plugin.d.ts +18 -30
- package/lib/core/plugin/enricher/dot-analytics.enricher.plugin.js +30 -20
- package/lib/core/plugin/identity/dot-analytics.identity.activity-tracker.d.ts +20 -0
- package/lib/core/{shared/dot-content-analytics.activity-tracker.js → plugin/identity/dot-analytics.identity.activity-tracker.js} +19 -38
- package/lib/core/plugin/identity/dot-analytics.identity.plugin.d.ts +13 -31
- package/lib/core/plugin/identity/dot-analytics.identity.plugin.js +14 -12
- package/lib/core/plugin/identity/dot-analytics.identity.utils.d.ts +7 -22
- package/lib/core/plugin/impression/dot-analytics.impression-tracker.d.ts +62 -0
- package/lib/core/plugin/impression/dot-analytics.impression-tracker.js +200 -0
- package/lib/core/plugin/impression/dot-analytics.impression.plugin.d.ts +40 -0
- package/lib/core/plugin/impression/dot-analytics.impression.plugin.js +27 -0
- package/lib/core/plugin/impression/dot-analytics.impression.utils.d.ts +26 -0
- package/lib/core/plugin/impression/dot-analytics.impression.utils.js +27 -0
- package/lib/core/plugin/impression/index.d.ts +2 -0
- package/lib/core/plugin/main/dot-analytics.plugin.d.ts +46 -0
- package/lib/core/plugin/main/dot-analytics.plugin.js +114 -0
- package/lib/core/shared/constants/dot-analytics.constants.d.ts +131 -0
- package/lib/core/shared/constants/dot-analytics.constants.js +52 -0
- package/lib/core/shared/constants/index.d.ts +4 -0
- package/lib/core/shared/dot-analytics.logger.d.ts +85 -0
- package/lib/core/shared/dot-analytics.logger.js +90 -0
- package/lib/core/shared/http/dot-analytics.http.d.ts +9 -0
- package/lib/core/shared/http/dot-analytics.http.js +34 -0
- package/lib/core/shared/models/data.model.d.ts +141 -0
- package/lib/core/shared/models/event.model.d.ts +135 -0
- package/lib/core/shared/models/index.d.ts +7 -0
- package/lib/core/shared/models/library.model.d.ts +243 -0
- package/lib/core/shared/models/request.model.d.ts +32 -0
- package/lib/core/shared/queue/dot-analytics.queue.utils.d.ts +28 -0
- package/lib/core/shared/queue/dot-analytics.queue.utils.js +80 -0
- package/lib/core/shared/queue/index.d.ts +1 -0
- package/lib/core/shared/utils/dot-analytics.utils.d.ts +260 -0
- package/lib/core/shared/utils/dot-analytics.utils.js +202 -0
- package/lib/react/components/DotContentAnalytics.d.ts +1 -1
- package/lib/react/hook/useContentAnalytics.d.ts +43 -15
- package/lib/react/hook/useContentAnalytics.js +18 -21
- package/lib/react/hook/useRouterTracker.d.ts +1 -1
- package/lib/react/hook/useRouterTracker.js +4 -4
- package/lib/react/internal/utils.d.ts +1 -1
- package/lib/react/internal/utils.js +3 -3
- package/lib/react/public-api.d.ts +1 -1
- package/lib/standalone.d.ts +2 -2
- package/package.json +7 -5
- package/uve/src/internal/constants.js +8 -3
- package/lib/core/dot-content-analytics.js +0 -43
- package/lib/core/plugin/dot-analytics.plugin.d.ts +0 -32
- package/lib/core/plugin/dot-analytics.plugin.js +0 -79
- package/lib/core/shared/dot-content-analytics.activity-tracker.d.ts +0 -28
- package/lib/core/shared/dot-content-analytics.constants.d.ts +0 -37
- package/lib/core/shared/dot-content-analytics.constants.js +0 -14
- package/lib/core/shared/dot-content-analytics.http.d.ts +0 -8
- package/lib/core/shared/dot-content-analytics.http.js +0 -29
- package/lib/core/shared/dot-content-analytics.model.d.ts +0 -351
- package/lib/core/shared/dot-content-analytics.utils.d.ts +0 -111
- package/lib/core/shared/dot-content-analytics.utils.js +0 -123
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
import { AnalyticsPlugin, PageData } from 'analytics';
|
|
2
|
+
import { DotCMSPredefinedEventType } from '../constants';
|
|
3
|
+
import { DotLogger, LogLevel } from '../dot-analytics.logger';
|
|
4
|
+
import { AnalyticsBasePayloadWithContext, ContentletData, DotCMSAnalyticsConfig, DotCMSAnalyticsEventContext, DotCMSBrowserData, DotCMSEventDeviceData, DotCMSEventUtmData, EnrichedAnalyticsPayload } from '../models';
|
|
5
|
+
export { cleanupActivityTracking, initializeActivityTracking, updateSessionActivity } from '../../plugin/identity/dot-analytics.identity.activity-tracker';
|
|
6
|
+
/**
|
|
7
|
+
* Type guard to check if an event is a predefined event type.
|
|
8
|
+
* Enables TypeScript type narrowing for better type safety.
|
|
9
|
+
*
|
|
10
|
+
* @param event - Event name to check
|
|
11
|
+
* @returns True if event is a predefined type, false for custom events
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```typescript
|
|
15
|
+
* if (isPredefinedEventType(eventName)) {
|
|
16
|
+
* // TypeScript knows eventName is DotCMSPredefinedEventType here
|
|
17
|
+
* console.log('Predefined event:', eventName);
|
|
18
|
+
* } else {
|
|
19
|
+
* // TypeScript knows eventName is string (custom) here
|
|
20
|
+
* console.log('Custom event:', eventName);
|
|
21
|
+
* }
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
export declare function isPredefinedEventType(event: string): event is DotCMSPredefinedEventType;
|
|
25
|
+
/**
|
|
26
|
+
* Validates required configuration fields for Analytics initialization.
|
|
27
|
+
*
|
|
28
|
+
* @param config - The analytics configuration to validate
|
|
29
|
+
* @returns Array of missing field names, or null if all required fields are present
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```ts
|
|
33
|
+
* const missing = validateAnalyticsConfig(config);
|
|
34
|
+
* if (missing) {
|
|
35
|
+
* console.error(`Missing: ${missing.join(' and ')}`);
|
|
36
|
+
* }
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
export declare function validateAnalyticsConfig(config: DotCMSAnalyticsConfig): string[] | null;
|
|
40
|
+
/**
|
|
41
|
+
* Generates a cryptographically secure random ID.
|
|
42
|
+
* @internal This function is for internal use only and should not be used outside of the SDK.
|
|
43
|
+
* @param prefix - The prefix for the generated ID
|
|
44
|
+
* @returns A unique ID string with the given prefix
|
|
45
|
+
*/
|
|
46
|
+
export declare const generateSecureId: (prefix: string) => string;
|
|
47
|
+
/**
|
|
48
|
+
* Safe sessionStorage wrapper with error handling
|
|
49
|
+
*/
|
|
50
|
+
export declare const safeSessionStorage: {
|
|
51
|
+
getItem: (key: string) => string | null;
|
|
52
|
+
setItem: (key: string, value: string) => void;
|
|
53
|
+
};
|
|
54
|
+
/**
|
|
55
|
+
* Gets or generates a user ID from localStorage.
|
|
56
|
+
* @internal This function is for internal use only.
|
|
57
|
+
* @returns The user ID string
|
|
58
|
+
*/
|
|
59
|
+
export declare const getUserId: () => string;
|
|
60
|
+
/**
|
|
61
|
+
* Gets session ID with comprehensive lifecycle management.
|
|
62
|
+
* Returns existing valid session ID or creates a new one if needed.
|
|
63
|
+
* @internal This function is for internal use only.
|
|
64
|
+
*
|
|
65
|
+
* Session validation criteria:
|
|
66
|
+
* 1. User is still active (< 30 min inactivity)
|
|
67
|
+
* 2. Session hasn't passed midnight (UTC)
|
|
68
|
+
*
|
|
69
|
+
* @returns The session ID string
|
|
70
|
+
*/
|
|
71
|
+
export declare const getSessionId: () => string;
|
|
72
|
+
/**
|
|
73
|
+
* Gets analytics context with user and session identification.
|
|
74
|
+
* Used by the identity plugin to inject context into analytics events.
|
|
75
|
+
*
|
|
76
|
+
* @param config - The analytics configuration object
|
|
77
|
+
* @returns The analytics context with site_key, session_id, and user_id
|
|
78
|
+
*/
|
|
79
|
+
export declare const getAnalyticsContext: (config: DotCMSAnalyticsConfig) => DotCMSAnalyticsEventContext;
|
|
80
|
+
/**
|
|
81
|
+
* Configuration result with warnings for analytics setup
|
|
82
|
+
*/
|
|
83
|
+
export interface AnalyticsConfigResult {
|
|
84
|
+
config: DotCMSAnalyticsConfig;
|
|
85
|
+
warnings?: string[];
|
|
86
|
+
missingAttributes?: string[];
|
|
87
|
+
hasIssues: boolean;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Gets analytics configuration from script tag attributes.
|
|
91
|
+
* Always returns a config (with defaults if needed).
|
|
92
|
+
*
|
|
93
|
+
* - If no data-analytics-server attribute is found, uses the current domain as the server endpoint
|
|
94
|
+
* - Both debug and autoPageView default to false (must be explicitly set to "true")
|
|
95
|
+
*
|
|
96
|
+
* @returns The analytics configuration object
|
|
97
|
+
*/
|
|
98
|
+
export declare const getAnalyticsConfig: () => DotCMSAnalyticsConfig;
|
|
99
|
+
/**
|
|
100
|
+
* Gets current device data for analytics.
|
|
101
|
+
* Combines static browser data with dynamic viewport information.
|
|
102
|
+
* Used by the identity plugin to inject device data into context.
|
|
103
|
+
*
|
|
104
|
+
* @returns Device data with screen resolution, language, and viewport dimensions
|
|
105
|
+
*/
|
|
106
|
+
export declare const getDeviceDataForContext: () => DotCMSEventDeviceData;
|
|
107
|
+
/**
|
|
108
|
+
* Retrieves the browser event data - optimized but accurate.
|
|
109
|
+
* @internal This function is for internal use only.
|
|
110
|
+
* @param location - The Location object to extract data from
|
|
111
|
+
* @returns Browser event data with all relevant information
|
|
112
|
+
*/
|
|
113
|
+
export declare const getBrowserEventData: (location: Location) => DotCMSBrowserData;
|
|
114
|
+
/**
|
|
115
|
+
* Extracts and transforms UTM parameters from the URL - cached for performance.
|
|
116
|
+
* Returns UTM data in DotCMS format (without 'utm_' prefix).
|
|
117
|
+
* @internal This function is for internal use only.
|
|
118
|
+
* @param location - The Location object to extract UTM parameters from
|
|
119
|
+
* @returns DotCMSEventUtmData object with transformed UTM parameters (source, medium, campaign, etc.)
|
|
120
|
+
*/
|
|
121
|
+
export declare const extractUTMParameters: (location: Location) => DotCMSEventUtmData;
|
|
122
|
+
/**
|
|
123
|
+
* Default redirect function.
|
|
124
|
+
* @internal This function is for internal use only.
|
|
125
|
+
* @param href - The URL to redirect to
|
|
126
|
+
*/
|
|
127
|
+
export declare const defaultRedirectFn: (href: string) => string;
|
|
128
|
+
/**
|
|
129
|
+
* Gets local time in ISO format without milliseconds.
|
|
130
|
+
* Used by enricher plugins to add local_time to events.
|
|
131
|
+
*
|
|
132
|
+
* @returns Local time string in ISO 8601 format with timezone offset (e.g., "2024-01-01T12:00:00-05:00")
|
|
133
|
+
*/
|
|
134
|
+
export declare const getLocalTime: () => string;
|
|
135
|
+
/**
|
|
136
|
+
* Gets page data from browser event data and payload.
|
|
137
|
+
* @internal This function is for internal use only.
|
|
138
|
+
* @param browserData - Browser event data
|
|
139
|
+
* @param payload - Payload with properties
|
|
140
|
+
* @returns PageData object for Analytics.js
|
|
141
|
+
*/
|
|
142
|
+
export declare const getPageData: (browserData: DotCMSBrowserData, payload: {
|
|
143
|
+
properties: Record<string, unknown>;
|
|
144
|
+
}) => PageData;
|
|
145
|
+
/**
|
|
146
|
+
* Gets device data from browser event data.
|
|
147
|
+
* @internal This function is for internal use only.
|
|
148
|
+
* @param browserData - Browser event data
|
|
149
|
+
* @returns Device data with screen resolution, language, and viewport dimensions
|
|
150
|
+
*/
|
|
151
|
+
export declare const getDeviceData: (browserData: DotCMSBrowserData) => DotCMSEventDeviceData;
|
|
152
|
+
/**
|
|
153
|
+
* Gets UTM data from browser event data.
|
|
154
|
+
* @internal This function is for internal use only.
|
|
155
|
+
* @param browserData - Browser event data
|
|
156
|
+
* @returns UTM data with source, medium, campaign, etc.
|
|
157
|
+
*/
|
|
158
|
+
export declare const getUtmData: (browserData: DotCMSBrowserData) => DotCMSEventUtmData;
|
|
159
|
+
/**
|
|
160
|
+
* Enriches payload with UTM data.
|
|
161
|
+
* @internal This function is for internal use only.
|
|
162
|
+
* @param payload - The payload to enrich
|
|
163
|
+
* @returns The payload with UTM data added
|
|
164
|
+
*/
|
|
165
|
+
export declare const enrichWithUtmData: <T extends Record<string, unknown>>(payload: T) => T;
|
|
166
|
+
/**
|
|
167
|
+
* Optimized payload enrichment using existing analytics.js data.
|
|
168
|
+
* Filters out Analytics.js default properties and only keeps user-provided properties in custom.
|
|
169
|
+
* Used by the enricher plugin to transform Analytics.js payload into DotCMS event format.
|
|
170
|
+
*
|
|
171
|
+
* @param payload - The Analytics.js payload with context already injected by identity plugin
|
|
172
|
+
* @param location - The Location object to extract page data from (defaults to window.location)
|
|
173
|
+
* @returns Enriched payload with page, UTM, custom data, and local_time (device is in context)
|
|
174
|
+
*/
|
|
175
|
+
export declare const enrichPagePayloadOptimized: (payload: AnalyticsBasePayloadWithContext, location?: Location) => EnrichedAnalyticsPayload;
|
|
176
|
+
/**
|
|
177
|
+
* Legacy function that enriches page payload with all data in one call.
|
|
178
|
+
* @internal This function is for internal use only.
|
|
179
|
+
* @param payload - The payload to enrich
|
|
180
|
+
* @param location - The Location object to extract data from
|
|
181
|
+
* @returns Object with enriched payload
|
|
182
|
+
*/
|
|
183
|
+
export declare const enrichPagePayload: (payload: {
|
|
184
|
+
properties: Record<string, unknown>;
|
|
185
|
+
} & Record<string, unknown>, location?: Location) => {
|
|
186
|
+
payload: {
|
|
187
|
+
local_time: string;
|
|
188
|
+
utm?: DotCMSEventUtmData | undefined;
|
|
189
|
+
page: PageData;
|
|
190
|
+
device: DotCMSEventDeviceData;
|
|
191
|
+
properties: Record<string, unknown>;
|
|
192
|
+
};
|
|
193
|
+
};
|
|
194
|
+
/**
|
|
195
|
+
* Creates a throttled version of a callback function
|
|
196
|
+
* Ensures the callback is executed at most once every `limitMs` milliseconds
|
|
197
|
+
* @param callback - The function to throttle
|
|
198
|
+
* @param limitMs - The time limit in milliseconds
|
|
199
|
+
* @returns A throttled function
|
|
200
|
+
*/
|
|
201
|
+
export declare function createThrottle<T extends (...args: unknown[]) => void>(callback: T, limitMs: number): (...args: Parameters<T>) => void;
|
|
202
|
+
/**
|
|
203
|
+
* Extracts the contentlet identifier from a DOM element
|
|
204
|
+
* @param element - The HTML element containing data attributes
|
|
205
|
+
* @returns The contentlet identifier or null if not found
|
|
206
|
+
*/
|
|
207
|
+
export declare function extractContentletIdentifier(element: HTMLElement): string | null;
|
|
208
|
+
/**
|
|
209
|
+
* Extracts all contentlet data from a DOM element's data attributes
|
|
210
|
+
* @param element - The HTML element containing data attributes
|
|
211
|
+
* @returns Complete contentlet data object
|
|
212
|
+
*/
|
|
213
|
+
export declare function extractContentletData(element: HTMLElement): ContentletData;
|
|
214
|
+
/**
|
|
215
|
+
* Initial scan delay for DOM readiness
|
|
216
|
+
* Allows React/Next.js to finish rendering before scanning for contentlets
|
|
217
|
+
*/
|
|
218
|
+
export declare const INITIAL_SCAN_DELAY_MS = 100;
|
|
219
|
+
/**
|
|
220
|
+
* Checks if code is running in a browser environment
|
|
221
|
+
* @returns true if window and document are available
|
|
222
|
+
*/
|
|
223
|
+
export declare const isBrowser: () => boolean;
|
|
224
|
+
/**
|
|
225
|
+
* Finds all contentlet elements in the DOM
|
|
226
|
+
* @returns Array of contentlet HTMLElements
|
|
227
|
+
*/
|
|
228
|
+
export declare const findContentlets: () => HTMLElement[];
|
|
229
|
+
/**
|
|
230
|
+
* Creates a MutationObserver that watches for contentlet changes in the DOM
|
|
231
|
+
* @param callback - Function to call when mutations are detected
|
|
232
|
+
* @param debounceMs - Debounce time in milliseconds (default: 250ms)
|
|
233
|
+
* @returns Configured and active MutationObserver
|
|
234
|
+
*/
|
|
235
|
+
export declare const createContentletObserver: (callback: () => void, debounceMs?: number) => MutationObserver;
|
|
236
|
+
/**
|
|
237
|
+
* Sets up cleanup handlers for page unload events
|
|
238
|
+
* Registers cleanup function to both 'beforeunload' and 'pagehide' for maximum compatibility
|
|
239
|
+
* @param cleanup - Function to call on page unload
|
|
240
|
+
*/
|
|
241
|
+
export declare const setupPluginCleanup: (cleanup: () => void) => void;
|
|
242
|
+
/**
|
|
243
|
+
* Creates a logger with plugin-specific prefix and configurable log level
|
|
244
|
+
* @param pluginName - Name of the plugin (e.g., 'Click', 'Impression')
|
|
245
|
+
* @param config - Analytics configuration with debug flag and optional logLevel
|
|
246
|
+
* @returns DotLogger instance with configured log level
|
|
247
|
+
*/
|
|
248
|
+
export declare const createPluginLogger: (pluginName: string, config: {
|
|
249
|
+
debug: boolean;
|
|
250
|
+
logLevel?: LogLevel;
|
|
251
|
+
}) => DotLogger;
|
|
252
|
+
/**
|
|
253
|
+
* Gets enhanced tracking plugins based on configuration
|
|
254
|
+
* Returns content impression and click tracking plugins if enabled
|
|
255
|
+
* @param config - Analytics configuration
|
|
256
|
+
* @param impressionPlugin - Impression tracking plugin factory
|
|
257
|
+
* @param clickPlugin - Click tracking plugin factory
|
|
258
|
+
* @returns Array of enabled tracking plugins
|
|
259
|
+
*/
|
|
260
|
+
export declare const getEnhancedTrackingPlugins: (config: DotCMSAnalyticsConfig, impressionPlugin: (config: DotCMSAnalyticsConfig) => AnalyticsPlugin, clickPlugin: (config: DotCMSAnalyticsConfig) => AnalyticsPlugin) => AnalyticsPlugin[];
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import { ANALYTICS_JS_DEFAULT_PROPERTIES as T, SESSION_STORAGE_KEY as h, DEFAULT_SESSION_TIMEOUT_MINUTES as y, USER_ID_KEY as w, DEFAULT_IMPRESSION_MUTATION_OBSERVER_DEBOUNCE_MS as I, EXPECTED_UTM_KEYS as D, ANALYTICS_CONTENTLET_CLASS as S } from "../constants/dot-analytics.constants.js";
|
|
2
|
+
import { DotLogger as E } from "../dot-analytics.logger.js";
|
|
3
|
+
import "../../../../uve/src/internal/constants.js";
|
|
4
|
+
function Y(t) {
|
|
5
|
+
var n, s;
|
|
6
|
+
const e = [];
|
|
7
|
+
return (n = t.siteAuth) != null && n.trim() || e.push('"siteAuth"'), (s = t.server) != null && s.trim() || e.push('"server"'), e.length > 0 ? e : null;
|
|
8
|
+
}
|
|
9
|
+
let u = null, l = null;
|
|
10
|
+
const g = (t) => {
|
|
11
|
+
const e = Date.now(), n = Math.random().toString(36).substr(2, 9), s = Math.random().toString(36).substr(2, 9);
|
|
12
|
+
return `${t}_${e}_${n}${s}`;
|
|
13
|
+
}, _ = {
|
|
14
|
+
getItem: (t) => {
|
|
15
|
+
try {
|
|
16
|
+
return localStorage.getItem(t);
|
|
17
|
+
} catch {
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
setItem: (t, e) => {
|
|
22
|
+
try {
|
|
23
|
+
localStorage.setItem(t, e);
|
|
24
|
+
} catch {
|
|
25
|
+
console.warn(`DotCMS Analytics [Core]: Could not save ${t} to localStorage`);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}, A = () => {
|
|
29
|
+
let t = _.getItem(w);
|
|
30
|
+
return t || (t = g("user"), _.setItem(w, t)), t;
|
|
31
|
+
}, C = (t) => {
|
|
32
|
+
const e = new Date(t), n = /* @__PURE__ */ new Date(), s = new Date(
|
|
33
|
+
e.getUTCFullYear(),
|
|
34
|
+
e.getUTCMonth(),
|
|
35
|
+
e.getUTCDate()
|
|
36
|
+
), r = new Date(n.getUTCFullYear(), n.getUTCMonth(), n.getUTCDate());
|
|
37
|
+
return s.getTime() !== r.getTime();
|
|
38
|
+
}, v = () => {
|
|
39
|
+
const t = Date.now();
|
|
40
|
+
if (typeof window > "u")
|
|
41
|
+
return g("session_fallback");
|
|
42
|
+
try {
|
|
43
|
+
const e = sessionStorage.getItem(h);
|
|
44
|
+
if (e) {
|
|
45
|
+
const { sessionId: r, startTime: o, lastActivity: a } = JSON.parse(e), i = !C(o), c = t - a < y * 60 * 1e3;
|
|
46
|
+
if (i && c)
|
|
47
|
+
return sessionStorage.setItem(
|
|
48
|
+
h,
|
|
49
|
+
JSON.stringify({
|
|
50
|
+
sessionId: r,
|
|
51
|
+
startTime: o,
|
|
52
|
+
lastActivity: t
|
|
53
|
+
})
|
|
54
|
+
), r;
|
|
55
|
+
}
|
|
56
|
+
const n = g("session"), s = {
|
|
57
|
+
sessionId: n,
|
|
58
|
+
startTime: t,
|
|
59
|
+
lastActivity: t
|
|
60
|
+
};
|
|
61
|
+
return sessionStorage.setItem(h, JSON.stringify(s)), n;
|
|
62
|
+
} catch {
|
|
63
|
+
return g("session_fallback");
|
|
64
|
+
}
|
|
65
|
+
}, x = (t) => {
|
|
66
|
+
const e = v(), n = A(), s = O();
|
|
67
|
+
return {
|
|
68
|
+
site_auth: t.siteAuth,
|
|
69
|
+
session_id: e,
|
|
70
|
+
user_id: n,
|
|
71
|
+
device: s
|
|
72
|
+
};
|
|
73
|
+
}, p = () => u || (u = {
|
|
74
|
+
user_language: navigator.language,
|
|
75
|
+
doc_encoding: document.characterSet || document.charset,
|
|
76
|
+
screen_resolution: typeof screen < "u" && screen.width && screen.height ? `${screen.width}x${screen.height}` : ""
|
|
77
|
+
}, u), O = () => {
|
|
78
|
+
const t = p(), e = window.innerWidth || document.documentElement.clientWidth || 0, n = window.innerHeight || document.documentElement.clientHeight || 0;
|
|
79
|
+
return {
|
|
80
|
+
screen_resolution: t.screen_resolution ?? "",
|
|
81
|
+
language: t.user_language ?? "",
|
|
82
|
+
viewport_width: String(e),
|
|
83
|
+
viewport_height: String(n)
|
|
84
|
+
};
|
|
85
|
+
}, N = (t) => {
|
|
86
|
+
const e = t.search;
|
|
87
|
+
if (l && l.search === e)
|
|
88
|
+
return l.params;
|
|
89
|
+
const n = new URLSearchParams(e), s = {};
|
|
90
|
+
return D.forEach((r) => {
|
|
91
|
+
const o = n.get(r);
|
|
92
|
+
if (o) {
|
|
93
|
+
const a = r.replace("utm_", "");
|
|
94
|
+
s[a] = o;
|
|
95
|
+
}
|
|
96
|
+
}), l = { search: e, params: s }, s;
|
|
97
|
+
}, b = () => {
|
|
98
|
+
try {
|
|
99
|
+
const t = (/* @__PURE__ */ new Date()).getTimezoneOffset(), e = t > 0 ? "-" : "+", n = Math.abs(t), s = Math.floor(n / 60), r = n % 60;
|
|
100
|
+
return `${e}${s.toString().padStart(2, "0")}:${r.toString().padStart(2, "0")}`;
|
|
101
|
+
} catch {
|
|
102
|
+
return "+00:00";
|
|
103
|
+
}
|
|
104
|
+
}, M = () => {
|
|
105
|
+
try {
|
|
106
|
+
const t = /* @__PURE__ */ new Date(), e = b(), n = t.getFullYear(), s = (t.getMonth() + 1).toString().padStart(2, "0"), r = t.getDate().toString().padStart(2, "0"), o = t.getHours().toString().padStart(2, "0"), a = t.getMinutes().toString().padStart(2, "0"), i = t.getSeconds().toString().padStart(2, "0");
|
|
107
|
+
return `${n}-${s}-${r}T${o}:${a}:${i}${e}`;
|
|
108
|
+
} catch {
|
|
109
|
+
return (/* @__PURE__ */ new Date()).toISOString();
|
|
110
|
+
}
|
|
111
|
+
}, B = (t, e = typeof window < "u" ? window.location : {}) => {
|
|
112
|
+
const n = M(), s = p(), { properties: r } = t, o = {};
|
|
113
|
+
Object.keys(r).forEach((c) => {
|
|
114
|
+
T.includes(c) || (o[c] = r[c]);
|
|
115
|
+
});
|
|
116
|
+
const a = {
|
|
117
|
+
url: e.href,
|
|
118
|
+
doc_encoding: s.doc_encoding,
|
|
119
|
+
doc_hash: e.hash,
|
|
120
|
+
doc_protocol: e.protocol,
|
|
121
|
+
doc_search: e.search,
|
|
122
|
+
doc_host: e.hostname,
|
|
123
|
+
doc_path: e.pathname,
|
|
124
|
+
title: r.title ?? (document == null ? void 0 : document.title)
|
|
125
|
+
}, i = N(e);
|
|
126
|
+
return {
|
|
127
|
+
...t,
|
|
128
|
+
page: a,
|
|
129
|
+
...Object.keys(i).length > 0 && { utm: i },
|
|
130
|
+
// Only include custom if there are user-provided properties
|
|
131
|
+
...Object.keys(o).length > 0 && { custom: o },
|
|
132
|
+
local_time: n
|
|
133
|
+
};
|
|
134
|
+
};
|
|
135
|
+
function L(t, e) {
|
|
136
|
+
let n = 0;
|
|
137
|
+
return (...s) => {
|
|
138
|
+
const r = Date.now();
|
|
139
|
+
r - n >= e && (t(...s), n = r);
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
function F(t) {
|
|
143
|
+
return t.dataset.dotAnalyticsIdentifier || null;
|
|
144
|
+
}
|
|
145
|
+
function k(t) {
|
|
146
|
+
return {
|
|
147
|
+
identifier: t.dataset.dotAnalyticsIdentifier || "",
|
|
148
|
+
inode: t.dataset.dotAnalyticsInode || "",
|
|
149
|
+
contentType: t.dataset.dotAnalyticsContenttype || "",
|
|
150
|
+
title: t.dataset.dotAnalyticsTitle || "",
|
|
151
|
+
baseType: t.dataset.dotAnalyticsBasetype || ""
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
const z = 100, U = () => typeof window < "u" && typeof document < "u", H = () => Array.from(document.querySelectorAll(`.${S}`)), J = (t, e = I) => {
|
|
155
|
+
const n = L(t, e), s = new MutationObserver((r) => {
|
|
156
|
+
r.some((a) => a.addedNodes.length === 0 && a.removedNodes.length === 0 ? !1 : [
|
|
157
|
+
...Array.from(a.addedNodes),
|
|
158
|
+
...Array.from(a.removedNodes)
|
|
159
|
+
].some((c) => {
|
|
160
|
+
var f, m;
|
|
161
|
+
if (c.nodeType !== Node.ELEMENT_NODE)
|
|
162
|
+
return !1;
|
|
163
|
+
const d = c;
|
|
164
|
+
return (f = d.classList) != null && f.contains(S) ? !0 : ((m = d.querySelector) == null ? void 0 : m.call(d, `.${S}`)) !== null;
|
|
165
|
+
})) && n();
|
|
166
|
+
});
|
|
167
|
+
return s.observe(document.body, {
|
|
168
|
+
childList: !0,
|
|
169
|
+
subtree: !0,
|
|
170
|
+
attributes: !1,
|
|
171
|
+
characterData: !1
|
|
172
|
+
}), s;
|
|
173
|
+
}, K = (t) => {
|
|
174
|
+
U() && (window.addEventListener("beforeunload", t), window.addEventListener("pagehide", t));
|
|
175
|
+
}, j = (t, e) => {
|
|
176
|
+
const n = e.logLevel ?? (e.debug ? "debug" : "warn");
|
|
177
|
+
return new E("Analytics", t, n);
|
|
178
|
+
}, W = (t, e, n) => [
|
|
179
|
+
t.impressions && e(t),
|
|
180
|
+
t.clicks && n(t)
|
|
181
|
+
].filter(Boolean);
|
|
182
|
+
export {
|
|
183
|
+
z as INITIAL_SCAN_DELAY_MS,
|
|
184
|
+
J as createContentletObserver,
|
|
185
|
+
j as createPluginLogger,
|
|
186
|
+
L as createThrottle,
|
|
187
|
+
B as enrichPagePayloadOptimized,
|
|
188
|
+
k as extractContentletData,
|
|
189
|
+
F as extractContentletIdentifier,
|
|
190
|
+
N as extractUTMParameters,
|
|
191
|
+
H as findContentlets,
|
|
192
|
+
g as generateSecureId,
|
|
193
|
+
x as getAnalyticsContext,
|
|
194
|
+
O as getDeviceDataForContext,
|
|
195
|
+
W as getEnhancedTrackingPlugins,
|
|
196
|
+
M as getLocalTime,
|
|
197
|
+
v as getSessionId,
|
|
198
|
+
A as getUserId,
|
|
199
|
+
U as isBrowser,
|
|
200
|
+
K as setupPluginCleanup,
|
|
201
|
+
Y as validateAnalyticsConfig
|
|
202
|
+
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ReactElement } from 'react';
|
|
2
|
-
import { DotCMSAnalyticsConfig } from '../../core/shared/
|
|
2
|
+
import { DotCMSAnalyticsConfig } from '../../core/shared/models';
|
|
3
3
|
/**
|
|
4
4
|
* Client bootstrapper for dotCMS Analytics in React/Next.
|
|
5
5
|
* - No UI: initializes the analytics singleton from props or env config.
|
|
@@ -1,29 +1,57 @@
|
|
|
1
|
-
import { DotCMSAnalytics, DotCMSAnalyticsConfig } from '../../core/shared/
|
|
1
|
+
import { DotCMSAnalytics, DotCMSAnalyticsConfig } from '../../core/shared/models';
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
3
|
+
* React hook for tracking user interactions and page views in your DotCMS application.
|
|
4
|
+
*
|
|
5
|
+
* Use this hook to add analytics tracking to your React components. It automatically
|
|
6
|
+
* handles user sessions, device information, and UTM campaign parameters.
|
|
7
|
+
*
|
|
8
|
+
* **Important:** Tracking is automatically disabled when editing content in DotCMS to avoid
|
|
9
|
+
* polluting your analytics data with editor activity.
|
|
6
10
|
*
|
|
7
11
|
* @example
|
|
12
|
+
* Basic usage - Track custom events
|
|
8
13
|
* ```tsx
|
|
9
|
-
* function
|
|
14
|
+
* function ProductCard({ title, price }) {
|
|
10
15
|
* const { track } = useContentAnalytics({
|
|
11
16
|
* server: 'https://demo.dotcms.com',
|
|
12
|
-
*
|
|
17
|
+
* siteAuth: 'my-site-auth',
|
|
13
18
|
* debug: false
|
|
14
19
|
* });
|
|
15
20
|
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
21
|
+
* const handleAddToCart = () => {
|
|
22
|
+
* track('add-to-cart', {
|
|
23
|
+
* product: title,
|
|
24
|
+
* price: price
|
|
25
|
+
* });
|
|
26
|
+
* };
|
|
27
|
+
*
|
|
28
|
+
* return <button onClick={handleAddToCart}>Add to Cart</button>;
|
|
29
|
+
* }
|
|
30
|
+
* ```
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* Track page views manually
|
|
34
|
+
* ```tsx
|
|
35
|
+
* function ArticlePage({ article }) {
|
|
36
|
+
* const { pageView } = useContentAnalytics({
|
|
37
|
+
* server: 'https://demo.dotcms.com',
|
|
38
|
+
* siteKey: 'your-site-key'
|
|
39
|
+
* });
|
|
40
|
+
*
|
|
41
|
+
* useEffect(() => {
|
|
42
|
+
* pageView({
|
|
43
|
+
* category: article.category,
|
|
44
|
+
* author: article.author
|
|
45
|
+
* });
|
|
46
|
+
* }, [article.id]);
|
|
22
47
|
* }
|
|
23
48
|
* ```
|
|
24
49
|
*
|
|
25
|
-
* @param
|
|
26
|
-
* @
|
|
27
|
-
* @
|
|
50
|
+
* @param config - Configuration object with server URL and site key
|
|
51
|
+
* @param config.server - The URL of your DotCMS Analytics server
|
|
52
|
+
* @param config.siteKey - Your unique site key for authentication
|
|
53
|
+
* @param config.debug - Optional. Set to true to see analytics events in the console
|
|
54
|
+
* @returns Object with `track()` and `pageView()` methods for analytics tracking
|
|
55
|
+
* @throws {Error} If the configuration is invalid (missing server or siteKey)
|
|
28
56
|
*/
|
|
29
57
|
export declare const useContentAnalytics: (config: DotCMSAnalyticsConfig) => DotCMSAnalytics;
|
|
@@ -1,32 +1,29 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { getUVEState as
|
|
1
|
+
import { useMemo as n, useCallback as o } from "react";
|
|
2
|
+
import { getUVEState as u } from "../../../uve/src/lib/core/core.utils.js";
|
|
3
3
|
import "../../../uve/src/internal/constants.js";
|
|
4
|
-
import { initializeAnalytics as
|
|
5
|
-
const
|
|
6
|
-
const t =
|
|
4
|
+
import { initializeAnalytics as l } from "../internal/utils.js";
|
|
5
|
+
const h = (r) => {
|
|
6
|
+
const t = n(() => l(r), [r.server, r.siteAuth]), e = n(() => !!u(), []);
|
|
7
7
|
if (!t)
|
|
8
8
|
throw new Error(
|
|
9
|
-
"Failed to initialize
|
|
9
|
+
"DotCMS Analytics: Failed to initialize. Please verify the required configuration (server and siteAuth)."
|
|
10
10
|
);
|
|
11
|
-
const a =
|
|
12
|
-
(
|
|
13
|
-
|
|
14
|
-
...s,
|
|
15
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
16
|
-
});
|
|
11
|
+
const a = o(
|
|
12
|
+
(i, c = {}) => {
|
|
13
|
+
e || t.track(i, c);
|
|
17
14
|
},
|
|
18
|
-
[t]
|
|
19
|
-
),
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
15
|
+
[t, e]
|
|
16
|
+
), s = o(
|
|
17
|
+
(i = {}) => {
|
|
18
|
+
e || t.pageView(i);
|
|
19
|
+
},
|
|
20
|
+
[t, e]
|
|
21
|
+
);
|
|
25
22
|
return {
|
|
26
23
|
track: a,
|
|
27
|
-
pageView:
|
|
24
|
+
pageView: s
|
|
28
25
|
};
|
|
29
26
|
};
|
|
30
27
|
export {
|
|
31
|
-
|
|
28
|
+
h as useContentAnalytics
|
|
32
29
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { DotCMSAnalytics } from '../../core/shared/
|
|
1
|
+
import { DotCMSAnalytics } from '../../core/shared/models';
|
|
2
2
|
/**
|
|
3
3
|
* Tracks page views on route changes using Next.js App Router signals.
|
|
4
4
|
* - Fires a single pageView per unique path+search.
|
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
import { usePathname as u, useSearchParams as
|
|
2
|
-
import { useRef as
|
|
1
|
+
import { usePathname as u, useSearchParams as c } from "next/navigation";
|
|
2
|
+
import { useRef as p, useEffect as m } from "react";
|
|
3
3
|
import { getUVEState as s } from "../../../uve/src/lib/core/core.utils.js";
|
|
4
4
|
import "../../../uve/src/internal/constants.js";
|
|
5
5
|
const g = (e, t) => `${e}${t != null && t.toString() ? "?" + t.toString() : ""}`;
|
|
6
6
|
function A(e, t = !1) {
|
|
7
|
-
const o =
|
|
7
|
+
const o = p(null), n = u(), r = c();
|
|
8
8
|
m(() => {
|
|
9
9
|
if (!e) return;
|
|
10
10
|
const i = (f) => {
|
|
11
11
|
s() || f !== o.current && (o.current = f, e.pageView());
|
|
12
12
|
};
|
|
13
|
-
t && console.info("
|
|
13
|
+
t && console.info("DotCMS Analytics [React]: using Next.js App Router tracking"), i(g(n, r));
|
|
14
14
|
}, [e, n, r, t]);
|
|
15
15
|
}
|
|
16
16
|
export {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { DotCMSAnalytics, DotCMSAnalyticsConfig } from '../../core/shared/
|
|
1
|
+
import { DotCMSAnalytics, DotCMSAnalyticsConfig } from '../../core/shared/models';
|
|
2
2
|
/**
|
|
3
3
|
* Initializes analytics with explicit configuration.
|
|
4
4
|
* Resets singleton if config changes.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { initializeContentAnalytics as r } from "../../core/dot-
|
|
2
|
-
let
|
|
3
|
-
const s = (
|
|
1
|
+
import { initializeContentAnalytics as r } from "../../core/dot-analytics.content.js";
|
|
2
|
+
let t, i;
|
|
3
|
+
const s = (e) => (i && (i.server !== e.server || i.siteAuth !== e.siteAuth) && (t = void 0), t !== void 0 || (i = e, t = r(e)), t);
|
|
4
4
|
export {
|
|
5
5
|
s as initializeAnalytics
|
|
6
6
|
};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export type { DotCMSAnalyticsConfig } from '../core/shared/
|
|
1
|
+
export type { DotCMSAnalyticsConfig } from '../core/shared/models';
|
|
2
2
|
export { DotContentAnalytics } from './components/DotContentAnalytics';
|
|
3
3
|
export { useContentAnalytics } from './hook/useContentAnalytics';
|
package/lib/standalone.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { ANALYTICS_WINDOWS_KEY } from './core/shared/
|
|
2
|
-
import { DotCMSAnalytics } from './core/shared/
|
|
1
|
+
import { ANALYTICS_WINDOWS_KEY } from './core/shared/constants';
|
|
2
|
+
import { DotCMSAnalytics } from './core/shared/models';
|
|
3
3
|
declare global {
|
|
4
4
|
interface Window {
|
|
5
5
|
[ANALYTICS_WINDOWS_KEY]: DotCMSAnalytics | null;
|