@croct/sdk 0.21.1 → 0.22.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.
package/constants.cjs CHANGED
@@ -25,7 +25,7 @@ __export(constants_exports, {
25
25
  module.exports = __toCommonJS(constants_exports);
26
26
  const BASE_ENDPOINT_URL = "https://api.croct.io";
27
27
  const MAX_QUERY_LENGTH = parseInt("<@maxQueryLength@>", 10);
28
- const VERSION = "0.21.1";
28
+ const VERSION = "0.22.0";
29
29
  const CLIENT_LIBRARY = `Croct SDK JS v${VERSION}`;
30
30
  // Annotate the CommonJS export names for ESM import in node:
31
31
  0 && (module.exports = {
package/constants.d.cts CHANGED
@@ -1,6 +1,6 @@
1
1
  declare const BASE_ENDPOINT_URL = "https://api.croct.io";
2
2
  declare const MAX_QUERY_LENGTH: number;
3
- declare const VERSION = "0.21.1";
4
- declare const CLIENT_LIBRARY = "Croct SDK JS v0.21.1";
3
+ declare const VERSION = "0.22.0";
4
+ declare const CLIENT_LIBRARY = "Croct SDK JS v0.22.0";
5
5
 
6
6
  export { BASE_ENDPOINT_URL, CLIENT_LIBRARY, MAX_QUERY_LENGTH, VERSION };
package/constants.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  declare const BASE_ENDPOINT_URL = "https://api.croct.io";
2
2
  declare const MAX_QUERY_LENGTH: number;
3
- declare const VERSION = "0.21.1";
4
- declare const CLIENT_LIBRARY = "Croct SDK JS v0.21.1";
3
+ declare const VERSION = "0.22.0";
4
+ declare const CLIENT_LIBRARY = "Croct SDK JS v0.22.0";
5
5
 
6
6
  export { BASE_ENDPOINT_URL, CLIENT_LIBRARY, MAX_QUERY_LENGTH, VERSION };
package/constants.js CHANGED
@@ -1,6 +1,6 @@
1
1
  const BASE_ENDPOINT_URL = "https://api.croct.io";
2
2
  const MAX_QUERY_LENGTH = parseInt("<@maxQueryLength@>", 10);
3
- const VERSION = "0.21.1";
3
+ const VERSION = "0.22.0";
4
4
  const CLIENT_LIBRARY = `Croct SDK JS v${VERSION}`;
5
5
  export {
6
6
  BASE_ENDPOINT_URL,
package/container.cjs CHANGED
@@ -47,6 +47,12 @@ const _Container = class _Container {
47
47
  getConfiguration() {
48
48
  return this.configuration;
49
49
  }
50
+ getTimeZone() {
51
+ if (this.timeZone === void 0) {
52
+ this.timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone ?? null;
53
+ }
54
+ return this.timeZone;
55
+ }
50
56
  getEvaluator() {
51
57
  if (this.evaluator === void 0) {
52
58
  this.evaluator = this.createEvaluator();
@@ -98,7 +104,8 @@ const _Container = class _Container {
98
104
  inactivityRetryPolicy: new import_retry.ArbitraryPolicy([3e4, 3e4, 12e4, 12e4, 3e5, 3e5, 9e5]),
99
105
  logger: this.getLogger("Tracker"),
100
106
  channel: this.getBeaconChannel(),
101
- eventMetadata: this.configuration.eventMetadata
107
+ eventMetadata: this.configuration.eventMetadata,
108
+ timeZone: this.getTimeZone() ?? void 0
102
109
  });
103
110
  const queue = this.getBeaconQueue();
104
111
  queue.addCallback("halfEmpty", tracker.unsuspend);
package/container.d.cts CHANGED
@@ -61,8 +61,10 @@ declare class Container {
61
61
  private beaconQueue?;
62
62
  private removeTokenSyncListener?;
63
63
  private readonly eventManager;
64
+ private timeZone?;
64
65
  constructor(configuration: Configuration);
65
66
  getConfiguration(): Configuration;
67
+ getTimeZone(): string | null;
66
68
  getEvaluator(): Evaluator;
67
69
  private createEvaluator;
68
70
  getContentFetcher(): ContentFetcher;
package/container.d.ts CHANGED
@@ -61,8 +61,10 @@ declare class Container {
61
61
  private beaconQueue?;
62
62
  private removeTokenSyncListener?;
63
63
  private readonly eventManager;
64
+ private timeZone?;
64
65
  constructor(configuration: Configuration);
65
66
  getConfiguration(): Configuration;
67
+ getTimeZone(): string | null;
66
68
  getEvaluator(): Evaluator;
67
69
  private createEvaluator;
68
70
  getContentFetcher(): ContentFetcher;
package/container.js CHANGED
@@ -25,6 +25,12 @@ const _Container = class _Container {
25
25
  getConfiguration() {
26
26
  return this.configuration;
27
27
  }
28
+ getTimeZone() {
29
+ if (this.timeZone === void 0) {
30
+ this.timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone ?? null;
31
+ }
32
+ return this.timeZone;
33
+ }
28
34
  getEvaluator() {
29
35
  if (this.evaluator === void 0) {
30
36
  this.evaluator = this.createEvaluator();
@@ -76,7 +82,8 @@ const _Container = class _Container {
76
82
  inactivityRetryPolicy: new ArbitraryPolicy([3e4, 3e4, 12e4, 12e4, 3e5, 3e5, 9e5]),
77
83
  logger: this.getLogger("Tracker"),
78
84
  channel: this.getBeaconChannel(),
79
- eventMetadata: this.configuration.eventMetadata
85
+ eventMetadata: this.configuration.eventMetadata,
86
+ timeZone: this.getTimeZone() ?? void 0
80
87
  });
81
88
  const queue = this.getBeaconQueue();
82
89
  queue.addCallback("halfEmpty", tracker.unsuspend);
@@ -60,8 +60,9 @@ class MinimalContextFactory {
60
60
  }
61
61
  }
62
62
  class TabContextFactory {
63
- constructor(tab) {
63
+ constructor(tab, timeZone) {
64
64
  this.tab = tab;
65
+ this.timeZone = timeZone;
65
66
  }
66
67
  createContext(attributes) {
67
68
  const url = new URL(this.tab.url);
@@ -75,9 +76,8 @@ class TabContextFactory {
75
76
  page.referrer = referrer;
76
77
  }
77
78
  context.page = page;
78
- const timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone ?? null;
79
- if (timeZone !== null) {
80
- context.timeZone = timeZone;
79
+ if (this.timeZone !== void 0) {
80
+ context.timeZone = this.timeZone;
81
81
  }
82
82
  if (attributes !== void 0 && Object.keys(attributes).length > 0) {
83
83
  context.attributes = attributes;
@@ -34,7 +34,8 @@ declare class MinimalContextFactory implements ContextFactory {
34
34
  }
35
35
  declare class TabContextFactory implements ContextFactory {
36
36
  private readonly tab;
37
- constructor(tab: Tab);
37
+ private readonly timeZone?;
38
+ constructor(tab: Tab, timeZone?: string);
38
39
  createContext(attributes?: JsonObject): EvaluationContext;
39
40
  }
40
41
 
@@ -34,7 +34,8 @@ declare class MinimalContextFactory implements ContextFactory {
34
34
  }
35
35
  declare class TabContextFactory implements ContextFactory {
36
36
  private readonly tab;
37
- constructor(tab: Tab);
37
+ private readonly timeZone?;
38
+ constructor(tab: Tab, timeZone?: string);
38
39
  createContext(attributes?: JsonObject): EvaluationContext;
39
40
  }
40
41
 
@@ -36,8 +36,9 @@ class MinimalContextFactory {
36
36
  }
37
37
  }
38
38
  class TabContextFactory {
39
- constructor(tab) {
39
+ constructor(tab, timeZone) {
40
40
  this.tab = tab;
41
+ this.timeZone = timeZone;
41
42
  }
42
43
  createContext(attributes) {
43
44
  const url = new URL(this.tab.url);
@@ -51,9 +52,8 @@ class TabContextFactory {
51
52
  page.referrer = referrer;
52
53
  }
53
54
  context.page = page;
54
- const timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone ?? null;
55
- if (timeZone !== null) {
56
- context.timeZone = timeZone;
55
+ if (this.timeZone !== void 0) {
56
+ context.timeZone = this.timeZone;
57
57
  }
58
58
  if (attributes !== void 0 && Object.keys(attributes).length > 0) {
59
59
  context.attributes = attributes;
@@ -132,7 +132,10 @@ class SdkFacade {
132
132
  if (this.evaluatorFacade === void 0) {
133
133
  this.evaluatorFacade = new import_evaluatorFacade.EvaluatorFacade({
134
134
  evaluator: this.sdk.evaluator,
135
- contextFactory: new import_evaluatorFacade.TabContextFactory(this.sdk.context.getTab()),
135
+ contextFactory: new import_evaluatorFacade.TabContextFactory(
136
+ this.sdk.context.getTab(),
137
+ this.sdk.timeZone ?? void 0
138
+ ),
136
139
  cidAssigner: this.sdk.cidAssigner,
137
140
  userTokenProvider: this.sdk.userTokenStore
138
141
  });
@@ -143,7 +146,10 @@ class SdkFacade {
143
146
  if (this.contentFetcherFacade === void 0) {
144
147
  this.contentFetcherFacade = new import_contentFetcherFacade.ContentFetcherFacade({
145
148
  contentFetcher: this.sdk.contentFetcher,
146
- contextFactory: new import_evaluatorFacade.TabContextFactory(this.sdk.context.getTab()),
149
+ contextFactory: new import_evaluatorFacade.TabContextFactory(
150
+ this.sdk.context.getTab(),
151
+ this.sdk.timeZone ?? void 0
152
+ ),
147
153
  cidAssigner: this.sdk.cidAssigner,
148
154
  previewTokenProvider: this.sdk.previewTokenStore,
149
155
  userTokenProvider: this.sdk.userTokenStore
@@ -110,7 +110,10 @@ class SdkFacade {
110
110
  if (this.evaluatorFacade === void 0) {
111
111
  this.evaluatorFacade = new EvaluatorFacade({
112
112
  evaluator: this.sdk.evaluator,
113
- contextFactory: new TabContextFactory(this.sdk.context.getTab()),
113
+ contextFactory: new TabContextFactory(
114
+ this.sdk.context.getTab(),
115
+ this.sdk.timeZone ?? void 0
116
+ ),
114
117
  cidAssigner: this.sdk.cidAssigner,
115
118
  userTokenProvider: this.sdk.userTokenStore
116
119
  });
@@ -121,7 +124,10 @@ class SdkFacade {
121
124
  if (this.contentFetcherFacade === void 0) {
122
125
  this.contentFetcherFacade = new ContentFetcherFacade({
123
126
  contentFetcher: this.sdk.contentFetcher,
124
- contextFactory: new TabContextFactory(this.sdk.context.getTab()),
127
+ contextFactory: new TabContextFactory(
128
+ this.sdk.context.getTab(),
129
+ this.sdk.timeZone ?? void 0
130
+ ),
125
131
  cidAssigner: this.sdk.cidAssigner,
126
132
  previewTokenProvider: this.sdk.previewTokenStore,
127
133
  userTokenProvider: this.sdk.userTokenStore
@@ -0,0 +1,181 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
+ var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
5
+ var __export = (target, all) => {
6
+ for (var name in all)
7
+ __defProp(target, name, { get: all[name], enumerable: true });
8
+ };
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") {
11
+ for (let key of __getOwnPropNames(from))
12
+ if (!__hasOwnProp.call(to, key) && key !== except)
13
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
14
+ }
15
+ return to;
16
+ };
17
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
18
+ var interactionMonitor_exports = {};
19
+ __export(interactionMonitor_exports, {
20
+ InteractionMonitor: () => InteractionMonitor
21
+ });
22
+ module.exports = __toCommonJS(interactionMonitor_exports);
23
+ var import_eventManager = require('./eventManager.cjs');
24
+ class InteractionMonitor {
25
+ constructor(options = {}) {
26
+ this.eventManager = new import_eventManager.SynchronousEventManager();
27
+ this.lastClickTime = 0;
28
+ this.enabled = false;
29
+ this.clickThrottleInterval = options.clickThrottleInterval ?? 500;
30
+ this.scrollDebounceInterval = options.scrollDebounceInterval ?? 250;
31
+ this.handleClick = this.handleClick.bind(this);
32
+ this.handleScroll = this.handleScroll.bind(this);
33
+ }
34
+ addListener(type, listener) {
35
+ this.eventManager.addListener(type, listener);
36
+ }
37
+ removeListener(type, listener) {
38
+ this.eventManager.removeListener(type, listener);
39
+ }
40
+ isEnabled() {
41
+ return this.enabled;
42
+ }
43
+ enable() {
44
+ if (this.enabled) {
45
+ return;
46
+ }
47
+ this.enabled = true;
48
+ window.addEventListener("click", this.handleClick, true);
49
+ window.addEventListener("scroll", this.handleScroll, true);
50
+ }
51
+ disable() {
52
+ if (!this.enabled) {
53
+ return;
54
+ }
55
+ this.enabled = false;
56
+ window.removeEventListener("click", this.handleClick, true);
57
+ window.removeEventListener("scroll", this.handleScroll, true);
58
+ this.flushPendingScroll();
59
+ }
60
+ handleClick(event) {
61
+ const currentTime = Date.now();
62
+ if (currentTime - this.lastClickTime < this.clickThrottleInterval) {
63
+ return;
64
+ }
65
+ this.lastClickTime = currentTime;
66
+ this.eventManager.dispatch("userClicked", {
67
+ type: "userClicked",
68
+ point: {
69
+ x: Math.max(0, Math.round(event.pageX)),
70
+ y: Math.max(0, Math.round(event.pageY))
71
+ },
72
+ surfaceSize: {
73
+ width: document.documentElement.scrollWidth,
74
+ height: document.documentElement.scrollHeight
75
+ }
76
+ });
77
+ }
78
+ handleScroll() {
79
+ const currentPosition = {
80
+ x: Math.max(0, Math.round(window.scrollX)),
81
+ y: Math.max(0, Math.round(window.scrollY))
82
+ };
83
+ if (this.scrollState === void 0) {
84
+ this.scrollState = {
85
+ start: currentPosition,
86
+ lastPosition: currentPosition
87
+ };
88
+ } else if (this.hasDirectionChanged(this.scrollState, currentPosition)) {
89
+ const turningPoint = this.scrollState.lastPosition;
90
+ this.flushPendingScroll(turningPoint);
91
+ this.scrollState = {
92
+ start: turningPoint,
93
+ lastPosition: currentPosition
94
+ };
95
+ } else {
96
+ this.scrollState.lastPosition = currentPosition;
97
+ }
98
+ if (this.scrollDebounceTimer !== void 0) {
99
+ window.clearTimeout(this.scrollDebounceTimer);
100
+ }
101
+ this.scrollDebounceTimer = window.setTimeout(
102
+ () => this.flushPendingScroll(),
103
+ this.scrollDebounceInterval
104
+ );
105
+ }
106
+ /**
107
+ * Determines whether the scroll direction has reversed on either axis.
108
+ *
109
+ * It compares two vectors:
110
+ * - The scroll direction: the overall direction from start to the previous position (start -> previous)
111
+ * - The movement direction: the direction of the latest movement (previous -> current)
112
+ *
113
+ * A reversal is detected when these two vectors point in opposite directions on the same axis.
114
+ * Axes with no movement (sign = 0) are ignored, so scrolling that simply stops on one axis
115
+ * without reversing does not trigger a flush.
116
+ *
117
+ * Example of vertical reversal:
118
+ * start = {y: 0}, previous = {y: 500}, current = {y: 400}
119
+ * scrollDirectionY = sign(500 - 0) = +1 (downward)
120
+ * movementDirectionY = sign(400 - 500) = -1 (upward)
121
+ * +1 !== -1 => reversed
122
+ *
123
+ * Example of no reversal (same direction):
124
+ * start = {y: 0}, previous = {y: 200}, current = {y: 500}
125
+ * scrollDirectionY = sign(200 - 0) = +1 (downward)
126
+ * movementDirectionY = sign(500 - 200) = +1 (downward)
127
+ * +1 === +1 => not reversed
128
+ *
129
+ * Example of horizontal stop ignored:
130
+ * start = {x: 0}, previous = {x: 300}, current = {x: 300}
131
+ * scrollDirectionX = sign(300 - 0) = +1
132
+ * movementDirectionX = sign(300 - 300) = 0 (no movement)
133
+ * movementDirectionX is 0 => ignored, not a reversal
134
+ */
135
+ hasDirectionChanged(state, current) {
136
+ const { start, lastPosition: previous } = state;
137
+ const scrollDirectionX = Math.sign(previous.x - start.x);
138
+ const scrollDirectionY = Math.sign(previous.y - start.y);
139
+ const movementDirectionX = Math.sign(current.x - previous.x);
140
+ const movementDirectionY = Math.sign(current.y - previous.y);
141
+ return scrollDirectionX !== 0 && movementDirectionX !== 0 && scrollDirectionX !== movementDirectionX || scrollDirectionY !== 0 && movementDirectionY !== 0 && scrollDirectionY !== movementDirectionY;
142
+ }
143
+ flushPendingScroll(end) {
144
+ if (this.scrollDebounceTimer !== void 0) {
145
+ window.clearTimeout(this.scrollDebounceTimer);
146
+ this.scrollDebounceTimer = void 0;
147
+ }
148
+ if (this.scrollState === void 0) {
149
+ return;
150
+ }
151
+ const { start } = this.scrollState;
152
+ const destination = end ?? {
153
+ x: Math.max(0, Math.round(window.scrollX)),
154
+ y: Math.max(0, Math.round(window.scrollY))
155
+ };
156
+ this.scrollState = void 0;
157
+ if (start.x === destination.x && start.y === destination.y) {
158
+ return;
159
+ }
160
+ this.eventManager.dispatch("userScrolled", {
161
+ type: "userScrolled",
162
+ start,
163
+ end: destination,
164
+ surfaceSize: {
165
+ width: document.documentElement.scrollWidth,
166
+ height: document.documentElement.scrollHeight
167
+ },
168
+ // Uses clientWidth/clientHeight instead of innerWidth/innerHeight to get the
169
+ // layout viewport size, which remains stable regardless of pinch-to-zoom level
170
+ // on mobile devices.
171
+ viewportSize: {
172
+ width: document.documentElement.clientWidth,
173
+ height: document.documentElement.clientHeight
174
+ }
175
+ });
176
+ }
177
+ }
178
+ // Annotate the CommonJS export names for ESM import in node:
179
+ 0 && (module.exports = {
180
+ InteractionMonitor
181
+ });
@@ -0,0 +1,64 @@
1
+ import { EventListener } from './eventManager.cjs';
2
+ import { UserClicked, UserScrolled } from './trackingEvents.cjs';
3
+ import './patch.cjs';
4
+ import '@croct/json';
5
+ import './utilityTypes.cjs';
6
+
7
+ type InteractionEventMap = {
8
+ userClicked: UserClicked;
9
+ userScrolled: UserScrolled;
10
+ };
11
+ type Options = {
12
+ clickThrottleInterval?: number;
13
+ scrollDebounceInterval?: number;
14
+ };
15
+ declare class InteractionMonitor {
16
+ private readonly eventManager;
17
+ private readonly clickThrottleInterval;
18
+ private readonly scrollDebounceInterval;
19
+ private lastClickTime;
20
+ private scrollState?;
21
+ private scrollDebounceTimer?;
22
+ private enabled;
23
+ constructor(options?: Options);
24
+ addListener<T extends keyof InteractionEventMap>(type: T, listener: EventListener<InteractionEventMap[T]>): void;
25
+ removeListener<T extends keyof InteractionEventMap>(type: T, listener: EventListener<InteractionEventMap[T]>): void;
26
+ isEnabled(): boolean;
27
+ enable(): void;
28
+ disable(): void;
29
+ private handleClick;
30
+ private handleScroll;
31
+ /**
32
+ * Determines whether the scroll direction has reversed on either axis.
33
+ *
34
+ * It compares two vectors:
35
+ * - The scroll direction: the overall direction from start to the previous position (start -> previous)
36
+ * - The movement direction: the direction of the latest movement (previous -> current)
37
+ *
38
+ * A reversal is detected when these two vectors point in opposite directions on the same axis.
39
+ * Axes with no movement (sign = 0) are ignored, so scrolling that simply stops on one axis
40
+ * without reversing does not trigger a flush.
41
+ *
42
+ * Example of vertical reversal:
43
+ * start = {y: 0}, previous = {y: 500}, current = {y: 400}
44
+ * scrollDirectionY = sign(500 - 0) = +1 (downward)
45
+ * movementDirectionY = sign(400 - 500) = -1 (upward)
46
+ * +1 !== -1 => reversed
47
+ *
48
+ * Example of no reversal (same direction):
49
+ * start = {y: 0}, previous = {y: 200}, current = {y: 500}
50
+ * scrollDirectionY = sign(200 - 0) = +1 (downward)
51
+ * movementDirectionY = sign(500 - 200) = +1 (downward)
52
+ * +1 === +1 => not reversed
53
+ *
54
+ * Example of horizontal stop ignored:
55
+ * start = {x: 0}, previous = {x: 300}, current = {x: 300}
56
+ * scrollDirectionX = sign(300 - 0) = +1
57
+ * movementDirectionX = sign(300 - 300) = 0 (no movement)
58
+ * movementDirectionX is 0 => ignored, not a reversal
59
+ */
60
+ private hasDirectionChanged;
61
+ private flushPendingScroll;
62
+ }
63
+
64
+ export { InteractionMonitor };
@@ -0,0 +1,64 @@
1
+ import { EventListener } from './eventManager.js';
2
+ import { UserClicked, UserScrolled } from './trackingEvents.js';
3
+ import './patch.js';
4
+ import '@croct/json';
5
+ import './utilityTypes.js';
6
+
7
+ type InteractionEventMap = {
8
+ userClicked: UserClicked;
9
+ userScrolled: UserScrolled;
10
+ };
11
+ type Options = {
12
+ clickThrottleInterval?: number;
13
+ scrollDebounceInterval?: number;
14
+ };
15
+ declare class InteractionMonitor {
16
+ private readonly eventManager;
17
+ private readonly clickThrottleInterval;
18
+ private readonly scrollDebounceInterval;
19
+ private lastClickTime;
20
+ private scrollState?;
21
+ private scrollDebounceTimer?;
22
+ private enabled;
23
+ constructor(options?: Options);
24
+ addListener<T extends keyof InteractionEventMap>(type: T, listener: EventListener<InteractionEventMap[T]>): void;
25
+ removeListener<T extends keyof InteractionEventMap>(type: T, listener: EventListener<InteractionEventMap[T]>): void;
26
+ isEnabled(): boolean;
27
+ enable(): void;
28
+ disable(): void;
29
+ private handleClick;
30
+ private handleScroll;
31
+ /**
32
+ * Determines whether the scroll direction has reversed on either axis.
33
+ *
34
+ * It compares two vectors:
35
+ * - The scroll direction: the overall direction from start to the previous position (start -> previous)
36
+ * - The movement direction: the direction of the latest movement (previous -> current)
37
+ *
38
+ * A reversal is detected when these two vectors point in opposite directions on the same axis.
39
+ * Axes with no movement (sign = 0) are ignored, so scrolling that simply stops on one axis
40
+ * without reversing does not trigger a flush.
41
+ *
42
+ * Example of vertical reversal:
43
+ * start = {y: 0}, previous = {y: 500}, current = {y: 400}
44
+ * scrollDirectionY = sign(500 - 0) = +1 (downward)
45
+ * movementDirectionY = sign(400 - 500) = -1 (upward)
46
+ * +1 !== -1 => reversed
47
+ *
48
+ * Example of no reversal (same direction):
49
+ * start = {y: 0}, previous = {y: 200}, current = {y: 500}
50
+ * scrollDirectionY = sign(200 - 0) = +1 (downward)
51
+ * movementDirectionY = sign(500 - 200) = +1 (downward)
52
+ * +1 === +1 => not reversed
53
+ *
54
+ * Example of horizontal stop ignored:
55
+ * start = {x: 0}, previous = {x: 300}, current = {x: 300}
56
+ * scrollDirectionX = sign(300 - 0) = +1
57
+ * movementDirectionX = sign(300 - 300) = 0 (no movement)
58
+ * movementDirectionX is 0 => ignored, not a reversal
59
+ */
60
+ private hasDirectionChanged;
61
+ private flushPendingScroll;
62
+ }
63
+
64
+ export { InteractionMonitor };
@@ -0,0 +1,158 @@
1
+ import { SynchronousEventManager } from "./eventManager.js";
2
+ class InteractionMonitor {
3
+ constructor(options = {}) {
4
+ this.eventManager = new SynchronousEventManager();
5
+ this.lastClickTime = 0;
6
+ this.enabled = false;
7
+ this.clickThrottleInterval = options.clickThrottleInterval ?? 500;
8
+ this.scrollDebounceInterval = options.scrollDebounceInterval ?? 250;
9
+ this.handleClick = this.handleClick.bind(this);
10
+ this.handleScroll = this.handleScroll.bind(this);
11
+ }
12
+ addListener(type, listener) {
13
+ this.eventManager.addListener(type, listener);
14
+ }
15
+ removeListener(type, listener) {
16
+ this.eventManager.removeListener(type, listener);
17
+ }
18
+ isEnabled() {
19
+ return this.enabled;
20
+ }
21
+ enable() {
22
+ if (this.enabled) {
23
+ return;
24
+ }
25
+ this.enabled = true;
26
+ window.addEventListener("click", this.handleClick, true);
27
+ window.addEventListener("scroll", this.handleScroll, true);
28
+ }
29
+ disable() {
30
+ if (!this.enabled) {
31
+ return;
32
+ }
33
+ this.enabled = false;
34
+ window.removeEventListener("click", this.handleClick, true);
35
+ window.removeEventListener("scroll", this.handleScroll, true);
36
+ this.flushPendingScroll();
37
+ }
38
+ handleClick(event) {
39
+ const currentTime = Date.now();
40
+ if (currentTime - this.lastClickTime < this.clickThrottleInterval) {
41
+ return;
42
+ }
43
+ this.lastClickTime = currentTime;
44
+ this.eventManager.dispatch("userClicked", {
45
+ type: "userClicked",
46
+ point: {
47
+ x: Math.max(0, Math.round(event.pageX)),
48
+ y: Math.max(0, Math.round(event.pageY))
49
+ },
50
+ surfaceSize: {
51
+ width: document.documentElement.scrollWidth,
52
+ height: document.documentElement.scrollHeight
53
+ }
54
+ });
55
+ }
56
+ handleScroll() {
57
+ const currentPosition = {
58
+ x: Math.max(0, Math.round(window.scrollX)),
59
+ y: Math.max(0, Math.round(window.scrollY))
60
+ };
61
+ if (this.scrollState === void 0) {
62
+ this.scrollState = {
63
+ start: currentPosition,
64
+ lastPosition: currentPosition
65
+ };
66
+ } else if (this.hasDirectionChanged(this.scrollState, currentPosition)) {
67
+ const turningPoint = this.scrollState.lastPosition;
68
+ this.flushPendingScroll(turningPoint);
69
+ this.scrollState = {
70
+ start: turningPoint,
71
+ lastPosition: currentPosition
72
+ };
73
+ } else {
74
+ this.scrollState.lastPosition = currentPosition;
75
+ }
76
+ if (this.scrollDebounceTimer !== void 0) {
77
+ window.clearTimeout(this.scrollDebounceTimer);
78
+ }
79
+ this.scrollDebounceTimer = window.setTimeout(
80
+ () => this.flushPendingScroll(),
81
+ this.scrollDebounceInterval
82
+ );
83
+ }
84
+ /**
85
+ * Determines whether the scroll direction has reversed on either axis.
86
+ *
87
+ * It compares two vectors:
88
+ * - The scroll direction: the overall direction from start to the previous position (start -> previous)
89
+ * - The movement direction: the direction of the latest movement (previous -> current)
90
+ *
91
+ * A reversal is detected when these two vectors point in opposite directions on the same axis.
92
+ * Axes with no movement (sign = 0) are ignored, so scrolling that simply stops on one axis
93
+ * without reversing does not trigger a flush.
94
+ *
95
+ * Example of vertical reversal:
96
+ * start = {y: 0}, previous = {y: 500}, current = {y: 400}
97
+ * scrollDirectionY = sign(500 - 0) = +1 (downward)
98
+ * movementDirectionY = sign(400 - 500) = -1 (upward)
99
+ * +1 !== -1 => reversed
100
+ *
101
+ * Example of no reversal (same direction):
102
+ * start = {y: 0}, previous = {y: 200}, current = {y: 500}
103
+ * scrollDirectionY = sign(200 - 0) = +1 (downward)
104
+ * movementDirectionY = sign(500 - 200) = +1 (downward)
105
+ * +1 === +1 => not reversed
106
+ *
107
+ * Example of horizontal stop ignored:
108
+ * start = {x: 0}, previous = {x: 300}, current = {x: 300}
109
+ * scrollDirectionX = sign(300 - 0) = +1
110
+ * movementDirectionX = sign(300 - 300) = 0 (no movement)
111
+ * movementDirectionX is 0 => ignored, not a reversal
112
+ */
113
+ hasDirectionChanged(state, current) {
114
+ const { start, lastPosition: previous } = state;
115
+ const scrollDirectionX = Math.sign(previous.x - start.x);
116
+ const scrollDirectionY = Math.sign(previous.y - start.y);
117
+ const movementDirectionX = Math.sign(current.x - previous.x);
118
+ const movementDirectionY = Math.sign(current.y - previous.y);
119
+ return scrollDirectionX !== 0 && movementDirectionX !== 0 && scrollDirectionX !== movementDirectionX || scrollDirectionY !== 0 && movementDirectionY !== 0 && scrollDirectionY !== movementDirectionY;
120
+ }
121
+ flushPendingScroll(end) {
122
+ if (this.scrollDebounceTimer !== void 0) {
123
+ window.clearTimeout(this.scrollDebounceTimer);
124
+ this.scrollDebounceTimer = void 0;
125
+ }
126
+ if (this.scrollState === void 0) {
127
+ return;
128
+ }
129
+ const { start } = this.scrollState;
130
+ const destination = end ?? {
131
+ x: Math.max(0, Math.round(window.scrollX)),
132
+ y: Math.max(0, Math.round(window.scrollY))
133
+ };
134
+ this.scrollState = void 0;
135
+ if (start.x === destination.x && start.y === destination.y) {
136
+ return;
137
+ }
138
+ this.eventManager.dispatch("userScrolled", {
139
+ type: "userScrolled",
140
+ start,
141
+ end: destination,
142
+ surfaceSize: {
143
+ width: document.documentElement.scrollWidth,
144
+ height: document.documentElement.scrollHeight
145
+ },
146
+ // Uses clientWidth/clientHeight instead of innerWidth/innerHeight to get the
147
+ // layout viewport size, which remains stable regardless of pinch-to-zoom level
148
+ // on mobile devices.
149
+ viewportSize: {
150
+ width: document.documentElement.clientWidth,
151
+ height: document.documentElement.clientHeight
152
+ }
153
+ });
154
+ }
155
+ }
156
+ export {
157
+ InteractionMonitor
158
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@croct/sdk",
3
- "version": "0.21.1",
3
+ "version": "0.22.0",
4
4
  "description": "Croct SDK for JavaScript.",
5
5
  "license": "MIT",
6
6
  "author": {
@@ -28,6 +28,8 @@ __export(eventSchemas_exports, {
28
28
  orderPlaced: () => orderPlaced,
29
29
  postViewed: () => postViewed,
30
30
  productViewed: () => productViewed,
31
+ userClicked: () => userClicked,
32
+ userScrolled: () => userScrolled,
31
33
  userSignedUp: () => userSignedUp
32
34
  });
33
35
  module.exports = __toCommonJS(eventSchemas_exports);
@@ -146,6 +148,48 @@ const eventOccurred = new import_validation.ObjectType({
146
148
  })
147
149
  }
148
150
  });
151
+ const point = new import_validation.ObjectType({
152
+ required: ["x", "y"],
153
+ properties: {
154
+ x: new import_validation.NumberType({
155
+ integer: true,
156
+ minimum: 0
157
+ }),
158
+ y: new import_validation.NumberType({
159
+ integer: true,
160
+ minimum: 0
161
+ })
162
+ }
163
+ });
164
+ const size = new import_validation.ObjectType({
165
+ required: ["width", "height"],
166
+ properties: {
167
+ width: new import_validation.NumberType({
168
+ integer: true,
169
+ minimum: 0
170
+ }),
171
+ height: new import_validation.NumberType({
172
+ integer: true,
173
+ minimum: 0
174
+ })
175
+ }
176
+ });
177
+ const userClicked = new import_validation.ObjectType({
178
+ required: ["point"],
179
+ properties: {
180
+ point,
181
+ surfaceSize: size
182
+ }
183
+ });
184
+ const userScrolled = new import_validation.ObjectType({
185
+ required: ["end"],
186
+ properties: {
187
+ start: point,
188
+ end: point,
189
+ surfaceSize: size,
190
+ viewportSize: size
191
+ }
192
+ });
149
193
  const leadGenerated = new import_validation.ObjectType({
150
194
  properties: {
151
195
  leadId: new import_validation.StringType({
@@ -175,5 +219,7 @@ const leadGenerated = new import_validation.ObjectType({
175
219
  orderPlaced,
176
220
  postViewed,
177
221
  productViewed,
222
+ userClicked,
223
+ userScrolled,
178
224
  userSignedUp
179
225
  });
@@ -12,6 +12,8 @@ declare const interestShown: ObjectType;
12
12
  declare const postViewed: ObjectType;
13
13
  declare const linkOpened: ObjectType;
14
14
  declare const eventOccurred: ObjectType;
15
+ declare const userClicked: ObjectType;
16
+ declare const userScrolled: ObjectType;
15
17
  declare const leadGenerated: ObjectType;
16
18
 
17
- export { cartModified, cartViewed, checkoutStarted, eventOccurred, goalCompleted, interestShown, leadGenerated, linkOpened, orderPlaced, postViewed, productViewed, userSignedUp };
19
+ export { cartModified, cartViewed, checkoutStarted, eventOccurred, goalCompleted, interestShown, leadGenerated, linkOpened, orderPlaced, postViewed, productViewed, userClicked, userScrolled, userSignedUp };
@@ -12,6 +12,8 @@ declare const interestShown: ObjectType;
12
12
  declare const postViewed: ObjectType;
13
13
  declare const linkOpened: ObjectType;
14
14
  declare const eventOccurred: ObjectType;
15
+ declare const userClicked: ObjectType;
16
+ declare const userScrolled: ObjectType;
15
17
  declare const leadGenerated: ObjectType;
16
18
 
17
- export { cartModified, cartViewed, checkoutStarted, eventOccurred, goalCompleted, interestShown, leadGenerated, linkOpened, orderPlaced, postViewed, productViewed, userSignedUp };
19
+ export { cartModified, cartViewed, checkoutStarted, eventOccurred, goalCompleted, interestShown, leadGenerated, linkOpened, orderPlaced, postViewed, productViewed, userClicked, userScrolled, userSignedUp };
@@ -121,6 +121,48 @@ const eventOccurred = new ObjectType({
121
121
  })
122
122
  }
123
123
  });
124
+ const point = new ObjectType({
125
+ required: ["x", "y"],
126
+ properties: {
127
+ x: new NumberType({
128
+ integer: true,
129
+ minimum: 0
130
+ }),
131
+ y: new NumberType({
132
+ integer: true,
133
+ minimum: 0
134
+ })
135
+ }
136
+ });
137
+ const size = new ObjectType({
138
+ required: ["width", "height"],
139
+ properties: {
140
+ width: new NumberType({
141
+ integer: true,
142
+ minimum: 0
143
+ }),
144
+ height: new NumberType({
145
+ integer: true,
146
+ minimum: 0
147
+ })
148
+ }
149
+ });
150
+ const userClicked = new ObjectType({
151
+ required: ["point"],
152
+ properties: {
153
+ point,
154
+ surfaceSize: size
155
+ }
156
+ });
157
+ const userScrolled = new ObjectType({
158
+ required: ["end"],
159
+ properties: {
160
+ start: point,
161
+ end: point,
162
+ surfaceSize: size,
163
+ viewportSize: size
164
+ }
165
+ });
124
166
  const leadGenerated = new ObjectType({
125
167
  properties: {
126
168
  leadId: new StringType({
@@ -149,5 +191,7 @@ export {
149
191
  orderPlaced,
150
192
  postViewed,
151
193
  productViewed,
194
+ userClicked,
195
+ userScrolled,
152
196
  userSignedUp
153
197
  };
@@ -2,7 +2,7 @@ export { tokenScopeSchema } from './contextSchemas.cjs';
2
2
  export { cart, cartItem, order, orderItem, productDetails } from './ecommerceSchemas.cjs';
3
3
  export { evaluationOptionsSchema } from './evaluatorSchemas.cjs';
4
4
  export { fetchOptionsSchema } from './contentFetcherSchemas.cjs';
5
- export { cartModified, cartViewed, checkoutStarted, eventOccurred, goalCompleted, interestShown, leadGenerated, linkOpened, orderPlaced, postViewed, productViewed, userSignedUp } from './eventSchemas.cjs';
5
+ export { cartModified, cartViewed, checkoutStarted, eventOccurred, goalCompleted, interestShown, leadGenerated, linkOpened, orderPlaced, postViewed, productViewed, userClicked, userScrolled, userSignedUp } from './eventSchemas.cjs';
6
6
  export { loggerSchema } from './loggerSchema.cjs';
7
7
  export { addOperation, clearOperation, combineOperation, decrementOperation, incrementOperation, mergeOperation, removeOperation, setOperation, unsetOperation } from './operationSchemas.cjs';
8
8
  export { sdkFacadeConfigurationSchema } from './sdkFacadeSchemas.cjs';
package/schema/index.d.ts CHANGED
@@ -2,7 +2,7 @@ export { tokenScopeSchema } from './contextSchemas.js';
2
2
  export { cart, cartItem, order, orderItem, productDetails } from './ecommerceSchemas.js';
3
3
  export { evaluationOptionsSchema } from './evaluatorSchemas.js';
4
4
  export { fetchOptionsSchema } from './contentFetcherSchemas.js';
5
- export { cartModified, cartViewed, checkoutStarted, eventOccurred, goalCompleted, interestShown, leadGenerated, linkOpened, orderPlaced, postViewed, productViewed, userSignedUp } from './eventSchemas.js';
5
+ export { cartModified, cartViewed, checkoutStarted, eventOccurred, goalCompleted, interestShown, leadGenerated, linkOpened, orderPlaced, postViewed, productViewed, userClicked, userScrolled, userSignedUp } from './eventSchemas.js';
6
6
  export { loggerSchema } from './loggerSchema.js';
7
7
  export { addOperation, clearOperation, combineOperation, decrementOperation, incrementOperation, mergeOperation, removeOperation, setOperation, unsetOperation } from './operationSchemas.js';
8
8
  export { sdkFacadeConfigurationSchema } from './sdkFacadeSchemas.js';
package/sdk.cjs CHANGED
@@ -83,6 +83,9 @@ class Sdk {
83
83
  const { appId } = this.container.getConfiguration();
84
84
  return appId;
85
85
  }
86
+ get timeZone() {
87
+ return this.container.getTimeZone();
88
+ }
86
89
  get cidAssigner() {
87
90
  return this.container.getCidAssigner();
88
91
  }
package/sdk.d.cts CHANGED
@@ -49,6 +49,7 @@ declare class Sdk {
49
49
  private constructor();
50
50
  static init(configuration: Configuration): Sdk;
51
51
  get appId(): string;
52
+ get timeZone(): string | null;
52
53
  get cidAssigner(): CidAssigner;
53
54
  get previewTokenStore(): TokenStore;
54
55
  get userTokenStore(): TokenStore;
package/sdk.d.ts CHANGED
@@ -49,6 +49,7 @@ declare class Sdk {
49
49
  private constructor();
50
50
  static init(configuration: Configuration): Sdk;
51
51
  get appId(): string;
52
+ get timeZone(): string | null;
52
53
  get cidAssigner(): CidAssigner;
53
54
  get previewTokenStore(): TokenStore;
54
55
  get userTokenStore(): TokenStore;
package/sdk.js CHANGED
@@ -61,6 +61,9 @@ class Sdk {
61
61
  const { appId } = this.container.getConfiguration();
62
62
  return appId;
63
63
  }
64
+ get timeZone() {
65
+ return this.container.getTimeZone();
66
+ }
64
67
  get cidAssigner() {
65
68
  return this.container.getCidAssigner();
66
69
  }
package/tracker.cjs CHANGED
@@ -21,6 +21,7 @@ __export(tracker_exports, {
21
21
  });
22
22
  module.exports = __toCommonJS(tracker_exports);
23
23
  var import_logging = require('./logging/index.cjs');
24
+ var import_interactionMonitor = require('./interactionMonitor.cjs');
24
25
  var import_error = require('./error.cjs');
25
26
  var import_trackingEvents = require('./trackingEvents.cjs');
26
27
  const trackedEvents = {};
@@ -36,16 +37,20 @@ class Tracker {
36
37
  this.inactivityTimer = {
37
38
  since: 0
38
39
  };
39
- const { tab, tokenProvider, channel, logger, inactivityRetryPolicy, ...options } = config;
40
+ const { tab, tokenProvider, channel, logger, inactivityRetryPolicy, timeZone, ...options } = config;
40
41
  this.tab = tab;
41
42
  this.tokenProvider = tokenProvider;
42
43
  this.inactivityRetryPolicy = inactivityRetryPolicy;
43
44
  this.channel = channel;
45
+ this.timeZone = timeZone;
44
46
  this.logger = logger ?? new import_logging.NullLogger();
45
47
  this.options = {
46
48
  ...options,
47
49
  eventMetadata: options.eventMetadata ?? {}
48
50
  };
51
+ this.interactionMonitor = new import_interactionMonitor.InteractionMonitor();
52
+ this.interactionMonitor.addListener("userClicked", (event) => this.enqueue(event));
53
+ this.interactionMonitor.addListener("userScrolled", (event) => this.enqueue(event));
49
54
  this.enable = this.enable.bind(this);
50
55
  this.disable = this.disable.bind(this);
51
56
  this.suspend = this.suspend.bind(this);
@@ -93,6 +98,7 @@ class Tracker {
93
98
  this.tab.addListener("load", this.trackPageLoad);
94
99
  this.tab.addListener("urlChange", this.trackTabUrlChange);
95
100
  this.tab.addListener("visibilityChange", this.trackTabVisibilityChange);
101
+ this.interactionMonitor.enable();
96
102
  }
97
103
  disable() {
98
104
  if (!this.state.enabled) {
@@ -103,6 +109,7 @@ class Tracker {
103
109
  if (this.state.suspended) {
104
110
  return;
105
111
  }
112
+ this.interactionMonitor.disable();
106
113
  this.tab.removeListener("load", this.trackPageLoad);
107
114
  this.tab.removeListener("urlChange", this.trackTabUrlChange);
108
115
  this.tab.removeListener("visibilityChange", this.trackTabVisibilityChange);
@@ -231,6 +238,7 @@ class Tracker {
231
238
  const context = {
232
239
  tabId: this.tab.id,
233
240
  url: this.tab.url,
241
+ ...this.timeZone !== void 0 ? { timeZone: this.timeZone } : {},
234
242
  ...Object.keys(metadata).length > 0 ? { metadata } : {}
235
243
  };
236
244
  return this.publish({
package/tracker.d.cts CHANGED
@@ -23,6 +23,7 @@ type Configuration = Options & {
23
23
  channel: OutputChannel<Beacon>;
24
24
  logger?: Logger;
25
25
  tab: Tab;
26
+ timeZone?: string;
26
27
  tokenProvider: TokenProvider;
27
28
  inactivityRetryPolicy: RetryPolicy<number>;
28
29
  };
@@ -42,11 +43,13 @@ declare class Tracker {
42
43
  private tab;
43
44
  private tokenProvider;
44
45
  private inactivityRetryPolicy;
46
+ private readonly timeZone?;
45
47
  private readonly channel;
46
48
  private readonly logger;
47
49
  private readonly listeners;
48
50
  private readonly pending;
49
51
  private readonly state;
52
+ private readonly interactionMonitor;
50
53
  private readonly inactivityTimer;
51
54
  constructor(config: Configuration);
52
55
  addListener(listener: EventListener): void;
package/tracker.d.ts CHANGED
@@ -23,6 +23,7 @@ type Configuration = Options & {
23
23
  channel: OutputChannel<Beacon>;
24
24
  logger?: Logger;
25
25
  tab: Tab;
26
+ timeZone?: string;
26
27
  tokenProvider: TokenProvider;
27
28
  inactivityRetryPolicy: RetryPolicy<number>;
28
29
  };
@@ -42,11 +43,13 @@ declare class Tracker {
42
43
  private tab;
43
44
  private tokenProvider;
44
45
  private inactivityRetryPolicy;
46
+ private readonly timeZone?;
45
47
  private readonly channel;
46
48
  private readonly logger;
47
49
  private readonly listeners;
48
50
  private readonly pending;
49
51
  private readonly state;
52
+ private readonly interactionMonitor;
50
53
  private readonly inactivityTimer;
51
54
  constructor(config: Configuration);
52
55
  addListener(listener: EventListener): void;
package/tracker.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { NullLogger } from "./logging/index.js";
2
+ import { InteractionMonitor } from "./interactionMonitor.js";
2
3
  import { formatCause } from "./error.js";
3
4
  import { isCartPartialEvent, isIdentifiedUserEvent } from "./trackingEvents.js";
4
5
  const trackedEvents = {};
@@ -14,16 +15,20 @@ class Tracker {
14
15
  this.inactivityTimer = {
15
16
  since: 0
16
17
  };
17
- const { tab, tokenProvider, channel, logger, inactivityRetryPolicy, ...options } = config;
18
+ const { tab, tokenProvider, channel, logger, inactivityRetryPolicy, timeZone, ...options } = config;
18
19
  this.tab = tab;
19
20
  this.tokenProvider = tokenProvider;
20
21
  this.inactivityRetryPolicy = inactivityRetryPolicy;
21
22
  this.channel = channel;
23
+ this.timeZone = timeZone;
22
24
  this.logger = logger ?? new NullLogger();
23
25
  this.options = {
24
26
  ...options,
25
27
  eventMetadata: options.eventMetadata ?? {}
26
28
  };
29
+ this.interactionMonitor = new InteractionMonitor();
30
+ this.interactionMonitor.addListener("userClicked", (event) => this.enqueue(event));
31
+ this.interactionMonitor.addListener("userScrolled", (event) => this.enqueue(event));
27
32
  this.enable = this.enable.bind(this);
28
33
  this.disable = this.disable.bind(this);
29
34
  this.suspend = this.suspend.bind(this);
@@ -71,6 +76,7 @@ class Tracker {
71
76
  this.tab.addListener("load", this.trackPageLoad);
72
77
  this.tab.addListener("urlChange", this.trackTabUrlChange);
73
78
  this.tab.addListener("visibilityChange", this.trackTabVisibilityChange);
79
+ this.interactionMonitor.enable();
74
80
  }
75
81
  disable() {
76
82
  if (!this.state.enabled) {
@@ -81,6 +87,7 @@ class Tracker {
81
87
  if (this.state.suspended) {
82
88
  return;
83
89
  }
90
+ this.interactionMonitor.disable();
84
91
  this.tab.removeListener("load", this.trackPageLoad);
85
92
  this.tab.removeListener("urlChange", this.trackTabUrlChange);
86
93
  this.tab.removeListener("visibilityChange", this.trackTabVisibilityChange);
@@ -209,6 +216,7 @@ class Tracker {
209
216
  const context = {
210
217
  tabId: this.tab.id,
211
218
  url: this.tab.url,
219
+ ...this.timeZone !== void 0 ? { timeZone: this.timeZone } : {},
212
220
  ...Object.keys(metadata).length > 0 ? { metadata } : {}
213
221
  };
214
222
  return this.publish({
@@ -21,6 +21,7 @@ __export(trackingEvents_exports, {
21
21
  ecommerceEventTypes: () => ecommerceEventTypes,
22
22
  eventTypes: () => eventTypes,
23
23
  identifiedUserEventTypes: () => identifiedUserEventTypes,
24
+ interactionEventTypes: () => interactionEventTypes,
24
25
  isCartPartialEvent: () => isCartPartialEvent,
25
26
  isIdentifiedUserEvent: () => isIdentifiedUserEvent,
26
27
  miscEventTypes: () => miscEventTypes,
@@ -57,6 +58,10 @@ const userEventTypes = [
57
58
  ...identifiedUserEventTypes,
58
59
  "userProfileChanged"
59
60
  ];
61
+ const interactionEventTypes = [
62
+ "userClicked",
63
+ "userScrolled"
64
+ ];
60
65
  const miscEventTypes = [
61
66
  "nothingChanged",
62
67
  "sessionAttributesChanged",
@@ -71,6 +76,7 @@ const eventTypes = [
71
76
  ...pageEventTypes,
72
77
  ...ecommerceEventTypes,
73
78
  ...userEventTypes,
79
+ ...interactionEventTypes,
74
80
  ...miscEventTypes
75
81
  ];
76
82
  function isIdentifiedUserEvent(event) {
@@ -85,6 +91,7 @@ function isCartPartialEvent(event) {
85
91
  ecommerceEventTypes,
86
92
  eventTypes,
87
93
  identifiedUserEventTypes,
94
+ interactionEventTypes,
88
95
  isCartPartialEvent,
89
96
  isIdentifiedUserEvent,
90
97
  miscEventTypes,
@@ -67,6 +67,14 @@ type Order = {
67
67
  installments?: number;
68
68
  status?: OrderStatus;
69
69
  };
70
+ type Point = {
71
+ x: number;
72
+ y: number;
73
+ };
74
+ type Size = {
75
+ width: number;
76
+ height: number;
77
+ };
70
78
  type Gender = 'male' | 'female' | 'neutral' | 'unknown';
71
79
  declare const pageEventTypes: readonly ["pageLoaded", "pageOpened"];
72
80
  declare const tabEventTypes: readonly ["tabOpened", "tabUrlChanged", "tabVisibilityChanged"];
@@ -74,8 +82,9 @@ declare const cartEventTypes: readonly ["cartModified", "cartViewed", "checkoutS
74
82
  declare const ecommerceEventTypes: readonly ["cartModified", "cartViewed", "checkoutStarted", "orderPlaced", "productViewed"];
75
83
  declare const identifiedUserEventTypes: string[];
76
84
  declare const userEventTypes: readonly [...string[], "userProfileChanged"];
85
+ declare const interactionEventTypes: readonly ["userClicked", "userScrolled"];
77
86
  declare const miscEventTypes: readonly ["nothingChanged", "sessionAttributesChanged", "goalCompleted", "interestShown", "postViewed", "eventOccurred", "linkOpened", "leadGenerated"];
78
- declare const eventTypes: readonly ["pageLoaded", "pageOpened", "cartModified", "cartViewed", "checkoutStarted", "orderPlaced", "productViewed", ...string[], "userProfileChanged", "nothingChanged", "sessionAttributesChanged", "goalCompleted", "interestShown", "postViewed", "eventOccurred", "linkOpened", "leadGenerated"];
87
+ declare const eventTypes: readonly ["pageLoaded", "pageOpened", "cartModified", "cartViewed", "checkoutStarted", "orderPlaced", "productViewed", ...string[], "userProfileChanged", "userClicked", "userScrolled", "nothingChanged", "sessionAttributesChanged", "goalCompleted", "interestShown", "postViewed", "eventOccurred", "linkOpened", "leadGenerated"];
79
88
  interface BaseEvent {
80
89
  type: string;
81
90
  }
@@ -195,6 +204,19 @@ interface PageLoaded extends BasePageEvent {
195
204
  lastModifiedTime: number;
196
205
  }
197
206
  type PageEvent = PageLoaded | PageOpened;
207
+ interface UserClicked extends BaseEvent {
208
+ type: 'userClicked';
209
+ point: Point;
210
+ surfaceSize?: Size;
211
+ }
212
+ interface UserScrolled extends BaseEvent {
213
+ type: 'userScrolled';
214
+ start?: Point;
215
+ end: Point;
216
+ surfaceSize?: Size;
217
+ viewportSize?: Size;
218
+ }
219
+ type InteractionEvent = UserClicked | UserScrolled;
198
220
  interface NothingChanged extends BaseEvent {
199
221
  type: 'nothingChanged';
200
222
  sinceTime: number;
@@ -256,6 +278,8 @@ type EventMap = {
256
278
  userSignedOut: UserSignedOut;
257
279
  userSignedUp: UserSignedUp;
258
280
  userProfileChanged: UserProfileChanged;
281
+ userClicked: UserClicked;
282
+ userScrolled: UserScrolled;
259
283
  productViewed: ProductViewed;
260
284
  cartViewed: CartViewed;
261
285
  cartModified: CartModified;
@@ -302,6 +326,7 @@ declare function isCartPartialEvent(event: PartialTrackingEvent): event is CartP
302
326
  type TrackingEventContext = {
303
327
  tabId: string;
304
328
  url: string;
329
+ timeZone?: string;
305
330
  metadata?: {
306
331
  [key: string]: string;
307
332
  };
@@ -318,4 +343,4 @@ type Beacon = {
318
343
  payload: BeaconPayload;
319
344
  };
320
345
 
321
- export { type Beacon, type BeaconPayload, type Cart, type CartEvent, type CartEventType, type CartItem, type CartModified, type CartViewed, type CheckoutStarted, type EcommerceEvent, type EventOccurred, type ExternalTrackingEvent, type ExternalTrackingEventPayload, type ExternalTrackingEventType, type Gender, type GoalCompleted, type IdentifiedUserEvent, type InterestShown, type LeadGenerated, type LinkOpened, type MiscEvent, type NothingChanged, type Order, type OrderItem, type OrderPlaced, type OrderStatus, type PageEvent, type PageEventType, type PageLoaded, type PageOpened, type PartialTrackingEvent, type PostDetails, type PostViewed, type ProductDetails, type ProductViewed, type SessionAttributesChanged, type TabEvent, type TabEventType, type TabOpened, type TabUrlChanged, type TabVisibilityChanged, type TrackingEvent, type TrackingEventContext, type TrackingEventType, type UserEvent, type UserProfile, type UserProfileChanged, type UserSignedIn, type UserSignedOut, type UserSignedUp, cartEventTypes, ecommerceEventTypes, eventTypes, identifiedUserEventTypes, isCartPartialEvent, isIdentifiedUserEvent, miscEventTypes, pageEventTypes, tabEventTypes, userEventTypes };
346
+ export { type Beacon, type BeaconPayload, type Cart, type CartEvent, type CartEventType, type CartItem, type CartModified, type CartViewed, type CheckoutStarted, type EcommerceEvent, type EventOccurred, type ExternalTrackingEvent, type ExternalTrackingEventPayload, type ExternalTrackingEventType, type Gender, type GoalCompleted, type IdentifiedUserEvent, type InteractionEvent, type InterestShown, type LeadGenerated, type LinkOpened, type MiscEvent, type NothingChanged, type Order, type OrderItem, type OrderPlaced, type OrderStatus, type PageEvent, type PageEventType, type PageLoaded, type PageOpened, type PartialTrackingEvent, type Point, type PostDetails, type PostViewed, type ProductDetails, type ProductViewed, type SessionAttributesChanged, type Size, type TabEvent, type TabEventType, type TabOpened, type TabUrlChanged, type TabVisibilityChanged, type TrackingEvent, type TrackingEventContext, type TrackingEventType, type UserClicked, type UserEvent, type UserProfile, type UserProfileChanged, type UserScrolled, type UserSignedIn, type UserSignedOut, type UserSignedUp, cartEventTypes, ecommerceEventTypes, eventTypes, identifiedUserEventTypes, interactionEventTypes, isCartPartialEvent, isIdentifiedUserEvent, miscEventTypes, pageEventTypes, tabEventTypes, userEventTypes };
@@ -67,6 +67,14 @@ type Order = {
67
67
  installments?: number;
68
68
  status?: OrderStatus;
69
69
  };
70
+ type Point = {
71
+ x: number;
72
+ y: number;
73
+ };
74
+ type Size = {
75
+ width: number;
76
+ height: number;
77
+ };
70
78
  type Gender = 'male' | 'female' | 'neutral' | 'unknown';
71
79
  declare const pageEventTypes: readonly ["pageLoaded", "pageOpened"];
72
80
  declare const tabEventTypes: readonly ["tabOpened", "tabUrlChanged", "tabVisibilityChanged"];
@@ -74,8 +82,9 @@ declare const cartEventTypes: readonly ["cartModified", "cartViewed", "checkoutS
74
82
  declare const ecommerceEventTypes: readonly ["cartModified", "cartViewed", "checkoutStarted", "orderPlaced", "productViewed"];
75
83
  declare const identifiedUserEventTypes: string[];
76
84
  declare const userEventTypes: readonly [...string[], "userProfileChanged"];
85
+ declare const interactionEventTypes: readonly ["userClicked", "userScrolled"];
77
86
  declare const miscEventTypes: readonly ["nothingChanged", "sessionAttributesChanged", "goalCompleted", "interestShown", "postViewed", "eventOccurred", "linkOpened", "leadGenerated"];
78
- declare const eventTypes: readonly ["pageLoaded", "pageOpened", "cartModified", "cartViewed", "checkoutStarted", "orderPlaced", "productViewed", ...string[], "userProfileChanged", "nothingChanged", "sessionAttributesChanged", "goalCompleted", "interestShown", "postViewed", "eventOccurred", "linkOpened", "leadGenerated"];
87
+ declare const eventTypes: readonly ["pageLoaded", "pageOpened", "cartModified", "cartViewed", "checkoutStarted", "orderPlaced", "productViewed", ...string[], "userProfileChanged", "userClicked", "userScrolled", "nothingChanged", "sessionAttributesChanged", "goalCompleted", "interestShown", "postViewed", "eventOccurred", "linkOpened", "leadGenerated"];
79
88
  interface BaseEvent {
80
89
  type: string;
81
90
  }
@@ -195,6 +204,19 @@ interface PageLoaded extends BasePageEvent {
195
204
  lastModifiedTime: number;
196
205
  }
197
206
  type PageEvent = PageLoaded | PageOpened;
207
+ interface UserClicked extends BaseEvent {
208
+ type: 'userClicked';
209
+ point: Point;
210
+ surfaceSize?: Size;
211
+ }
212
+ interface UserScrolled extends BaseEvent {
213
+ type: 'userScrolled';
214
+ start?: Point;
215
+ end: Point;
216
+ surfaceSize?: Size;
217
+ viewportSize?: Size;
218
+ }
219
+ type InteractionEvent = UserClicked | UserScrolled;
198
220
  interface NothingChanged extends BaseEvent {
199
221
  type: 'nothingChanged';
200
222
  sinceTime: number;
@@ -256,6 +278,8 @@ type EventMap = {
256
278
  userSignedOut: UserSignedOut;
257
279
  userSignedUp: UserSignedUp;
258
280
  userProfileChanged: UserProfileChanged;
281
+ userClicked: UserClicked;
282
+ userScrolled: UserScrolled;
259
283
  productViewed: ProductViewed;
260
284
  cartViewed: CartViewed;
261
285
  cartModified: CartModified;
@@ -302,6 +326,7 @@ declare function isCartPartialEvent(event: PartialTrackingEvent): event is CartP
302
326
  type TrackingEventContext = {
303
327
  tabId: string;
304
328
  url: string;
329
+ timeZone?: string;
305
330
  metadata?: {
306
331
  [key: string]: string;
307
332
  };
@@ -318,4 +343,4 @@ type Beacon = {
318
343
  payload: BeaconPayload;
319
344
  };
320
345
 
321
- export { type Beacon, type BeaconPayload, type Cart, type CartEvent, type CartEventType, type CartItem, type CartModified, type CartViewed, type CheckoutStarted, type EcommerceEvent, type EventOccurred, type ExternalTrackingEvent, type ExternalTrackingEventPayload, type ExternalTrackingEventType, type Gender, type GoalCompleted, type IdentifiedUserEvent, type InterestShown, type LeadGenerated, type LinkOpened, type MiscEvent, type NothingChanged, type Order, type OrderItem, type OrderPlaced, type OrderStatus, type PageEvent, type PageEventType, type PageLoaded, type PageOpened, type PartialTrackingEvent, type PostDetails, type PostViewed, type ProductDetails, type ProductViewed, type SessionAttributesChanged, type TabEvent, type TabEventType, type TabOpened, type TabUrlChanged, type TabVisibilityChanged, type TrackingEvent, type TrackingEventContext, type TrackingEventType, type UserEvent, type UserProfile, type UserProfileChanged, type UserSignedIn, type UserSignedOut, type UserSignedUp, cartEventTypes, ecommerceEventTypes, eventTypes, identifiedUserEventTypes, isCartPartialEvent, isIdentifiedUserEvent, miscEventTypes, pageEventTypes, tabEventTypes, userEventTypes };
346
+ export { type Beacon, type BeaconPayload, type Cart, type CartEvent, type CartEventType, type CartItem, type CartModified, type CartViewed, type CheckoutStarted, type EcommerceEvent, type EventOccurred, type ExternalTrackingEvent, type ExternalTrackingEventPayload, type ExternalTrackingEventType, type Gender, type GoalCompleted, type IdentifiedUserEvent, type InteractionEvent, type InterestShown, type LeadGenerated, type LinkOpened, type MiscEvent, type NothingChanged, type Order, type OrderItem, type OrderPlaced, type OrderStatus, type PageEvent, type PageEventType, type PageLoaded, type PageOpened, type PartialTrackingEvent, type Point, type PostDetails, type PostViewed, type ProductDetails, type ProductViewed, type SessionAttributesChanged, type Size, type TabEvent, type TabEventType, type TabOpened, type TabUrlChanged, type TabVisibilityChanged, type TrackingEvent, type TrackingEventContext, type TrackingEventType, type UserClicked, type UserEvent, type UserProfile, type UserProfileChanged, type UserScrolled, type UserSignedIn, type UserSignedOut, type UserSignedUp, cartEventTypes, ecommerceEventTypes, eventTypes, identifiedUserEventTypes, interactionEventTypes, isCartPartialEvent, isIdentifiedUserEvent, miscEventTypes, pageEventTypes, tabEventTypes, userEventTypes };
package/trackingEvents.js CHANGED
@@ -26,6 +26,10 @@ const userEventTypes = [
26
26
  ...identifiedUserEventTypes,
27
27
  "userProfileChanged"
28
28
  ];
29
+ const interactionEventTypes = [
30
+ "userClicked",
31
+ "userScrolled"
32
+ ];
29
33
  const miscEventTypes = [
30
34
  "nothingChanged",
31
35
  "sessionAttributesChanged",
@@ -40,6 +44,7 @@ const eventTypes = [
40
44
  ...pageEventTypes,
41
45
  ...ecommerceEventTypes,
42
46
  ...userEventTypes,
47
+ ...interactionEventTypes,
43
48
  ...miscEventTypes
44
49
  ];
45
50
  function isIdentifiedUserEvent(event) {
@@ -53,6 +58,7 @@ export {
53
58
  ecommerceEventTypes,
54
59
  eventTypes,
55
60
  identifiedUserEventTypes,
61
+ interactionEventTypes,
56
62
  isCartPartialEvent,
57
63
  isIdentifiedUserEvent,
58
64
  miscEventTypes,