@tracelog/lib 0.3.0 → 0.4.0

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.
@@ -1,5 +1,5 @@
1
1
  var y = /* @__PURE__ */ ((r) => (r.Mobile = "mobile", r.Tablet = "tablet", r.Desktop = "desktop", r.Unknown = "unknown", r))(y || {});
2
- const ee = 15 * 60 * 1e3, Ze = 1e3, et = 1e4, Ue = 250, tt = 24, Ee = 500, ve = 3, rt = 5e3, xe = 1e4, nt = 10, ye = 5, Te = 500, Ie = 120, A = 1, st = 0, it = 1, z = 3e4, G = 864e5, _e = 120, we = 8 * 1024, Ae = 10, be = 10, Y = 255, T = 1e3, K = 100, Me = 3, _ = 2, at = 2e3, k = "data-tl", ot = [
2
+ const ee = 15 * 60 * 1e3, Ze = 1e3, et = 1e4, Ue = 250, tt = 24, Ee = 500, ve = 3, rt = 5e3, xe = 1e4, nt = 10, ye = 5, Te = 500, _e = 120, A = 1, st = 0, it = 1, z = 3e4, G = 864e5, Ie = 120, we = 8 * 1024, Ae = 10, be = 10, Y = 255, T = 1e3, K = 100, Me = 3, I = 2, at = 2e3, k = "data-tl", ot = [
3
3
  "button",
4
4
  "a",
5
5
  'input[type="button"]',
@@ -75,7 +75,7 @@ const ee = 15 * 60 * 1e3, Ze = 1e3, et = 1e4, Ue = 250, tt = 24, Ee = 500, ve =
75
75
  excludedUrlPaths: r.excludedUrlPaths ?? [],
76
76
  tags: r.tags ?? [],
77
77
  ipExcluded: r.ipExcluded ?? !1
78
- }), I = "tl", dt = (r) => r ? `${I}:${r}:uid` : `${I}:uid`, ht = (r) => r ? `${I}:${r}:queue` : `${I}:queue`, gt = (r) => r ? `${I}:${r}:session` : `${I}:session`, ft = (r) => r ? `${I}:${r}:broadcast` : `${I}:broadcast`, Fe = {
78
+ }), _ = "tl", dt = (r) => r ? `${_}:${r}:uid` : `${_}:uid`, ht = (r) => r ? `${_}:${r}:queue` : `${_}:queue`, gt = (r) => r ? `${_}:${r}:session` : `${_}:session`, ft = (r) => r ? `${_}:${r}:broadcast` : `${_}:broadcast`, Fe = {
79
79
  LCP: 4e3,
80
80
  FCP: 1800,
81
81
  CLS: 0.25,
@@ -224,7 +224,7 @@ const St = () => {
224
224
  const e = Math.random() * 16 | 0;
225
225
  return (r === "x" ? e : e & 3 | 8).toString(16);
226
226
  });
