clarity-js 0.8.10-beta → 0.8.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. package/.lintstagedrc.yml +3 -0
  2. package/biome.json +43 -0
  3. package/build/clarity.extended.js +1 -1
  4. package/build/clarity.insight.js +1 -1
  5. package/build/clarity.js +3581 -3019
  6. package/build/clarity.min.js +1 -1
  7. package/build/clarity.module.js +3581 -3019
  8. package/build/clarity.performance.js +1 -1
  9. package/package.json +17 -10
  10. package/rollup.config.ts +84 -88
  11. package/src/clarity.ts +34 -28
  12. package/src/core/config.ts +2 -2
  13. package/src/core/event.ts +36 -32
  14. package/src/core/hash.ts +5 -6
  15. package/src/core/history.ts +10 -11
  16. package/src/core/index.ts +21 -11
  17. package/src/core/measure.ts +9 -5
  18. package/src/core/report.ts +9 -5
  19. package/src/core/scrub.ts +29 -20
  20. package/src/core/task.ts +73 -45
  21. package/src/core/time.ts +3 -3
  22. package/src/core/timeout.ts +2 -2
  23. package/src/core/version.ts +1 -1
  24. package/src/data/baseline.ts +60 -55
  25. package/src/data/consent.ts +2 -2
  26. package/src/data/custom.ts +8 -13
  27. package/src/data/dimension.ts +11 -7
  28. package/src/data/encode.ts +36 -30
  29. package/src/data/envelope.ts +38 -38
  30. package/src/data/extract.ts +86 -77
  31. package/src/data/index.ts +10 -6
  32. package/src/data/limit.ts +1 -1
  33. package/src/data/metadata.ts +305 -266
  34. package/src/data/metric.ts +18 -8
  35. package/src/data/ping.ts +8 -4
  36. package/src/data/signal.ts +18 -18
  37. package/src/data/summary.ts +6 -4
  38. package/src/data/token.ts +10 -8
  39. package/src/data/upgrade.ts +7 -3
  40. package/src/data/upload.ts +100 -49
  41. package/src/data/variable.ts +27 -20
  42. package/src/diagnostic/encode.ts +2 -2
  43. package/src/diagnostic/fraud.ts +3 -4
  44. package/src/diagnostic/internal.ts +11 -5
  45. package/src/diagnostic/script.ts +12 -8
  46. package/src/global.ts +1 -1
  47. package/src/insight/blank.ts +4 -4
  48. package/src/insight/encode.ts +23 -17
  49. package/src/insight/snapshot.ts +57 -37
  50. package/src/interaction/change.ts +9 -6
  51. package/src/interaction/click.ts +34 -28
  52. package/src/interaction/clipboard.ts +2 -2
  53. package/src/interaction/encode.ts +35 -31
  54. package/src/interaction/input.ts +11 -9
  55. package/src/interaction/pointer.ts +41 -30
  56. package/src/interaction/resize.ts +5 -5
  57. package/src/interaction/scroll.ts +20 -17
  58. package/src/interaction/selection.ts +12 -8
  59. package/src/interaction/submit.ts +2 -2
  60. package/src/interaction/timeline.ts +13 -9
  61. package/src/interaction/unload.ts +1 -1
  62. package/src/interaction/visibility.ts +2 -2
  63. package/src/layout/animation.ts +47 -41
  64. package/src/layout/discover.ts +5 -5
  65. package/src/layout/document.ts +31 -19
  66. package/src/layout/dom.ts +141 -91
  67. package/src/layout/encode.ts +52 -37
  68. package/src/layout/mutation.ts +321 -318
  69. package/src/layout/node.ts +104 -81
  70. package/src/layout/offset.ts +7 -6
  71. package/src/layout/region.ts +66 -43
  72. package/src/layout/schema.ts +15 -8
  73. package/src/layout/selector.ts +47 -25
  74. package/src/layout/style.ts +44 -36
  75. package/src/layout/target.ts +14 -10
  76. package/src/layout/traverse.ts +17 -11
  77. package/src/performance/blank.ts +1 -1
  78. package/src/performance/encode.ts +4 -4
  79. package/src/performance/interaction.ts +58 -70
  80. package/src/performance/navigation.ts +2 -2
  81. package/src/performance/observer.ts +59 -26
  82. package/src/queue.ts +16 -9
  83. package/tsconfig.json +2 -2
  84. package/tslint.json +25 -32
  85. package/types/core.d.ts +13 -13
  86. package/types/data.d.ts +32 -29
  87. package/types/diagnostic.d.ts +1 -1
  88. package/types/interaction.d.ts +5 -4
  89. package/types/layout.d.ts +36 -21
  90. package/types/performance.d.ts +6 -5
