@dotcms/analytics 1.1.1-next.6 → 1.1.1-next.8

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 CHANGED
@@ -426,14 +426,14 @@ Standalone attributes to verify:
426
426
  - Angular & Vue support
427
427
  - Realtime dashboard
428
428
 
429
- ## dotCMS Support
429
+ ## Support
430
430
 
431
431
  We offer multiple channels to get help with the dotCMS Analytics SDK:
432
432
 
433
- - **GitHub Issues**: For bug reports and feature requests, please [open an issue](https://github.com/dotCMS/core/issues/new/choose) in the GitHub repository.
434
- - **Community Forum**: Join our [community discussions](https://community.dotcms.com/) to ask questions and share solutions.
435
- - **Stack Overflow**: Use the tag `dotcms-analytics` when posting questions.
436
- - **Enterprise Support**: Enterprise customers can access premium support through the [dotCMS Support Portal](https://helpdesk.dotcms.com/support/).
433
+ - **GitHub Issues**: For bug reports and feature requests, please [open an issue](https://github.com/dotCMS/core/issues/new/choose) in the GitHub repository
434
+ - **Community Forum**: Join our [community discussions](https://community.dotcms.com/) to ask questions and share solutions
435
+ - **Stack Overflow**: Use the tag `dotcms-analytics` when posting questions
436
+ - **Enterprise Support**: Enterprise customers can access premium support through the [dotCMS Support Portal](https://helpdesk.dotcms.com/support/)
437
437
 
438
438
  When reporting issues, please include:
439
439
 
@@ -442,9 +442,9 @@ When reporting issues, please include:
442
442
  - Minimal reproduction steps
443
443
  - Expected vs. actual behavior
444
444
 
445
- ## How To Contribute
445
+ ## Contributing
446
446
 
447
- GitHub pull requests are the preferred method to contribute code to dotCMS. We welcome contributions to the DotCMS Analytics SDK! If you'd like to contribute, please follow these steps:
447
+ GitHub pull requests are the preferred method to contribute code to dotCMS. We welcome contributions to the dotCMS Analytics SDK! If you'd like to contribute, please follow these steps:
448
448
 
449
449
  1. Fork the repository [dotCMS/core](https://github.com/dotCMS/core)
450
450
  2. Create a feature branch (`git checkout -b feature/amazing-feature`)
@@ -454,7 +454,7 @@ GitHub pull requests are the preferred method to contribute code to dotCMS. We w
454
454
 
455
455
  Please ensure your code follows the existing style and includes appropriate tests.
456
456
 
457
- ## Licensing Information
457
+ ## Licensing
458
458
 
459
459
  dotCMS comes in multiple editions and as such is dual-licensed. The dotCMS Community Edition is licensed under the GPL 3.0 and is freely available for download, customization, and deployment for use within organizations of all stripes. dotCMS Enterprise Editions (EE) adds several enterprise features and is available via a supported, indemnified commercial license from dotCMS. For the differences between the editions, see [the feature page](http://www.dotcms.com/cms-platform/features).
460
460
 
@@ -1,4 +1,11 @@
1
+ import { ANALYTICS_WINDOWS_ACTIVE_KEY, ANALYTICS_WINDOWS_CLEANUP_KEY } from '../../../../uve/src/internal.ts';
1
2
  import { DotCMSAnalytics, DotCMSAnalyticsConfig } from './shared/models';
3
+ declare global {
4
+ interface Window {
5
+ [ANALYTICS_WINDOWS_ACTIVE_KEY]?: boolean;
6
+ [ANALYTICS_WINDOWS_CLEANUP_KEY]?: () => void;
7
+ }
8
+ }
2
9
  /**
3
10
  * Creates an analytics instance for content analytics tracking.
4
11
  *
@@ -1,33 +1,34 @@
1
- import { Analytics as o } from "analytics";
2
- import { dotAnalytics as s } from "./plugin/dot-analytics.plugin.js";
3
- import { dotAnalyticsEnricherPlugin as l } from "./plugin/enricher/dot-analytics.enricher.plugin.js";
4
- import { dotAnalyticsIdentityPlugin as u } from "./plugin/identity/dot-analytics.identity.plugin.js";
5
- import { cleanupActivityTracking as a } from "./shared/dot-content-analytics.activity-tracker.js";
6
- const f = (i) => {
7
- if (!i.siteAuth)
8
- return console.error('DotCMS Analytics: Missing "siteAuth" in configuration'), null;
9
- if (!i.server)
10
- return console.error('DotCMS Analytics: Missing "server" in configuration'), null;
11
- const t = o({
1
+ import { Analytics as a } from "analytics";
2
+ import { ANALYTICS_WINDOWS_ACTIVE_KEY as r, ANALYTICS_WINDOWS_CLEANUP_KEY as s } from "../../uve/src/internal/constants.js";
3
+ import { dotAnalytics as l } from "./plugin/dot-analytics.plugin.js";
4
+ import { dotAnalyticsEnricherPlugin as c } from "./plugin/enricher/dot-analytics.enricher.plugin.js";
5
+ import { dotAnalyticsIdentityPlugin as p } from "./plugin/identity/dot-analytics.identity.plugin.js";
6
+ import { validateAnalyticsConfig as m } from "./shared/dot-content-analytics.utils.js";
7
+ import { cleanupActivityTracking as u } from "./shared/dot-content-analytics.activity-tracker.js";
8
+ const I = (n) => {
9
+ const o = m(n);
10
+ if (o)
11
+ return console.error(`DotCMS Analytics: Missing ${o.join(" and ")} in configuration`), typeof window < "u" && (window[r] = !1), null;
12
+ const i = a({
12
13
  app: "dotAnalytics",
13
- debug: i.debug,
14
+ debug: n.debug,
14
15
  plugins: [
15
- u(i),
16
+ p(n),
16
17
  // Inject identity context (user_id, session_id, local_tz)
17
- l(),
18
+ c(),
18
19
  // Enrich and clean payload with page, device, utm data and custom data
19
- s(i)
20
+ l(n)
20
21
  // Send events to server
21
22
  ]
22
- }), r = () => a();
23
- return typeof window < "u" && (window.addEventListener("beforeunload", r), window.__dotAnalyticsCleanup = r), {
23
+ }), e = () => u();
24
+ return typeof window < "u" && (window.addEventListener("beforeunload", e), window[s] = e, window[r] = !0, window.dispatchEvent(new CustomEvent("dotcms:analytics:ready"))), {
24
25
  /**
25
26
  * Track a page view.
26
27
  * Session activity is automatically updated by the identity plugin.
27
28
  * @param payload - Optional custom data to include with the page view (any valid JSON object)
28
29
  */
29
- pageView: (n = {}) => {
30
- t == null || t.page(n);
30
+ pageView: (t = {}) => {
31
+ i == null || i.page(t);
31
32
  },
32
33
  /**
33
34
  * Track a custom event.
@@ -35,11 +36,11 @@ const f = (i) => {
35
36
  * @param eventName - The name of the event to track
36
37
  * @param payload - Custom data to include with the event (any valid JSON object)
37
38
  */
38
- track: (n, e = {}) => {
39
- t == null || t.track(n, e);
39
+ track: (t, d = {}) => {
40
+ i == null || i.track(t, d);
40
41
  }
41
42
  };
42
43
  };
43
44
  export {
44
- f as initializeContentAnalytics
45
+ I as initializeContentAnalytics
45
46
  };
@@ -1,4 +1,11 @@
1
+ import { ANALYTICS_WINDOWS_ACTIVE_KEY, ANALYTICS_WINDOWS_CLEANUP_KEY } from '../../../../../uve/src/internal.ts';
1
2
  import { DotCMSAnalyticsConfig } from './models';
3
+ declare global {
4
+ interface Window {
5
+ [ANALYTICS_WINDOWS_CLEANUP_KEY]?: () => void;
6
+ [ANALYTICS_WINDOWS_ACTIVE_KEY]?: boolean;
7
+ }
8
+ }
2
9
  /**
3
10
  * Updates session activity with throttling
4
11
  */
@@ -15,7 +22,7 @@ export declare const getSessionInfo: () => {
15
22
  */
16
23
  export declare const initializeActivityTracking: (config: DotCMSAnalyticsConfig) => void;
17
24
  /**
18
- * Cleans up activity tracking listeners
25
+ * Cleans up activity tracking listeners and resets analytics state
19
26
  */
20
27
  export declare const cleanupActivityTracking: () => void;
21
28
  /**
@@ -1,5 +1,6 @@
1
- import { DEFAULT_SESSION_TIMEOUT_MINUTES as c, ACTIVITY_EVENTS as r } from "./constants/dot-content-analytics.constants.js";
2
- class o {
1
+ import { ANALYTICS_WINDOWS_ACTIVE_KEY as o, ANALYTICS_WINDOWS_CLEANUP_KEY as r } from "../../../uve/src/internal/constants.js";
2
+ import { DEFAULT_SESSION_TIMEOUT_MINUTES as c, ACTIVITY_EVENTS as v } from "./constants/dot-content-analytics.constants.js";
3
+ class l {
3
4
  constructor() {
4
5
  this.activityListeners = [], this.lastActivityTime = Date.now(), this.inactivityTimer = null, this.isThrottled = !1, this.config = null, this.ACTIVITY_THROTTLE_MS = 1e3;
5
6
  }
@@ -44,7 +45,7 @@ class o {
44
45
  if (this.cleanup(), this.config = i, typeof window > "u")
45
46
  return;
46
47
  const s = () => this.updateSessionActivity();
47
- r.forEach((a) => {
48
+ v.forEach((a) => {
48
49
  window.addEventListener(a, s, { passive: !0 }), this.activityListeners.push(
49
50
  () => window.removeEventListener(a, s)
50
51
  );
@@ -72,15 +73,15 @@ class o {
72
73
  };
73
74
  }
74
75
  }
75
- const t = new o(), h = () => {
76
+ const t = new l(), u = () => {
76
77
  t.updateSessionActivity();
77
- }, l = (e) => {
78
+ }, d = (e) => {
78
79
  t.initialize(e);
79
- }, T = () => {
80
- t.cleanup();
80
+ }, y = () => {
81
+ t.cleanup(), typeof window < "u" && (window[o] = !1, window[r] = void 0, window.dispatchEvent(new CustomEvent("dotcms:analytics:cleanup")));
81
82
  };
82
83
  export {
83
- T as cleanupActivityTracking,
84
- l as initializeActivityTracking,
85
- h as updateSessionActivity
84
+ y as cleanupActivityTracking,
85
+ d as initializeActivityTracking,
86
+ u as updateSessionActivity
86
87
  };
@@ -1,6 +1,21 @@
1
1
  import { PageData } from 'analytics';
2
2
  import { AnalyticsBasePayloadWithContext, DotCMSAnalyticsConfig, DotCMSAnalyticsEventContext, DotCMSBrowserData, DotCMSEventDeviceData, DotCMSEventUtmData, EnrichedAnalyticsPayload } from './models';
3
3
  export { cleanupActivityTracking, getLastActivity, getSessionInfo, initializeActivityTracking, isUserInactive, updateSessionActivity } from './dot-content-analytics.activity-tracker';
4
+ /**
5
+ * Validates required configuration fields for Analytics initialization.
6
+ *
7
+ * @param config - The analytics configuration to validate
8
+ * @returns Array of missing field names, or null if all required fields are present
9
+ *
10
+ * @example
11
+ * ```ts
12
+ * const missing = validateAnalyticsConfig(config);
13
+ * if (missing) {
14
+ * console.error(`Missing: ${missing.join(' and ')}`);
15
+ * }
16
+ * ```
17
+ */
18
+ export declare function validateAnalyticsConfig(config: DotCMSAnalyticsConfig): string[] | null;
4
19
  /**
5
20
  * Generates a cryptographically secure random ID.
6
21
  * @internal This function is for internal use only and should not be used outside of the SDK.
@@ -1,9 +1,15 @@
1
- import { ANALYTICS_JS_DEFAULT_PROPERTIES as w, SESSION_STORAGE_KEY as h, DEFAULT_SESSION_TIMEOUT_MINUTES as _, USER_ID_KEY as l, EXPECTED_UTM_KEYS as f } from "./constants/dot-content-analytics.constants.js";
2
- let g = null, u = null;
1
+ import { ANALYTICS_JS_DEFAULT_PROPERTIES as f, SESSION_STORAGE_KEY as h, DEFAULT_SESSION_TIMEOUT_MINUTES as w, USER_ID_KEY as l, EXPECTED_UTM_KEYS as _ } from "./constants/dot-content-analytics.constants.js";
2
+ import "../../../uve/src/internal/constants.js";
3
+ function U(t) {
4
+ var n, s;
5
+ const e = [];
6
+ return (n = t.siteAuth) != null && n.trim() || e.push('"siteAuth"'), (s = t.server) != null && s.trim() || e.push('"server"'), e.length > 0 ? e : null;
7
+ }
8
+ let u = null, g = null;
3
9
  const d = (t) => {
4
10
  const e = Date.now(), n = Math.random().toString(36).substr(2, 9), s = Math.random().toString(36).substr(2, 9);
5
11
  return `${t}_${e}_${n}${s}`;
6
- }, S = {
12
+ }, m = {
7
13
  getItem: (t) => {
8
14
  try {
9
15
  return localStorage.getItem(t);
@@ -19,8 +25,8 @@ const d = (t) => {
19
25
  }
20
26
  }
21
27
  }, p = () => {
22
- let t = S.getItem(l);
23
- return t || (t = d("user"), S.setItem(l, t)), t;
28
+ let t = m.getItem(l);
29
+ return t || (t = d("user"), m.setItem(l, t)), t;
24
30
  }, D = (t) => {
25
31
  const e = new Date(t), n = /* @__PURE__ */ new Date(), s = new Date(
26
32
  e.getUTCFullYear(),
@@ -35,7 +41,7 @@ const d = (t) => {
35
41
  try {
36
42
  const e = sessionStorage.getItem(h);
37
43
  if (e) {
38
- const { sessionId: o, startTime: r, lastActivity: a } = JSON.parse(e), c = !D(r), i = t - a < _ * 60 * 1e3;
44
+ const { sessionId: o, startTime: r, lastActivity: a } = JSON.parse(e), c = !D(r), i = t - a < w * 60 * 1e3;
39
45
  if (c && i)
40
46
  return sessionStorage.setItem(
41
47
  h,
@@ -55,7 +61,7 @@ const d = (t) => {
55
61
  } catch {
56
62
  return d("session_fallback");
57
63
  }
58
- }, U = (t) => {
64
+ }, $ = (t) => {
59
65
  const e = T(), n = p(), s = I();
60
66
  return t.debug && console.warn("DotCMS Analytics Identity Context:", {
61
67
  sessionId: e,
@@ -66,12 +72,12 @@ const d = (t) => {
66
72
  user_id: n,
67
73
  device: s
68
74
  };
69
- }, m = () => g || (g = {
75
+ }, S = () => u || (u = {
70
76
  user_language: navigator.language,
71
77
  doc_encoding: document.characterSet || document.charset,
72
78
  screen_resolution: typeof screen < "u" && screen.width && screen.height ? `${screen.width}x${screen.height}` : ""
73
- }, g), I = () => {
74
- const t = m(), e = window.innerWidth || document.documentElement.clientWidth || 0, n = window.innerHeight || document.documentElement.clientHeight || 0;
79
+ }, u), I = () => {
80
+ const t = S(), e = window.innerWidth || document.documentElement.clientWidth || 0, n = window.innerHeight || document.documentElement.clientHeight || 0;
75
81
  return {
76
82
  screen_resolution: t.screen_resolution ?? "",
77
83
  language: t.user_language ?? "",
@@ -80,16 +86,16 @@ const d = (t) => {
80
86
  };
81
87
  }, y = (t) => {
82
88
  const e = t.search;
83
- if (u && u.search === e)
84
- return u.params;
89
+ if (g && g.search === e)
90
+ return g.params;
85
91
  const n = new URLSearchParams(e), s = {};
86
- return f.forEach((o) => {
92
+ return _.forEach((o) => {
87
93
  const r = n.get(o);
88
94
  if (r) {
89
95
  const a = o.replace("utm_", "");
90
96
  s[a] = r;
91
97
  }
92
- }), u = { search: e, params: s }, s;
98
+ }), g = { search: e, params: s }, s;
93
99
  }, E = () => {
94
100
  try {
95
101
  const t = (/* @__PURE__ */ new Date()).getTimezoneOffset(), e = t > 0 ? "-" : "+", n = Math.abs(t), s = Math.floor(n / 60), o = n % 60;
@@ -104,10 +110,10 @@ const d = (t) => {
104
110
  } catch {
105
111
  return (/* @__PURE__ */ new Date()).toISOString();
106
112
  }
107
- }, $ = (t, e = typeof window < "u" ? window.location : {}) => {
108
- const n = C(), s = m(), { properties: o } = t, r = {};
113
+ }, A = (t, e = typeof window < "u" ? window.location : {}) => {
114
+ const n = C(), s = S(), { properties: o } = t, r = {};
109
115
  Object.keys(o).forEach((i) => {
110
- w.includes(i) || (r[i] = o[i]);
116
+ f.includes(i) || (r[i] = o[i]);
111
117
  });
112
118
  const a = {
113
119
  url: e.href,
@@ -129,12 +135,13 @@ const d = (t) => {
129
135
  };
130
136
  };
131
137
  export {
132
- $ as enrichPagePayloadOptimized,
138
+ A as enrichPagePayloadOptimized,
133
139
  y as extractUTMParameters,
134
140
  d as generateSecureId,
135
- U as getAnalyticsContext,
141
+ $ as getAnalyticsContext,
136
142
  I as getDeviceDataForContext,
137
143
  C as getLocalTime,
138
144
  T as getSessionId,
139
- p as getUserId
145
+ p as getUserId,
146
+ U as validateAnalyticsConfig
140
147
  };
@@ -5,8 +5,3 @@ export * from './data.model';
5
5
  export * from './event.model';
6
6
  export * from './request.model';
7
7
  export * from './library.model';
8
- declare global {
9
- interface Window {
10
- __dotAnalyticsCleanup?: () => void;
11
- }
12
- }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dotcms/analytics",
3
- "version": "1.1.1-next.6",
3
+ "version": "1.1.1-next.8",
4
4
  "description": "Official JavaScript library for Content Analytics with DotCMS.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -1,3 +1,8 @@
1
- import { UVEEventType as n } from "../../../types/src/lib/editor/public.js";
2
- import { onContentletHovered as r, onIframeScroll as o, onRequestBounds as t, onPageReload as E, onContentChanges as u } from "./events.js";
3
- n.CONTENT_CHANGES + "", n.PAGE_RELOAD + "", n.REQUEST_BOUNDS + "", n.IFRAME_SCROLL + "", n.CONTENTLET_HOVERED + "";
1
+ import { UVEEventType as t } from "../../../types/src/lib/editor/public.js";
2
+ import { onContentletHovered as e, onIframeScroll as o, onRequestBounds as r, onPageReload as E, onContentChanges as _ } from "./events.js";
3
+ t.CONTENT_CHANGES + "", t.PAGE_RELOAD + "", t.REQUEST_BOUNDS + "", t.IFRAME_SCROLL + "", t.CONTENTLET_HOVERED + "";
4
+ const N = "__dotAnalyticsActive__", T = "__dotAnalyticsCleanup";
5
+ export {
6
+ N as ANALYTICS_WINDOWS_ACTIVE_KEY,
7
+ T as ANALYTICS_WINDOWS_CLEANUP_KEY
8
+ };