227
- var w = /* @__PURE__ */ ((r) => (r.Skip = "skip", r.Localhost = "localhost:", r))(w || {}), re = /* @__PURE__ */ ((r) => (r.EVENT = "event", r.QUEUE = "queue", r))(re || {}), d = /* @__PURE__ */ ((r) => (r.PAGE_VIEW = "page_view", r.CLICK = "click", r.SCROLL = "scroll", r.SESSION_START = "session_start", r.SESSION_END = "session_end", r.CUSTOM = "custom", r.WEB_VITALS = "web_vitals", r.ERROR = "error", r))(d || {}), x = /* @__PURE__ */ ((r) => (r.UP = "up", r.DOWN = "down", r))(x || {}), N = /* @__PURE__ */ ((r) => (r.JS_ERROR = "js_error", r.PROMISE_REJECTION = "promise_rejection", r.NETWORK_ERROR = "network_error", r))(N || {}), H = /* @__PURE__ */ ((r) => (r.QA = "qa", r.DEBUG = "debug", r))(H || {}), yt = /* @__PURE__ */ ((r) => (r.AND = "AND", r.OR = "OR", r))(yt || {}), Tt = /* @__PURE__ */ ((r) => (r.URL_MATCHES = "url_matches", r.ELEMENT_MATCHES = "element_matches", r.DEVICE_TYPE = "device_type", r.ELEMENT_TEXT = "element_text", r.ELEMENT_ATTRIBUTE = "element_attribute", r.UTM_SOURCE = "utm_source", r.UTM_MEDIUM = "utm_medium", r.UTM_CAMPAIGN = "utm_campaign", r))(Tt || {}), It = /* @__PURE__ */ ((r) => (r.EQUALS = "equals", r.CONTAINS = "contains", r.STARTS_WITH = "starts_with", r.ENDS_WITH = "ends_with", r.REGEX = "regex", r.GREATER_THAN = "greater_than", r.LESS_THAN = "less_than", r.EXISTS = "exists", r.NOT_EXISTS = "not_exists", r))(It || {});
227
+ var w = /* @__PURE__ */ ((r) => (r.Skip = "skip", r.Localhost = "localhost:", r))(w || {}), re = /* @__PURE__ */ ((r) => (r.EVENT = "event", r.QUEUE = "queue", r))(re || {}), d = /* @__PURE__ */ ((r) => (r.PAGE_VIEW = "page_view", r.CLICK = "click", r.SCROLL = "scroll", r.SESSION_START = "session_start", r.SESSION_END = "session_end", r.CUSTOM = "custom", r.WEB_VITALS = "web_vitals", r.ERROR = "error", r))(d || {}), x = /* @__PURE__ */ ((r) => (r.UP = "up", r.DOWN = "down", r))(x || {}), N = /* @__PURE__ */ ((r) => (r.JS_ERROR = "js_error", r.PROMISE_REJECTION = "promise_rejection", r.NETWORK_ERROR = "network_error", r))(N || {}), H = /* @__PURE__ */ ((r) => (r.QA = "qa", r.DEBUG = "debug", r))(H || {}), yt = /* @__PURE__ */ ((r) => (r.AND = "AND", r.OR = "OR", r))(yt || {}), Tt = /* @__PURE__ */ ((r) => (r.URL_MATCHES = "url_matches", r.ELEMENT_MATCHES = "element_matches", r.DEVICE_TYPE = "device_type", r.ELEMENT_TEXT = "element_text", r.ELEMENT_ATTRIBUTE = "element_attribute", r.UTM_SOURCE = "utm_source", r.UTM_MEDIUM = "utm_medium", r.UTM_CAMPAIGN = "utm_campaign", r))(Tt || {}), _t = /* @__PURE__ */ ((r) => (r.EQUALS = "equals", r.CONTAINS = "contains", r.STARTS_WITH = "starts_with", r.ENDS_WITH = "ends_with", r.REGEX = "regex", r.GREATER_THAN = "greater_than", r.LESS_THAN = "less_than", r.EXISTS = "exists", r.NOT_EXISTS = "not_exists", r))(_t || {});
228
228
  class O extends Error {
229
229
  constructor(e, t, n) {
230
230
  super(e), this.errorCode = t, this.layer = n, this.name = this.constructor.name, Error.captureStackTrace && Error.captureStackTrace(this, this.constructor);
@@ -240,7 +240,7 @@ class M extends O {
240
240
  super(e, "APP_CONFIG_INVALID", t);
241
241
  }
242
242
  }
243
- class _t extends O {
243
+ class It extends O {
244
244
  constructor(e, t = "config") {
245
245
  super(e, "SESSION_TIMEOUT_INVALID", t);
246
246
  }
@@ -270,7 +270,7 @@ const At = (r) => {
270
270
  provided: r.sessionTimeout,
271
271
  min: z,
272
272
  max: G
273
- }), new _t(p.INVALID_SESSION_TIMEOUT, "config");
273
+ }), new It(p.INVALID_SESSION_TIMEOUT, "config");
274
274
  if (r.globalMetadata !== void 0 && (typeof r.globalMetadata != "object" || r.globalMetadata === null))