package/src/core/index.ts CHANGED
@@ -1,13 +1,13 @@
1
- import { Config } from "@clarity-types/core";
1
+ import type { Config } from "@clarity-types/core";
2
2
  import { Constant } from "@clarity-types/data";
3
3
  import { FunctionNames } from "@clarity-types/performance";
4
+ import * as clarity from "@src/clarity";
4
5
  import configuration from "@src/core/config";
5
6
  import * as event from "@src/core/event";
6
7
  import * as history from "@src/core/history";
7
8
  import * as report from "@src/core/report";
8
9
  import * as task from "@src/core/task";
9
10
  import * as time from "@src/core/time";
10
- import * as clarity from "@src/clarity";
11
11
  import * as custom from "@src/data/custom";
12
12
 
13
13
  let status = false;
@@ -36,15 +36,17 @@ export function active(): boolean {
36
36
 
37
37
  export function check(): boolean {
38
38
  try {
39
- let globalPrivacyControlSet = navigator && "globalPrivacyControl" in navigator && navigator['globalPrivacyControl'] == true;
40
- return status === false &&
39
+ const globalPrivacyControlSet = navigator && "globalPrivacyControl" in navigator && navigator.globalPrivacyControl === true;
40
+ return (
41
+ status === false &&
41
42
  typeof Promise !== "undefined" &&
42
- window["MutationObserver"] &&
43
- document["createTreeWalker"] &&
43
+ window.MutationObserver &&
44
+ document.createTreeWalker &&
44
45
  "now" in Date &&
45
46
  "now" in performance &&
46
47
  typeof WeakMap !== "undefined" &&
47
48
  !globalPrivacyControlSet
49
+ );
48
50
  } catch (ex) {
49
51
  return false;
50
52
  }
@@ -52,9 +54,13 @@ export function check(): boolean {
52
54
 
53
55
  export function config(override: Config): boolean {
54
56
  // Process custom configuration overrides, if available
55
- if (override === null || status) { return false; }
56
- for (let key in override) {
57
- if (key in configuration) { configuration[key] = override[key]; }
57
+ if (override === null || status) {
58
+ return false;
59
+ }
60
+ for (const key in override) {
61
+ if (key in configuration) {
62
+ configuration[key] = override[key];
63
+ }
58
64
  }
59
65
  return true;
60
66
  }
@@ -71,8 +77,12 @@ export function suspend(): void {
71
77
  if (status) {
72
78
  custom.event(Constant.Clarity, Constant.Suspend);
73
79
  clarity.stop();
74
- ["mousemove", "touchstart"].forEach(x => event.bind(document, x, restart));
75
- ["resize", "scroll", "pageshow"].forEach(x => event.bind(window, x, restart));
80
+ for (const x of ["mousemove", "touchstart"]) {
81
+ event.bind(document, x, restart);
82
+ }
83
+ for (const x of ["resize", "scroll", "pageshow"]) {
84
+ event.bind(window, x, restart);
85
+ }
76
86
  }
77
87
  }
78
88
 
@@ -3,12 +3,16 @@ import { report } from "@src/core/report";
3
3
  import * as metric from "@src/data/metric";
4
4
  import * as internal from "@src/diagnostic/internal";
5
5
 
6
- // tslint:disable-next-line: ban-types
6
+ // biome-ignore lint/complexity/noBannedTypes: specifically looking to instrument function calls
7
7
  export default function (method: Function): Function {
8
- return function (): void {
9
- let start = performance.now();
10
- try { method.apply(this, arguments); } catch (ex) { throw report(ex); }
11
- let duration = performance.now() - start;
8
+ return function (...args): void {
9
+ const start = performance.now();
10
+ try {
11
+ method.apply(this, args);
12
+ } catch (ex) {
13
+ throw report(ex);
14
+ }
15
+ const duration = performance.now() - start;
12
16
  metric.sum(Metric.TotalCost, duration);
13
17
  if (duration > Setting.LongTask) {
14
18
  metric.count(Metric.LongTaskCount);
@@ -1,4 +1,4 @@
1
- import { Report } from "@clarity-types/core";
1
+ import type { Report } from "@clarity-types/core";
2
2
  import config from "@src/core/config";
3
3
  import { data } from "@src/data/envelope";
4
4
 
@@ -13,12 +13,16 @@ export function report(e: Error): Error {
13
13
  if (history && history.indexOf(e.message) === -1) {
14
14
  const url = config.report;
15
15
  if (url && url.length > 0) {
16
- let payload: Report = {v: data.version, p: data.projectId, u: data.userId, s: data.sessionId, n: data.pageNum};
17
- if (e.message) { payload.m = e.message; }
18
- if (e.stack) { payload.e = e.stack; }
16
+ const payload: Report = { v: data.version, p: data.projectId, u: data.userId, s: data.sessionId, n: data.pageNum };
17
+ if (e.message) {
18
+ payload.m = e.message;
19
+ }
20
+ if (e.stack) {
21
+ payload.e = e.stack;
22
+ }
19
23
  // Using POST request instead of a GET request (img-src) to not violate existing CSP rules
20
24
  // Since, Clarity already uses XHR to upload data, we stick with similar POST mechanism for reporting too
21
- let xhr = new XMLHttpRequest();
25
+ const xhr = new XMLHttpRequest();
22
26
  xhr.open("POST", url, true);
23
27
  xhr.send(JSON.stringify(payload));
24
28
  history.push(e.message);
package/src/core/scrub.ts CHANGED
@@ -10,9 +10,9 @@ let digitRegex = null;
10
10
  let letterRegex = null;
11
11
  let currencyRegex = null;
12
12
 
13
- export function text(value: string, hint: string, privacy: Privacy, mangle: boolean = false, type?: string): string {
13
+ export function text(value: string, hint: string, privacy: Privacy, mangle = false, type?: string): string {
14
14
  if (value) {
15
- if (hint == "input" && (type === "checkbox" || type === "radio")) {
15
+ if (hint === "input" && (type === "checkbox" || type === "radio")) {
16
16
  return value;
17
17
  }
18
18
 
@@ -88,17 +88,21 @@ export function text(value: string, hint: string, privacy: Privacy, mangle: bool
88
88
  return value;
89
89
  }
90
90
 
91
- export function url(input: string, electron: boolean = false, truncate: boolean = false): string {
91
+ export function url(input: string, electron = false, truncate = false): string {
92
92
  let result = input;
93
93
  // Replace the URL for Electron apps so we don't send back file:/// URL
94
94
  if (electron) {
95
95
  result = `${Data.Constant.HTTPS}${Data.Constant.Electron}`;
96
96
  } else {
97
- let drop = config.drop;
97
+ const drop = config.drop;
98
98
  if (drop && drop.length > 0 && input && input.indexOf("?") > 0) {
99
- let [path, query] = input.split("?");
100
- let swap = Data.Constant.Dropped;
101
- result = path + "?" + query.split("&").map(p => drop.some(x => p.indexOf(`${x}=`) === 0) ? `${p.split("=")[0]}=${swap}` : p).join("&");
99
+ const [path, query] = input.split("?");
100
+ const swap = Data.Constant.Dropped;
101
+ result =
102
+ `${path}?${query
103
+ .split("&")
104
+ .map((p) => (drop.some((x) => p.indexOf(`${x}=`) === 0) ? `${p.split("=")[0]}=${swap}` : p))
105
+ .join("&")}`;
102
106
  }
103
107
  }
104
108
 
@@ -109,12 +113,12 @@ export function url(input: string, electron: boolean = false, truncate: boolean
109
113
  }
110
114
 
111
115
  function mangleText(value: string): string {
112
- let trimmed = value.trim();
116
+ const trimmed = value.trim();
113
117
  if (trimmed.length > 0) {
114
- let first = trimmed[0];
115
- let index = value.indexOf(first);
116
- let prefix = value.substr(0, index);
117
- let suffix = value.substr(index + trimmed.length);
118
+ const first = trimmed[0];
119
+ const index = value.indexOf(first);
120
+ const prefix = value.substr(0, index);
121
+ const suffix = value.substr(index + trimmed.length);
118
122
  return `${prefix}${trimmed.length.toString(36)}${suffix}`;
119
123
  }
120
124
  return value;
@@ -130,7 +134,7 @@ export function scrub(value: string, letter: string, digit: string): string {
130
134
  }
131
135
 
132
136
  function mangleToken(value: string): string {
133
- let length = ((Math.floor(value.length / Data.Setting.WordLength) + 1) * Data.Setting.WordLength);
137
+ const length = (Math.floor(value.length / Data.Setting.WordLength) + 1) * Data.Setting.WordLength;
134
138
  let output: string = Layout.Constant.Empty;
135
139
  for (let i = 0; i < length; i++) {
136
140
  output += i > 0 && i % Data.Setting.WordLength === 0 ? Data.Constant.Space : Data.Constant.Mask;
@@ -143,10 +147,12 @@ function regex(): void {
143
147
  // Reference: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions/Unicode_Property_Escapes
144
148
  if (unicodeRegex && digitRegex === null) {
145
149
  try {
146
- digitRegex = new RegExp("\\p{N}", "gu");
147
- letterRegex = new RegExp("\\p{L}", "gu");
148
- currencyRegex = new RegExp("\\p{Sc}", "gu");
149
- } catch { unicodeRegex = false; }
150
+ digitRegex = /\p{N}/gu;
151
+ letterRegex = /\p{L}/gu;
152
+ currencyRegex = /\p{Sc}/gu;
153
+ } catch {
154
+ unicodeRegex = false;
155
+ }
150
156
  }
151
157
  }
152
158
 
@@ -161,16 +167,19 @@ function redact(value: string): string {
161
167
  regex(); // Initialize regular expressions
162
168
 
163
169
  for (let i = 0; i < value.length; i++) {
164
- let c = value.charCodeAt(i);
170
+ const c = value.charCodeAt(i);
165
171
  hasDigit = hasDigit || (c >= Data.Character.Zero && c <= Data.Character.Nine); // Check for digits in the current word
166
172
  hasEmail = hasEmail || c === Data.Character.At; // Check for @ sign anywhere within the current word
167
- hasWhitespace = c === Data.Character.Tab || c === Data.Character.NewLine || c === Data.Character.Return || c === Data.Character.Blank;
173
+ hasWhitespace =
174
+ c === Data.Character.Tab || c === Data.Character.NewLine || c === Data.Character.Return || c === Data.Character.Blank;
168
175
 
169
176
  // Process each word as an individual token to redact any sensitive information
170
177
  if (i === 0 || i === value.length - 1 || hasWhitespace) {
171
178
  // Performance optimization: Lazy load string -> array conversion only when required
172
179
  if (hasDigit || hasEmail) {
173
- if (array === null) { array = value.split(Data.Constant.Empty); }
180
+ if (array === null) {
181
+ array = value.split(Data.Constant.Empty);
182
+ }
174
183
  // Work on a token at a time so we don't have to apply regex to a larger string
175
184
  let token = value.substring(spaceIndex + 1, hasWhitespace ? i : i + 1);
176
185
  // Check if unicode regex is supported, otherwise fallback to calling mask function on this token
package/src/core/task.ts CHANGED
@@ -1,5 +1,12 @@
1
- import { AsyncTask, Priority, RequestIdleCallbackDeadline, RequestIdleCallbackOptions, Task, Timer } from "@clarity-types/core";
2
- import { TaskFunction, TaskResolve, Tasks } from "@clarity-types/core";
1
+ import {
2
+ type AsyncTask,
3
+ Priority,
4
+ type RequestIdleCallbackDeadline,
5
+ type RequestIdleCallbackOptions,
6
+ Task,
7
+ type Timer,
8
+ } from "@clarity-types/core";
9
+ import type { TaskFunction, TaskResolve, Tasks } from "@clarity-types/core";
3
10
  import { Code, Metric, Setting, Severity } from "@clarity-types/data";
4
11
  import * as metadata from "@src/data/metadata";
5
12
  import * as metric from "@src/data/metric";
@@ -25,7 +32,9 @@ export function resume(): void {
25
32
  if (pauseTask) {
26
33
  resumeResolve();
27
34
  pauseTask = null;
28
- if (activeTask === null) { run(); }
35
+ if (activeTask === null) {
36
+ run();
37
+ }
29
38
  }
30
39
  }
31
40
 
@@ -38,14 +47,14 @@ export function reset(): void {
38
47
 
39
48
  export async function schedule(task: TaskFunction, priority: Priority = Priority.Normal): Promise<void> {
40
49
  // If this task is already scheduled, skip it
41
- for (let q of queuedTasks) {
50
+ for (const q of queuedTasks) {
42
51
  if (q.task === task) {
43
52
  return;
44
53
  }
45
54
  }
46
55
 
47
- let promise = new Promise<void>((resolve: TaskResolve): void => {
48
- let insert = priority === Priority.High ? "unshift" : "push";
56
+ const promise = new Promise<void>((resolve: TaskResolve): void => {
57
+ const insert = priority === Priority.High ? "unshift" : "push";
49
58
  // Queue this task for asynchronous execution later
50
59
  // We also store a unique page identifier (id) along with the task to ensure
51
60
  // ensure that we do not accidentally execute this task in context of a different page
@@ -54,38 +63,49 @@ export async function schedule(task: TaskFunction, priority: Priority = Priority
54
63
 
55
64
  // If there is no active task running, and Clarity is not in pause state,
56
65
  // invoke the first task in the queue synchronously. This ensures that we don't yield the thread during unload event
57
- if (activeTask === null && pauseTask === null) { run(); }
66
+ if (activeTask === null && pauseTask === null) {
67
+ run();
68
+ }
58
69
 
59
70
  return promise;
60
71
  }
61
72
 
62
73
  function run(): void {
63
- let entry = queuedTasks.shift();
74
+ const entry = queuedTasks.shift();
64
75
  if (entry) {
65
76
  activeTask = entry;
66
- entry.task().then((): void => {
67
- // Bail out if the context in which this task was operating is different from the current page
68
- // An example scenario where task could span across pages is Single Page Applications (SPA)
69
- // A task that started on page #1, but completes on page #2
70
- if (entry.id !== metadata.id()) { return; }
71
- entry.resolve();
72
- activeTask = null; // Reset active task back to null now that the promise is resolved
73
- run();
74
- }).catch((error: Error): void => {
75
- // If one of the scheduled tasks failed, log, recover and continue processing rest of the tasks
76
- if (entry.id !== metadata.id()) { return; }
77
- if (error) { internal.log(Code.RunTask, Severity.Warning, error.name, error.message, error.stack); }
78
- activeTask = null;
79
- run();
80
- });
77
+ entry
78
+ .task()
79
+ .then((): void => {
80
+ // Bail out if the context in which this task was operating is different from the current page
81
+ // An example scenario where task could span across pages is Single Page Applications (SPA)
82
+ // A task that started on page #1, but completes on page #2
83
+ if (entry.id !== metadata.id()) {
84
+ return;
85
+ }
86
+ entry.resolve();
87
+ activeTask = null; // Reset active task back to null now that the promise is resolved
88
+ run();
89
+ })
90
+ .catch((error: Error): void => {
91
+ // If one of the scheduled tasks failed, log, recover and continue processing rest of the tasks
92
+ if (entry.id !== metadata.id()) {
93
+ return;
94
+ }
95
+ if (error) {
96
+ internal.log(Code.RunTask, Severity.Warning, error.name, error.message, error.stack);
97
+ }
98
+ activeTask = null;
99
+ run();
100
+ });
81
101
  }
82
102
  }
83
103
 
84
104
  export function state(timer: Timer): Task {
85
- let id = key(timer);
105
+ const id = key(timer);
86
106
  if (id in tracker) {
87
- let elapsed = performance.now() - tracker[id].start;
88
- return (elapsed > tracker[id].yield) ? Task.Wait : Task.Run;
107
+ const elapsed = performance.now() - tracker[id].start;
108
+ return elapsed > tracker[id].yield ? Task.Wait : Task.Run;
89
109
  }
90
110
  // If this task is no longer being tracked, send stop message to the caller
91
111
  return Task.Stop;
@@ -96,10 +116,10 @@ export function start(timer: Timer): void {
96
116
  }
97
117
 
98
118
  function restart(timer: Timer): void {
99
- let id = key(timer);
100
- if (tracker && tracker[id]) {
101
- let c = tracker[id].calls;
102
- let y = tracker[id].yield;
119
+ const id = key(timer);
120
+ if (tracker?.[id]) {
121
+ const c = tracker[id].calls;
122
+ const y = tracker[id].yield;
103
123
  start(timer);
104
124
  tracker[id].calls = c + 1;
105
125
  tracker[id].yield = y;
@@ -107,15 +127,17 @@ function restart(timer: Timer): void {
107
127
  }
108
128
 
109
129
  export function stop(timer: Timer): void {
110
- let end = performance.now();
111
- let id = key(timer);
112
- let duration = end - tracker[id].start;
130
+ const end = performance.now();
131
+ const id = key(timer);
132
+ const duration = end - tracker[id].start;
113
133
  metric.sum(timer.cost, duration);
114
134
  metric.count(Metric.InvokeCount);
115
135
 
116
136
  // For the first execution, which is synchronous, time is automatically counted towards TotalDuration.
117
137
  // However, for subsequent asynchronous runs, we need to manually update TotalDuration metric.
118
- if (tracker[id].calls > 0) { metric.sum(Metric.TotalCost, duration); }
138
+ if (tracker[id].calls > 0) {
139
+ metric.sum(Metric.TotalCost, duration);
140
+ }
119
141
  }
120
142
 
121
143
  export async function suspend(timer: Timer): Promise<Task> {
@@ -123,10 +145,10 @@ export async function suspend(timer: Timer): Promise<Task> {
123
145
  // It's possible that Clarity is wrapping up instrumentation on a page and we are still in the middle of an async task.
124
146
  // In that case, we do not wish to continue yielding thread.
125
147
  // Instead, we will turn async task into a sync task and maximize our chances of getting some data back.
126
- let id = key(timer);
148
+ const id = key(timer);
127
149
  if (id in tracker) {
128
150
  stop(timer);
129
- // some customer polyfills for requestIdleCallback return null
151
+ // some customer polyfills for requestIdleCallback return null
130
152
  tracker[id].yield = (await wait())?.timeRemaining() || Setting.LongTask;
131
153
  restart(timer);
132
154
  }
@@ -140,7 +162,9 @@ function key(timer: Timer): string {
140
162
  }
141
163
 
142
164
  async function wait(): Promise<RequestIdleCallbackDeadline> {
143
- if (pauseTask) { await pauseTask; }
165
+ if (pauseTask) {
166
+ await pauseTask;
167
+ }
144
168
  return new Promise<RequestIdleCallbackDeadline>((resolve: (deadline: RequestIdleCallbackDeadline) => void): void => {
145
169
  requestIdleCallback(resolve, { timeout: idleTimeout });
146
170
  });
@@ -162,20 +186,24 @@ function requestIdleCallbackPolyfill(callback: (deadline: RequestIdleCallbackDea
162
186
  const incoming = channel.port1;
163
187
  const outgoing = channel.port2;
164
188
  incoming.onmessage = (event: MessageEvent): void => {
165
- let currentTime = performance.now();
166
- let elapsed = currentTime - startTime;
167
- let duration = currentTime - event.data;
189
+ const currentTime = performance.now();
190
+ const elapsed = currentTime - startTime;
191
+ const duration = currentTime - event.data;
168
192
  if (duration > Setting.LongTask && elapsed < options.timeout) {
169
- requestAnimationFrame((): void => { outgoing.postMessage(currentTime); });
193
+ requestAnimationFrame((): void => {
194
+ outgoing.postMessage(currentTime);
195
+ });
170
196
  } else {
171
- let didTimeout = elapsed > options.timeout;
197
+ const didTimeout = elapsed > options.timeout;
172
198
  callback({
173
199
  didTimeout,
174
- timeRemaining: (): number => didTimeout ? Setting.LongTask : Math.max(0, Setting.LongTask - duration)
200
+ timeRemaining: (): number => (didTimeout ? Setting.LongTask : Math.max(0, Setting.LongTask - duration)),
175
201
  });
176
202
  }
177
203
  };
178
- requestAnimationFrame((): void => { outgoing.postMessage(performance.now()); });
204
+ requestAnimationFrame((): void => {
205
+ outgoing.postMessage(performance.now());
206
+ });
179
207
  }
180
208
 
181
- let requestIdleCallback = window["requestIdleCallback"] || requestIdleCallbackPolyfill;
209
+ const requestIdleCallback = window.requestIdleCallback || requestIdleCallbackPolyfill;
package/src/core/time.ts CHANGED
@@ -4,13 +4,13 @@ export function start(): void {
4
4
  startTime = performance.now() + performance.timeOrigin;
5
5
  }
6
6
 
7
- // event.timestamp is number of milliseconds elapsed since the document was loaded
7
+ // event.timestamp is number of milliseconds elapsed since the document was loaded
8
8
  // since iframes can be loaded later the event timestamp is not the same as performance.now()
9
9
  // converting everything to absolute time by adding timeorigin of the event view
10
10
  // to synchronize times before calculating the difference with start time
11
11
  export function time(event: UIEvent | PageTransitionEvent = null): number {
12
- let ts = event && event.timeStamp > 0 ? event.timeStamp : performance.now();
13
- let origin = event && (event as UIEvent).view ? (event as UIEvent).view.performance.timeOrigin : performance.timeOrigin;
12
+ const ts = event && event.timeStamp > 0 ? event.timeStamp : performance.now();
13
+ const origin = event && (event as UIEvent).view ? (event as UIEvent).view.performance.timeOrigin : performance.timeOrigin;
14
14
  return Math.max(Math.round(ts + origin - startTime), 0);
15
15
  }
16
16
 
@@ -1,4 +1,4 @@
1
- import { Event } from "@clarity-types/data";
1
+ import type { Event } from "@clarity-types/data";
2
2
  import measure from "./measure";
3
3
 
4
4
  export function setTimeout(handler: (event?: Event | boolean) => void, timeout?: number, event?: Event): number {
@@ -6,5 +6,5 @@ export function setTimeout(handler: (event?: Event | boolean) => void, timeout?:
6
6
  }
7
7
 
8
8
  export function clearTimeout(handle: number): void {
9
- return window.clearTimeout(handle);
9
+ window.clearTimeout(handle);
10
10
  }
@@ -1,2 +1,2 @@
1
- let version = "0.8.10-beta";
1
+ const version = "0.8.10";
2
2
  export default version;
@@ -1,11 +1,11 @@
1
- import { Event, BooleanFlag } from "@clarity-types/data";
2
- import { BaselineData, BaselineState } from "@clarity-types/data";
1
+ import { BooleanFlag, Event } from "@clarity-types/data";
2
+ import type { BaselineData, BaselineState } from "@clarity-types/data";
3
3
  import { time } from "@src/core/time";
4
4
  import encode from "@src/data/encode";
5
5
 
6
6
  export let state: BaselineState = null;
7
7
  let buffer: BaselineData = null;
8
- let update: boolean = false;
8
+ let update = false;
9
9
 
10
10
  export function start(): void {
11
11
  update = false;
@@ -16,60 +16,65 @@ export function reset(): void {
16
16
  // Baseline state holds the previous values - if it is updated in the current payload,
17
17
  // reset the state to current value after sending the previous state
18
18
  if (update) {
19
- state = { time: time(), event: Event.Baseline, data: {
20
- visible: buffer.visible,
21
- docWidth: buffer.docWidth,
22
- docHeight: buffer.docHeight,
23
- screenWidth: buffer.screenWidth,
24
- screenHeight: buffer.screenHeight,
25
- scrollX: buffer.scrollX,
26
- scrollY: buffer.scrollY,
27
- pointerX: buffer.pointerX,
28
- pointerY: buffer.pointerY,
29
- activityTime: buffer.activityTime,
30
- scrollTime: buffer.scrollTime,
31
- pointerTime: buffer.pointerTime,
32
- moveX: buffer.moveX,
33
- moveY: buffer.moveY,
34
- moveTime: buffer.moveTime,
35
- downX: buffer.downX,
36
- downY: buffer.downY,
37
- downTime: buffer.downTime,
38
- upX: buffer.upX,
39
- upY: buffer.upY,
40
- upTime: buffer.upTime,
41
- pointerPrevX: buffer.pointerPrevX,
42
- pointerPrevY: buffer.pointerPrevY,
43
- pointerPrevTime: buffer.pointerPrevTime,
44
- }
19
+ state = {
20
+ time: time(),
21
+ event: Event.Baseline,
22
+ data: {
23
+ visible: buffer.visible,
24
+ docWidth: buffer.docWidth,
25
+ docHeight: buffer.docHeight,
26
+ screenWidth: buffer.screenWidth,
27
+ screenHeight: buffer.screenHeight,
28
+ scrollX: buffer.scrollX,
29
+ scrollY: buffer.scrollY,
30
+ pointerX: buffer.pointerX,
31
+ pointerY: buffer.pointerY,
32
+ activityTime: buffer.activityTime,
33
+ scrollTime: buffer.scrollTime,
34
+ pointerTime: buffer.pointerTime,
35
+ moveX: buffer.moveX,
36
+ moveY: buffer.moveY,
37
+ moveTime: buffer.moveTime,
38
+ downX: buffer.downX,
39
+ downY: buffer.downY,
40
+ downTime: buffer.downTime,
41
+ upX: buffer.upX,
42
+ upY: buffer.upY,
43
+ upTime: buffer.upTime,
44
+ pointerPrevX: buffer.pointerPrevX,
45
+ pointerPrevY: buffer.pointerPrevY,
46
+ pointerPrevTime: buffer.pointerPrevTime,
47
+ },
45
48
  };
46
49
  }
47
- buffer = buffer ? buffer : {
48
- visible: BooleanFlag.True,
49
- docWidth: 0,
50
- docHeight: 0,
51
- screenWidth: 0,
52
- screenHeight: 0,
53
- scrollX: 0,
54
- scrollY: 0,
55
- pointerX: 0,
56
- pointerY: 0,
57
- activityTime: 0,
58
- scrollTime: 0,
59
- pointerTime: undefined,
60
- moveX: undefined,
61
- moveY: undefined,
62
- moveTime: undefined,
63
- downX: undefined,
64
- downY: undefined,
65
- downTime: undefined,
66
- upX: undefined,
67
- upY: undefined,
68
- upTime: undefined,
69
- pointerPrevX: undefined,
70
- pointerPrevY: undefined,
71
- pointerPrevTime: undefined,
72
- };
50
+ buffer = buffer
51
+ ? buffer
52
+ : {
53
+ visible: BooleanFlag.True,
54
+ docWidth: 0,
55
+ docHeight: 0,
56
+ screenWidth: 0,
57
+ screenHeight: 0,
58
+ scrollX: 0,
59
+ scrollY: 0,
60
+ pointerX: 0,
61
+ pointerY: 0,
62
+ activityTime: 0,
63
+ scrollTime: 0,
64
+ pointerTime: undefined,
65
+ moveX: undefined,
66
+ moveY: undefined,
67
+ moveTime: undefined,
68
+ downX: undefined,
69
+ downY: undefined,
70
+ downTime: undefined,
71
+ upX: undefined,
72
+ upY: undefined,
73
+ upTime: undefined,
74
+ pointerPrevX: undefined,
75
+ pointerPrevY: undefined,
76
+ pointerPrevTime: undefined,
77
+ };
73
78
  }
74
79
 
75
80
  export function track(event: Event, x: number, y: number, time?: number): void {
@@ -4,7 +4,7 @@ import * as dimension from "@src/data/dimension";
4
4
  const enum ConsentType {
5
5
  None = 0,
6
6
  Implicit = 1,
7
- General = 2
7
+ General = 2,
8
8
  }
9
9
 
10
10
  export function config(track: boolean): void {
@@ -18,4 +18,4 @@ export function consent(): void {
18
18
 
19
19
  function trackConsent(consent: ConsentType): void {
20
20
  dimension.log(Dimension.Consent, consent.toString());
21
- }
21
+ }
@@ -1,4 +1,4 @@
1
- import { Constant, CustomData, Event } from "@clarity-types/data";
1
+ import { type CustomData, Event } from "@clarity-types/data";
2
2
  import * as core from "@src/core";
3
3
  import encode from "./encode";
4
4
 
@@ -7,17 +7,12 @@ export let data: CustomData = null;
7
7
  // custom events allow 2 parameters or 1 parameter to be passed. If 2 are passed we
8
8
  // consider it a key value pair. If only 1 is passed we only consider the event to have a value.
9
9
  export function event(a: string, b: string): void {
10
- if (core.active() &&
11
- a &&
12
- typeof a === Constant.String &&
13
- a.length < 255
14
- ) {
15
- if (b && typeof b === Constant.String && b.length < 255) {
16
- data = { key: a, value: b};
17
- } else {
18
- data = { value: a }
19
- }
20
- encode(Event.Custom);
21
-
10
+ if (core.active() && a && typeof a === "string" && a.length < 255) {
11
+ if (b && typeof b === "string" && b.length < 255) {
12
+ data = { key: a, value: b };
13
+ } else {
14
+ data = { value: a };
15
+ }
16
+ encode(Event.Custom);
22
17
  }
23
18
  }