275
275
  throw a.clientError("ConfigValidation", "Global metadata must be an object", {
276
276
  provided: r.globalMetadata,
@@ -545,9 +545,9 @@ const At = (r) => {
545
545
  } : r.length === 0 ? {
546
546
  valid: !1,
547
547
  error: "Event name cannot be empty"
548
- } : r.length > _e ? {
548
+ } : r.length > Ie ? {
549
549
  valid: !1,
550
- error: `Event name is too long (max ${_e} characters)`
550
+ error: `Event name is too long (max ${Ie} characters)`
551
551
  } : r.includes("<") || r.includes(">") || r.includes("&") ? {
552
552
  valid: !1,
553
553
  error: "Event name contains invalid characters"
@@ -1492,7 +1492,7 @@ class Yt extends f {
1492
1492
  this.visibilityChangeHandler || this.beforeUnloadHandler || (this.visibilityChangeHandler = () => {
1493
1493
  document.hidden ? this.clearSessionTimeout() : this.get("sessionId") && this.setupSessionTimeout();
1494
1494
  }, this.beforeUnloadHandler = () => {
1495
- this.eventManager.flushImmediatelySync();
1495
+ this.endSession("page_unload");
1496
1496
  }, document.addEventListener("visibilitychange", this.visibilityChangeHandler), window.addEventListener("beforeunload", this.beforeUnloadHandler));
1497
1497
  }
1498
1498
  cleanupLifecycleListeners() {
@@ -1765,22 +1765,33 @@ class Jt extends f {
1765
1765
  limitWarningLogged = !1;
1766
1766
  minDepthChange = ye;
1767
1767
  minIntervalMs = Te;
1768
- maxEventsPerSession = Ie;
1768
+ maxEventsPerSession = _e;
1769
1769
  constructor(e) {
1770
1770
  super(), this.eventManager = e;
1771
1771
  }
1772
1772
  startTracking() {
1773
1773
  this.limitWarningLogged = !1, this.applyConfigOverrides(), this.set("scrollEventCount", 0);
1774
- const e = this.get("config").scrollContainerSelectors, n = (Array.isArray(e) ? e : typeof e == "string" ? [e] : []).map((s) => this.safeQuerySelector(s)).filter((s) => s instanceof HTMLElement);
1775
- n.length === 0 && n.push(window);
1776
- for (const s of n)
1777
- this.setupScrollContainer(s);
1774
+ const e = this.get("config").scrollContainerSelectors, t = Array.isArray(e) ? e : typeof e == "string" ? [e] : [];
1775
+ t.length === 0 ? this.setupScrollContainer(window) : this.trySetupContainers(t, 0);
1778
1776
  }
1779
1777
  stopTracking() {
1780
1778
  for (const e of this.containers)
1781
1779
  this.clearContainerTimer(e), e.element instanceof Window ? window.removeEventListener("scroll", e.listener) : e.element.removeEventListener("scroll", e.listener);
1782
1780
  this.containers.length = 0, this.set("scrollEventCount", 0), this.limitWarningLogged = !1;
1783
1781
  }
1782
+ trySetupContainers(e, t) {
1783
+ const n = e.map((s) => this.safeQuerySelector(s)).filter((s) => s instanceof HTMLElement);
1784
+ if (n.length > 0) {
1785
+ for (const s of n)
1786
+ this.containers.some((o) => o.element === s) || this.setupScrollContainer(s);
1787
+ return;
1788
+ }
1789
+ if (t < 5) {
1790
+ setTimeout(() => this.trySetupContainers(e, t + 1), 200);
1791
+ return;
1792
+ }
1793
+ this.containers.length === 0 && this.setupScrollContainer(window);
1794
+ }
1784
1795
  setupScrollContainer(e) {
1785
1796
  if (e !== window && !this.isElementScrollable(e))
1786
1797
  return;
@@ -1836,7 +1847,7 @@ class Jt extends f {
1836
1847
  }));
1837
1848
  }
1838
1849
  applyConfigOverrides() {
1839
- this.minDepthChange = ye, this.minIntervalMs = Te, this.maxEventsPerSession = Ie;
1850
+ this.minDepthChange = ye, this.minIntervalMs = Te, this.maxEventsPerSession = _e;
1840
1851
  }
1841
1852
  isWindowScrollable() {
1842
1853
  return document.documentElement.scrollHeight > window.innerHeight;
@@ -2048,7 +2059,7 @@ class tr extends f {
2048
2059
  "largest-contentful-paint",
2049
2060
  (n) => {
2050
2061
  const s = n.getEntries(), i = s[s.length - 1];
2051
- i && this.sendVital({ type: "LCP", value: Number(i.startTime.toFixed(_)) });
2062
+ i && this.sendVital({ type: "LCP", value: Number(i.startTime.toFixed(I)) });
2052
2063
  },
2053
2064
  { type: "largest-contentful-paint", buffered: !0 },
2054
2065
  !0
@@ -2066,14 +2077,14 @@ class tr extends f {
2066
2077
  const c = typeof o.value == "number" ? o.value : 0;
2067
2078
  e += c;
2068
2079
  }
2069
- this.sendVital({ type: "CLS", value: Number(e.toFixed(_)) });
2080
+ this.sendVital({ type: "CLS", value: Number(e.toFixed(I)) });
2070
2081
  },
2071
2082
  { type: "layout-shift", buffered: !0 }
2072
2083
  ), this.safeObserve(
2073
2084
  "paint",
2074
2085
  (n) => {
2075
2086
  for (const s of n.getEntries())
2076
- s.name === "first-contentful-paint" && this.sendVital({ type: "FCP", value: Number(s.startTime.toFixed(_)) });
2087
+ s.name === "first-contentful-paint" && this.sendVital({ type: "FCP", value: Number(s.startTime.toFixed(I)) });
2077
2088
  },
2078
2089
  { type: "paint", buffered: !0 },
2079
2090
  !0
@@ -2086,7 +2097,7 @@ class tr extends f {
2086
2097
  const c = (o.processingEnd ?? 0) - (o.startTime ?? 0);
2087
2098
  s = Math.max(s, c);
2088
2099
  }
2089
- s > 0 && this.sendVital({ type: "INP", value: Number(s.toFixed(_)) });
2100
+ s > 0 && this.sendVital({ type: "INP", value: Number(s.toFixed(I)) });
2090
2101
  },
2091
2102
  { type: "event", buffered: !0 }
2092
2103
  );
@@ -2094,7 +2105,7 @@ class tr extends f {
2094
2105
  async initWebVitals() {
2095
2106
  try {
2096
2107
  const { onLCP: e, onCLS: t, onFCP: n, onTTFB: s, onINP: i } = await Promise.resolve().then(() => Tr), o = (c) => (l) => {
2097
- const u = Number(l.value.toFixed(_));
2108
+ const u = Number(l.value.toFixed(I));
2098
2109
  this.sendVital({ type: c, value: u });
2099
2110
  };
2100
2111
  e(o("LCP")), t(o("CLS")), n(o("FCP")), s(o("TTFB")), i(o("INP"));
@@ -2110,7 +2121,7 @@ class tr extends f {
2110
2121
  if (!e)
2111
2122
  return;
2112
2123
  const t = e.responseStart;
2113
- typeof t == "number" && Number.isFinite(t) && this.sendVital({ type: "TTFB", value: Number(t.toFixed(_)) });
2124
+ typeof t == "number" && Number.isFinite(t) && this.sendVital({ type: "TTFB", value: Number(t.toFixed(I)) });
2114
2125
  } catch (e) {
2115
2126
  a.warn("PerformanceHandler", "Failed to report TTFB", {
2116
2127
  error: e instanceof Error ? e.message : "Unknown error"
@@ -2123,7 +2134,7 @@ class tr extends f {
2123
2134
  (e) => {
2124
2135
  const t = e.getEntries();
2125
2136
  for (const n of t) {
2126
- const s = Number(n.duration.toFixed(_)), i = Date.now();
2137
+ const s = Number(n.duration.toFixed(I)), i = Date.now();
2127
2138
  i - this.lastLongTaskSentAt >= mt && (this.shouldSendVital("LONG_TASK", s) && this.trackWebVital("LONG_TASK", s), this.lastLongTaskSentAt = i);
2128
2139
  }
2129
2140
  },
@@ -2455,10 +2466,10 @@ const sr = async (r) => {
2455
2466
  } finally {
2456
2467
  q = !1;
2457
2468
  }
2458
- }, Ir = {
2469
+ }, _r = {
2459
2470
  WEB_VITALS_THRESHOLDS: Fe
2460
2471
  // Business thresholds for performance analysis
2461
- }, _r = {
2472
+ }, Ir = {
2462
2473
  PII_PATTERNS: ze
2463
2474
  // Patterns for sensitive data protection
2464
2475
  }, wr = {
@@ -2743,7 +2754,7 @@ export {
2743
2754
  Cr as ANALYTICS_QUERY_LIMITS,
2744
2755
  Pr as ANOMALY_DETECTION,
2745
2756
  Mr as CONTENT_ANALYTICS,
2746
- _r as DATA_PROTECTION,
2757
+ Ir as DATA_PROTECTION,
2747
2758
  br as DEVICE_ANALYTICS,
2748
2759
  y as DeviceType,
2749
2760
  wr as ENGAGEMENT_THRESHOLDS,
@@ -2751,13 +2762,13 @@ export {
2751
2762
  d as EventType,
2752
2763
  Rr as INSIGHT_THRESHOLDS,
2753
2764
  H as Mode,
2754
- Ir as PERFORMANCE_CONFIG,
2765
+ _r as PERFORMANCE_CONFIG,
2755
2766
  Nr as SEGMENTATION_ANALYTICS,
2756
2767
  Ar as SESSION_ANALYTICS,
2757
2768
  Or as SPECIAL_PAGE_URLS,
2758
2769
  x as ScrollDirection,
2759
2770
  Lr as TEMPORAL_ANALYSIS,
2760
- It as TagConditionOperator,
2771
+ _t as TagConditionOperator,
2761
2772
  Tt as TagConditionType,
2762
2773
  yt as TagLogicalOperator,
2763
2774
  Dr as tracelog
package/dist/cjs/api.d.ts CHANGED
@@ -28,14 +28,14 @@ export declare const event: (name: string, metadata?: Record<string, MetadataTyp
28
28
  * @param event - Event name to listen to
29
29
  * @param callback - Function to call when event is emitted
30
30
  * @example
31
- * // Listen for real-time events
32
- * tracelog.on('realtime', (data) => {
33
- * console.log('Event tracked:', data.type, data.data);
31
+ * // Listen for tracked events
32
+ * tracelog.on('event', (data) => {
33
+ * console.log('Event tracked:', data.type);
34
34
  * });
35
35
  *
36
- * // Listen for sent events
37
- * tracelog.on('sent', (data) => {
38
- * console.log('Events sent:', data.eventCount);
36
+ * // Listen for event queues being sent
37
+ * tracelog.on('queue', (data) => {
38
+ * console.log('Events sent:', data.events.length);
39
39
  * });
40
40
  */
41
41
  export declare const on: <K extends keyof EmitterMap>(event: K, callback: EmitterCallback<EmitterMap[K]>) => void;
@@ -45,7 +45,7 @@ export declare const on: <K extends keyof EmitterMap>(event: K, callback: Emitte
45
45
  * @param callback - The same function reference that was used in on()
46
46
  * @example
47
47
  * // Remove a specific listener
48
- * tracelog.off('realtime', myCallback);
48
+ * tracelog.off('event', myCallback);
49
49
  */
50
50
  export declare const off: <K extends keyof EmitterMap>(event: K, callback: EmitterCallback<EmitterMap[K]>) => void;
51
51
  /**
package/dist/cjs/api.js CHANGED
@@ -96,14 +96,14 @@ exports.event = event;
96
96
  * @param event - Event name to listen to
97
97
  * @param callback - Function to call when event is emitted
98
98
  * @example
99
- * // Listen for real-time events
100
- * tracelog.on('realtime', (data) => {
101
- * console.log('Event tracked:', data.type, data.data);
99
+ * // Listen for tracked events
100
+ * tracelog.on('event', (data) => {
101
+ * console.log('Event tracked:', data.type);
102
102
  * });
103
103
  *
104
- * // Listen for sent events
105
- * tracelog.on('sent', (data) => {
106
- * console.log('Events sent:', data.eventCount);
104
+ * // Listen for event queues being sent
105
+ * tracelog.on('queue', (data) => {
106
+ * console.log('Events sent:', data.events.length);
107
107
  * });
108
108
  */
109
109
  const on = (event, callback) => {
@@ -119,7 +119,7 @@ exports.on = on;
119
119
  * @param callback - The same function reference that was used in on()
120
120
  * @example
121
121
  * // Remove a specific listener
122
- * tracelog.off('realtime', myCallback);
122
+ * tracelog.off('event', myCallback);
123
123
  */
124
124
  const off = (event, callback) => {
125
125
  if (!app) {
@@ -1,2 +1,2 @@
1
1
  export { Mode, EventType, DeviceType, ScrollDirection, ErrorType, TagConditionOperator, TagLogicalOperator, TagConditionType, } from './types';
2
- export type { ScrollData, ClickData, CustomEventData, MetadataType, WebVitalsData, ErrorData, PageViewData, UTM, EventData, AppConfig, ApiConfig, ExtendedEventsQueueDto, TagConfig, BaseEventsQueueDto, WebVitalType, SessionEndReason, } from './types';
2
+ export type { ScrollData, ClickData, CustomEventData, MetadataType, WebVitalsData, ErrorData, PageViewData, UTM, EventLocation, EventData, AppConfig, ApiConfig, ExtendedEventsQueueDto, TagConfig, BaseEventsQueueDto, WebVitalType, SessionEndReason, } from './types';
@@ -10,6 +10,7 @@ export declare class ScrollHandler extends StateManager {
10
10
  constructor(eventManager: EventManager);
11
11
  startTracking(): void;
12
12
  stopTracking(): void;
13
+ private trySetupContainers;
13
14
  private setupScrollContainer;
14
15
  private processScrollEvent;
15
16
  private shouldEmitScrollEvent;
@@ -21,14 +21,11 @@ class ScrollHandler extends state_manager_1.StateManager {
21
21
  this.set('scrollEventCount', 0);
22
22
  const raw = this.get('config').scrollContainerSelectors;
23
23
  const selectors = Array.isArray(raw) ? raw : typeof raw === 'string' ? [raw] : [];
24
- const elements = selectors
25
- .map((sel) => this.safeQuerySelector(sel))
26
- .filter((element) => element instanceof HTMLElement);
27
- if (elements.length === 0) {
28
- elements.push(window);
24
+ if (selectors.length === 0) {
25
+ this.setupScrollContainer(window);
29
26
  }
30
- for (const element of elements) {
31
- this.setupScrollContainer(element);
27
+ else {
28
+ this.trySetupContainers(selectors, 0);
32
29
  }
33
30
  }
34
31
  stopTracking() {
@@ -45,6 +42,27 @@ class ScrollHandler extends state_manager_1.StateManager {
45
42
  this.set('scrollEventCount', 0);
46
43
  this.limitWarningLogged = false;
47
44
  }
45
+ trySetupContainers(selectors, attempt) {
46
+ const elements = selectors
47
+ .map((sel) => this.safeQuerySelector(sel))
48
+ .filter((element) => element instanceof HTMLElement);
49
+ if (elements.length > 0) {
50
+ for (const element of elements) {
51
+ const isAlreadyTracking = this.containers.some((c) => c.element === element);
52
+ if (!isAlreadyTracking) {
53
+ this.setupScrollContainer(element);
54
+ }
55
+ }
56
+ return;
57
+ }
58
+ if (attempt < 5) {
59
+ setTimeout(() => this.trySetupContainers(selectors, attempt + 1), 200);
60
+ return;
61
+ }
62
+ if (this.containers.length === 0) {
63
+ this.setupScrollContainer(window);
64
+ }
65
+ }
48
66
  setupScrollContainer(element) {
49
67
  // Skip setup for non-scrollable elements
50
68
  if (element !== window && !this.isElementScrollable(element)) {
@@ -250,7 +250,7 @@ class SessionManager extends state_manager_1.StateManager {
250
250
  }
251
251
  };
252
252
  this.beforeUnloadHandler = () => {
253
- this.eventManager.flushImmediatelySync();
253
+ this.endSession('page_unload');
254
254
  };
255
255
  // Handle tab visibility changes
256
256
  document.addEventListener('visibilitychange', this.visibilityChangeHandler);
@@ -75,6 +75,10 @@ export interface PageViewData {
75
75
  search?: string;
76
76
  hash?: string;
77
77
  }
78
+ export interface EventLocation {
79
+ country: string;
80
+ country_code: string;
81
+ }
78
82
  export interface VitalSample {
79
83
  type: WebVitalType;
80
84
  value: number;
@@ -94,6 +98,7 @@ export interface EventData {
94
98
  session_end_reason?: SessionEndReason;
95
99
  error_data?: ErrorData;
96
100
  utm?: UTM;
101
+ location?: EventLocation;
97
102
  tags?: string[] | {
98
103
  id: string;
99
104
  key: string;
package/dist/esm/api.d.ts CHANGED
@@ -28,14 +28,14 @@ export declare const event: (name: string, metadata?: Record<string, MetadataTyp
28
28
  * @param event - Event name to listen to
29
29
  * @param callback - Function to call when event is emitted
30
30
  * @example
31
- * // Listen for real-time events
32
- * tracelog.on('realtime', (data) => {
33
- * console.log('Event tracked:', data.type, data.data);
31
+ * // Listen for tracked events
32
+ * tracelog.on('event', (data) => {
33
+ * console.log('Event tracked:', data.type);
34
34
  * });
35
35
  *
36
- * // Listen for sent events
37
- * tracelog.on('sent', (data) => {
38
- * console.log('Events sent:', data.eventCount);
36
+ * // Listen for event queues being sent
37
+ * tracelog.on('queue', (data) => {
38
+ * console.log('Events sent:', data.events.length);
39
39
  * });
40
40
  */
41
41
  export declare const on: <K extends keyof EmitterMap>(event: K, callback: EmitterCallback<EmitterMap[K]>) => void;
@@ -45,7 +45,7 @@ export declare const on: <K extends keyof EmitterMap>(event: K, callback: Emitte
45
45
  * @param callback - The same function reference that was used in on()
46
46
  * @example
47
47
  * // Remove a specific listener
48
- * tracelog.off('realtime', myCallback);
48
+ * tracelog.off('event', myCallback);
49
49
  */
50
50
  export declare const off: <K extends keyof EmitterMap>(event: K, callback: EmitterCallback<EmitterMap[K]>) => void;
51
51
  /**
package/dist/esm/api.js CHANGED
@@ -91,14 +91,14 @@ export const event = (name, metadata) => {
91
91
  * @param event - Event name to listen to
92
92
  * @param callback - Function to call when event is emitted
93
93
  * @example
94
- * // Listen for real-time events
95
- * tracelog.on('realtime', (data) => {
96
- * console.log('Event tracked:', data.type, data.data);
94
+ * // Listen for tracked events
95
+ * tracelog.on('event', (data) => {
96
+ * console.log('Event tracked:', data.type);
97
97
  * });
98
98
  *
99
- * // Listen for sent events
100
- * tracelog.on('sent', (data) => {
101
- * console.log('Events sent:', data.eventCount);
99
+ * // Listen for event queues being sent
100
+ * tracelog.on('queue', (data) => {
101
+ * console.log('Events sent:', data.events.length);
102
102
  * });
103
103
  */
104
104
  export const on = (event, callback) => {
@@ -113,7 +113,7 @@ export const on = (event, callback) => {
113
113
  * @param callback - The same function reference that was used in on()
114
114
  * @example
115
115
  * // Remove a specific listener
116
- * tracelog.off('realtime', myCallback);
116
+ * tracelog.off('event', myCallback);
117
117
  */
118
118
  export const off = (event, callback) => {
119
119
  if (!app) {
@@ -1,2 +1,2 @@
1
1
  export { Mode, EventType, DeviceType, ScrollDirection, ErrorType, TagConditionOperator, TagLogicalOperator, TagConditionType, } from './types';
2
- export type { ScrollData, ClickData, CustomEventData, MetadataType, WebVitalsData, ErrorData, PageViewData, UTM, EventData, AppConfig, ApiConfig, ExtendedEventsQueueDto, TagConfig, BaseEventsQueueDto, WebVitalType, SessionEndReason, } from './types';
2
+ export type { ScrollData, ClickData, CustomEventData, MetadataType, WebVitalsData, ErrorData, PageViewData, UTM, EventLocation, EventData, AppConfig, ApiConfig, ExtendedEventsQueueDto, TagConfig, BaseEventsQueueDto, WebVitalType, SessionEndReason, } from './types';
@@ -10,6 +10,7 @@ export declare class ScrollHandler extends StateManager {
10
10
  constructor(eventManager: EventManager);
11
11
  startTracking(): void;
12
12
  stopTracking(): void;
13
+ private trySetupContainers;
13
14
  private setupScrollContainer;
14
15
  private processScrollEvent;
15
16
  private shouldEmitScrollEvent;
@@ -18,14 +18,11 @@ export class ScrollHandler extends StateManager {
18
18
  this.set('scrollEventCount', 0);
19
19
  const raw = this.get('config').scrollContainerSelectors;
20
20
  const selectors = Array.isArray(raw) ? raw : typeof raw === 'string' ? [raw] : [];
21
- const elements = selectors
22
- .map((sel) => this.safeQuerySelector(sel))
23
- .filter((element) => element instanceof HTMLElement);
24
- if (elements.length === 0) {
25
- elements.push(window);
21
+ if (selectors.length === 0) {
22
+ this.setupScrollContainer(window);
26
23
  }
27
- for (const element of elements) {
28
- this.setupScrollContainer(element);
24
+ else {
25
+ this.trySetupContainers(selectors, 0);
29
26
  }
30
27
  }
31
28
  stopTracking() {
@@ -42,6 +39,27 @@ export class ScrollHandler extends StateManager {
42
39
  this.set('scrollEventCount', 0);
43
40
  this.limitWarningLogged = false;
44
41
  }
42
+ trySetupContainers(selectors, attempt) {
43
+ const elements = selectors
44
+ .map((sel) => this.safeQuerySelector(sel))
45
+ .filter((element) => element instanceof HTMLElement);
46
+ if (elements.length > 0) {
47
+ for (const element of elements) {
48
+ const isAlreadyTracking = this.containers.some((c) => c.element === element);
49
+ if (!isAlreadyTracking) {
50
+ this.setupScrollContainer(element);
51
+ }
52
+ }
53
+ return;
54
+ }
55
+ if (attempt < 5) {
56
+ setTimeout(() => this.trySetupContainers(selectors, attempt + 1), 200);
57
+ return;
58
+ }
59
+ if (this.containers.length === 0) {
60
+ this.setupScrollContainer(window);
61
+ }
62
+ }
45
63
  setupScrollContainer(element) {
46
64
  // Skip setup for non-scrollable elements
47
65
  if (element !== window && !this.isElementScrollable(element)) {
@@ -247,7 +247,7 @@ export class SessionManager extends StateManager {
247
247
  }
248
248
  };
249
249
  this.beforeUnloadHandler = () => {
250
- this.eventManager.flushImmediatelySync();
250
+ this.endSession('page_unload');
251
251
  };
252
252
  // Handle tab visibility changes
253
253
  document.addEventListener('visibilitychange', this.visibilityChangeHandler);
@@ -75,6 +75,10 @@ export interface PageViewData {
75
75
  search?: string;
76
76
  hash?: string;
77
77
  }
78
+ export interface EventLocation {
79
+ country: string;
80
+ country_code: string;
81
+ }
78
82
  export interface VitalSample {
79
83
  type: WebVitalType;
80
84
  value: number;
@@ -94,6 +98,7 @@ export interface EventData {
94
98
  session_end_reason?: SessionEndReason;
95
99
  error_data?: ErrorData;
96
100
  utm?: UTM;
101
+ location?: EventLocation;
97
102
  tags?: string[] | {
98
103
  id: string;
99
104
  key: string;
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@tracelog/lib",
3
3
  "description": "JavaScript library for web analytics and real-time event tracking",
4
4
  "license": "MIT",
5
- "version": "0.3.0",
5
+ "version": "0.4.0",
6
6
  "main": "./dist/cjs/public-api.js",
7
7
  "module": "./dist/esm/public-api.js",
8
8
  "types": "./dist/esm/public-api.d.ts",