clarity-js 0.7.58 → 0.7.60

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,6 @@
1
1
  import { Event } from "@clarity-types/data";
2
2
  import { PointerState, Setting } from "@clarity-types/interaction";
3
+ import { FunctionNames } from "@clarity-types/performance";
3
4
  import { bind } from "@src/core/event";
4
5
  import { schedule } from "@src/core/task";
5
6
  import { time } from "@src/core/time";
@@ -11,7 +12,8 @@ import encode from "./encode";
11
12
 
12
13
  export let state: PointerState[] = [];
13
14
  let timeout: number = null;
14
- let activeTouchPointId = 0;
15
+ let hasPrimaryTouch = false;
16
+ let primaryTouchId = 0;
15
17
  const activeTouchPointIds = new Set<number>();
16
18
 
17
19
  export function start(): void {
@@ -45,6 +47,7 @@ function mouse(event: Event, root: Node, evt: MouseEvent): void {
45
47
  // Check for null values before processing this event
46
48
  if (x !== null && y !== null) { handler({ time: time(evt), event, data: { target: target(evt), x, y } }); }
47
49
  }
50
+ mouse.dn = FunctionNames.PointerMouse;
48
51
 
49
52
  function touch(event: Event, root: Node, evt: TouchEvent): void {
50
53
  let frame = iframe(root);
@@ -67,7 +70,9 @@ function touch(event: Event, root: Node, evt: TouchEvent): void {
67
70
  switch(event) {
68
71
  case Event.TouchStart:
69
72
  if (activeTouchPointIds.size === 0) {
70
- activeTouchPointId = id;
73
+ // Track presence of primary touch separately to handle scenarios when same id is repeated
74
+ hasPrimaryTouch = true;
75
+ primaryTouchId = id;
71
76
  }
72
77
  activeTouchPointIds.add(id);
73
78
  break;
@@ -76,13 +81,19 @@ function touch(event: Event, root: Node, evt: TouchEvent): void {
76
81
  activeTouchPointIds.delete(id);
77
82
  break;
78
83
  }
79
- const isPrimary = activeTouchPointId === id;
84
+ const isPrimary = hasPrimaryTouch && primaryTouchId === id;
80
85
 
81
86
  // Check for null values before processing this event
82
87
  if (x !== null && y !== null) { handler({ time: t, event, data: { target: target(evt), x, y, id, isPrimary } }); }
88
+
89
+ // Reset primary touch point id once touch event ends
90
+ if (event === Event.TouchCancel || event === Event.TouchEnd) {
91
+ if (primaryTouchId === id) { hasPrimaryTouch = false; }
92
+ }
83
93
  }
84
94
  }
85
95
  }
96
+ touch.dn = FunctionNames.PointerTouch;
86
97
 
87
98
  function handler(current: PointerState): void {
88
99
  switch (current.event) {
@@ -1,5 +1,6 @@
1
1
  import { Event } from "@clarity-types/data";
2
2
  import { ResizeData, Setting } from "@clarity-types/interaction";
3
+ import { FunctionNames } from "@clarity-types/performance";
3
4
  import { clearTimeout, setTimeout } from "@src/core/timeout";
4
5
  import { bind } from "@src/core/event";
5
6
  import encode from "./encode";
@@ -31,6 +32,7 @@ function recompute(): void {
31
32
  initialStateLogged = true;
32
33
  }
33
34
  }
35
+ recompute.dn = FunctionNames.ResizeRecompute;
34
36
 
35
37
  function process(event: Event): void {
36
38
  schedule(encode.bind(this, event));
@@ -1,5 +1,6 @@
1
1
  import { Constant, Dimension, Event } from "@clarity-types/data";
2
2
  import { ScrollState, Setting } from "@clarity-types/interaction";
3
+ import { FunctionNames } from "@clarity-types/performance";
3
4
  import { bind } from "@src/core/event";
4
5
  import { schedule } from "@src/core/task";
5
6
  import { time } from "@src/core/time";
@@ -68,6 +69,7 @@ function recompute(event: UIEvent = null): void {
68
69
  clearTimeout(timeout);
69
70
  timeout = setTimeout(process, Setting.LookAhead, Event.Scroll);
70
71
  }
72
+ recompute.dn = FunctionNames.ScrollRecompute;
71
73
 
72
74
  function getPositionNode(x: number, y: number): Node {
73
75
  let node: Node;
@@ -112,6 +114,7 @@ export function compute(): void {
112
114
  dimension.log(Dimension.InitialScrollBottom, bottom?.hash?.join(Constant.Dot));
113
115
  }
114
116
  }
117
+ compute.dn = FunctionNames.ScrollCompute;
115
118
 
116
119
  export function stop(): void {
117
120
  clearTimeout(timeout);
@@ -1,5 +1,6 @@
1
1
  import { Event } from "@clarity-types/data";
2
2
  import { SelectionData, Setting } from "@clarity-types/interaction";
3
+ import { FunctionNames } from "@clarity-types/performance";
3
4
  import { bind } from "@src/core/event";
4
5
  import { schedule } from "@src/core/task";
5
6
  import { clearTimeout, setTimeout } from "@src/core/timeout";
@@ -50,6 +51,7 @@ function recompute(root: Node): void {
50
51
  clearTimeout(timeout);
51
52
  timeout = setTimeout(process, Setting.LookAhead, Event.Selection);
52
53
  }
54
+ recompute.dn = FunctionNames.SelectionRecompute;
53
55
 
54
56
  function process(event: Event): void {
55
57
  schedule(encode.bind(this, event));
@@ -1,5 +1,6 @@
1
1
  import { Event } from "@clarity-types/data";
2
2
  import { SubmitState } from "@clarity-types/interaction";
3
+ import { FunctionNames } from "@clarity-types/performance";
3
4
  import { bind } from "@src/core/event";
4
5
  import { schedule } from "@src/core/task";
5
6
  import { time } from "@src/core/time";
@@ -20,6 +21,7 @@ function recompute(evt: UIEvent): void {
20
21
  state.push({ time: time(evt), event: Event.Submit, data: { target: target(evt) } });
21
22
  schedule(encode.bind(this, Event.Submit));
22
23
  }
24
+ recompute.dn = FunctionNames.SubmitRecompute;
23
25
 
24
26
  export function reset(): void {
25
27
  state = [];
@@ -1,5 +1,6 @@
1
1
  import { Event } from "@clarity-types/data";
2
2
  import { UnloadData } from "@clarity-types/interaction";
3
+ import { FunctionNames } from "@clarity-types/performance";
3
4
  import * as clarity from "@src/clarity";
4
5
  import { bind } from "@src/core/event";
5
6
  import { time } from "@src/core/time";
@@ -16,6 +17,7 @@ function recompute(evt: UIEvent): void {
16
17
  encode(Event.Unload, time(evt));
17
18
  clarity.stop();
18
19
  }
20
+ recompute.dn = FunctionNames.UnloadRecompute;
19
21
 
20
22
  export function reset(): void {
21
23
  data = null;
@@ -1,5 +1,6 @@
1
1
  import { Event } from "@clarity-types/data";
2
2
  import { VisibilityData } from "@clarity-types/interaction";
3
+ import { FunctionNames } from "@clarity-types/performance";
3
4
  import { bind } from "@src/core/event";
4
5
  import { time } from "@src/core/time";
5
6
  import encode from "./encode";
@@ -15,6 +16,7 @@ function recompute(evt: UIEvent = null): void {
15
16
  data = { visible: "visibilityState" in document ? document.visibilityState : "default" };
16
17
  encode(Event.Visibility, time(evt));
17
18
  }
19
+ recompute.dn = FunctionNames.VisibilityRecompute;
18
20
 
19
21
  export function reset(): void {
20
22
  data = null;
@@ -1,5 +1,6 @@
1
1
  import { Event } from "@clarity-types/data";
2
2
  import { DocumentData } from "@clarity-types/layout";
3
+ import { FunctionNames } from "@clarity-types/performance";
3
4
  import encode from "@src/layout/encode";
4
5
 
5
6
  export let data: DocumentData;
@@ -40,6 +41,7 @@ export function compute(): void {
40
41
  encode(Event.Document);
41
42
  }
42
43
  }
44
+ compute.dn = FunctionNames.DocumentCompute;
43
45
 
44
46
  export function stop(): void {
45
47
  reset();
@@ -1,3 +1,4 @@
1
+ import { FunctionNames } from "@clarity-types/performance";
1
2
  import * as discover from "@src/layout/discover";
2
3
  import * as doc from "@src/layout/document";
3
4
  import * as dom from "@src/layout/dom";
@@ -28,6 +29,7 @@ export function start(): void {
28
29
  style.start();
29
30
  animation.start();
30
31
  }
32
+ start.dn = FunctionNames.LayoutStart;
31
33
 
32
34
  export function stop(): void {
33
35
  region.stop();
@@ -1,6 +1,7 @@
1
1
  import { Priority, Task, Timer } from "@clarity-types/core";
2
2
  import { Code, Event, Metric, Severity } from "@clarity-types/data";
3
3
  import { Constant, MutationHistory, MutationRecordWithTime, MutationQueue, Setting, Source } from "@clarity-types/layout";
4
+ import { FunctionNames } from "@clarity-types/performance";
4
5
  import api from "@src/core/api";
5
6
  import * as core from "@src/core";
6
7
  import { bind } from "@src/core/event";
@@ -13,6 +14,7 @@ import * as summary from "@src/data/summary";
13
14
  import * as internal from "@src/diagnostic/internal";
14
15
  import * as doc from "@src/layout/document";
15
16
  import * as dom from "@src/layout/dom";
17
+ import * as metric from "@src/data/metric";
16
18
  import encode from "@src/layout/encode";
17
19
  import * as region from "@src/layout/region";
18
20
  import traverse from "@src/layout/traverse";
@@ -89,6 +91,7 @@ export function start(): void {
89
91
  } catch { attachShadow = null; }
90
92
  }
91
93
  }
94
+ start.dn = FunctionNames.MutationStart;
92
95
 
93
96
  export function observe(node: Node): void {
94
97
  // Create a new observer for every time a new DOM tree (e.g. root document or shadowdom root) is discovered on the page
@@ -139,6 +142,7 @@ function handle(m: MutationRecord[]): void {
139
142
  measure(region.compute)();
140
143
  });
141
144
  }
145
+ handle.dn = FunctionNames.MutationHandle;
142
146
 
143
147
  async function processMutation(timer: Timer, mutation: MutationRecord, instance: number, timestamp: number): Promise<void> {
144
148
  let state = task.state(timer);
@@ -192,10 +196,27 @@ async function process(): Promise<void> {
192
196
  if (Object.keys(throttledMutations).length === 0 && processedMutations) {
193
197
  await encode(Event.Mutation, timer, time());
194
198
  }
199
+
200
+ cleanHistory();
195
201
 
196
202
  task.stop(timer);
197
203
  }
198
204
 
205
+ function cleanHistory(): void {
206
+ let now = time();
207
+ if (Object.keys(history).length > Setting.MaxMutationHistoryCount) {
208
+ history = {};
209
+ metric.count(Metric.HistoryClear);
210
+ }
211
+
212
+ for (let key of Object.keys(history)) {
213
+ let h = history[key];
214
+ if (now > h[1] + Setting.MaxMutationHistoryTime) {
215
+ delete history[key];
216
+ }
217
+ }
218
+ }
219
+
199
220
  function track(m: MutationRecord, timer: Timer, instance: number, timestamp: number): string {
200
221
  let value = m.target ? dom.get(m.target.parentNode) : null;
201
222
  // Check if the parent is already discovered and that the parent is not the document root
@@ -299,3 +320,4 @@ function generate(target: Node, type: MutationRecordType): void {
299
320
  type
300
321
  }]);
301
322
  }
323
+ generate.dn = FunctionNames.MutationGenerate;
@@ -1,5 +1,6 @@
1
1
  import { Event, Setting } from "@clarity-types/data";
2
2
  import { InteractionState, RegionData, RegionState, RegionQueue, RegionVisibility } from "@clarity-types/layout";
3
+ import { FunctionNames } from "@clarity-types/performance";
3
4
  import { time } from "@src/core/time";
4
5
  import * as dom from "@src/layout/dom";
5
6
  import encode from "@src/layout/encode";
@@ -76,6 +77,7 @@ export function compute(): void {
76
77
  // Schedule encode only when we have at least one valid data entry
77
78
  if (state.length > 0) { encode(Event.Region); }
78
79
  }
80
+ compute.dn = FunctionNames.RegionCompute;
79
81
 
80
82
  function handler(entries: IntersectionObserverEntry[]): void {
81
83
  for (let entry of entries) {
@@ -19,37 +19,39 @@ let styleTimeMap: {[key: string]: number} = {};
19
19
  let documentNodes = [];
20
20
 
21
21
  export function start(): void {
22
- if (replace === null) {
23
- replace = CSSStyleSheet.prototype.replace;
24
- CSSStyleSheet.prototype.replace = function(): Promise<CSSStyleSheet> {
25
- if (core.active()) {
26
- metric.max(Metric.ConstructedStyles, 1);
27
- // if we haven't seen this stylesheet on this page yet, wait until the checkDocumentStyles has found it
28
- // and attached the sheet to a document. This way the timestamp of the style sheet creation will align
29
- // to when it is used in the document rather than potentially being misaligned during the traverse process.
30
- if (this[styleSheetPageNum] === metadataFields.pageNum) {
31
- trackStyleChange(time(), this[styleSheetId], StyleSheetOperation.Replace, arguments[0]);
22
+ if (window['CSSStyleSheet'] && CSSStyleSheet.prototype) {
23
+ if (replace === null) {
24
+ replace = CSSStyleSheet.prototype.replace;
25
+ CSSStyleSheet.prototype.replace = function(): Promise<CSSStyleSheet> {
26
+ if (core.active()) {
27
+ metric.max(Metric.ConstructedStyles, 1);
28
+ // if we haven't seen this stylesheet on this page yet, wait until the checkDocumentStyles has found it
29
+ // and attached the sheet to a document. This way the timestamp of the style sheet creation will align
30
+ // to when it is used in the document rather than potentially being misaligned during the traverse process.
31
+ if (this[styleSheetPageNum] === metadataFields.pageNum) {
32
+ trackStyleChange(time(), this[styleSheetId], StyleSheetOperation.Replace, arguments[0]);
33
+ }
32
34
  }
33
- }
34
- return replace.apply(this, arguments);
35
- };
36
- }
37
-
38
- if (replaceSync === null) {
39
- replaceSync = CSSStyleSheet.prototype.replaceSync;
40
- CSSStyleSheet.prototype.replaceSync = function(): void {
41
- if (core.active()) {
42
- metric.max(Metric.ConstructedStyles, 1);
43
- // if we haven't seen this stylesheet on this page yet, wait until the checkDocumentStyles has found it
44
- // and attached the sheet to a document. This way the timestamp of the style sheet creation will align
45
- // to when it is used in the document rather than potentially being misaligned during the traverse process.
46
- if (this[styleSheetPageNum] === metadataFields.pageNum) {
47
- trackStyleChange(time(), this[styleSheetId], StyleSheetOperation.ReplaceSync, arguments[0]);
48
- }
49
- }
50
- return replaceSync.apply(this, arguments);
51
- };
52
- }
35
+ return replace.apply(this, arguments);
36
+ };
37
+ }
38
+
39
+ if (replaceSync === null) {
40
+ replaceSync = CSSStyleSheet.prototype.replaceSync;
41
+ CSSStyleSheet.prototype.replaceSync = function(): void {
42
+ if (core.active()) {
43
+ metric.max(Metric.ConstructedStyles, 1);
44
+ // if we haven't seen this stylesheet on this page yet, wait until the checkDocumentStyles has found it
45
+ // and attached the sheet to a document. This way the timestamp of the style sheet creation will align
46
+ // to when it is used in the document rather than potentially being misaligned during the traverse process.
47
+ if (this[styleSheetPageNum] === metadataFields.pageNum) {
48
+ trackStyleChange(time(), this[styleSheetId], StyleSheetOperation.ReplaceSync, arguments[0]);
49
+ }
50
+ }
51
+ return replaceSync.apply(this, arguments);
52
+ };
53
+ }
54
+ }
53
55
  }
54
56
 
55
57
  export function checkDocumentStyles(documentNode: Document, timestamp: number): void {
@@ -1,3 +1,4 @@
1
+ import { FunctionNames } from "@clarity-types/performance";
1
2
  import * as navigation from "@src/performance/navigation";
2
3
  import * as observer from "@src/performance/observer";
3
4
 
@@ -5,6 +6,7 @@ export function start(): void {
5
6
  navigation.reset();
6
7
  observer.start();
7
8
  }
9
+ start.dn = FunctionNames.PerformanceStart;
8
10
 
9
11
  export function stop(): void {
10
12
  observer.stop();
@@ -1,4 +1,5 @@
1
1
  import { Code, Constant, Dimension, Metric, Severity, PerformanceEventTiming } from "@clarity-types/data";
2
+ import { FunctionNames } from "@clarity-types/performance";
2
3
  import config from "@src/core/config";
3
4
  import { bind } from "@src/core/event";
4
5
  import measure from "@src/core/measure";
@@ -49,10 +50,12 @@ function observe(): void {
49
50
  }
50
51
  } catch { internal.log(Code.PerformanceObserver, Severity.Warning); }
51
52
  }
53
+ observe.dn = FunctionNames.ObserverObserve;
52
54
 
53
55
  function handle(entries: PerformanceObserverEntryList): void {
54
56
  process(entries.getEntries());
55
57
  }
58
+ handle.dn = FunctionNames.ObserverHandle;
56
59
 
57
60
  function process(entries: PerformanceEntryList): void {
58
61
  let visible = "visibilityState" in document ? document.visibilityState === "visible" : true;
package/types/data.d.ts CHANGED
@@ -127,7 +127,8 @@ export const enum Metric {
127
127
  /**
128
128
  * @deprecated Move it to dimension as it'll report only last value
129
129
  */
130
- InteractionNextPaint = 37
130
+ InteractionNextPaint = 37,
131
+ HistoryClear = 38
131
132
  }
132
133
 
133
134
  export const enum Dimension {
@@ -194,7 +195,8 @@ export const enum Code {
194
195
  * @deprecated No longer support ContentSecurityPolicy
195
196
  */
196
197
  ContentSecurityPolicy = 7,
197
- Config = 8
198
+ Config = 8,
199
+ FunctionExecutionTime = 9
198
200
  }
199
201
 
200
202
  export const enum Severity {
package/types/layout.d.ts CHANGED
@@ -156,7 +156,9 @@ export const enum JsonLD {
156
156
  export const enum Setting {
157
157
  LookAhead = 33, // 33ms
158
158
  MutationSuspendThreshold = 10, // Stop listening for mutations after hitting a threshold count
159
- MutationActivePeriod = 3000 // Unit: milliseconds. Let mutations continue as normal during active periods of user interactions
159
+ MutationActivePeriod = 3000, // Unit: milliseconds. Let mutations continue as normal during active periods of user interactions
160
+ MaxMutationHistoryCount = 10000,
161
+ MaxMutationHistoryTime = 30000, // Unit: milliseconds. Maximum time to keep mutation history in memory
160
162
  }
161
163
 
162
164
  export const enum StyleSheetOperation {
@@ -31,3 +31,35 @@ export interface NavigationData {
31
31
  encodedSize: number;
32
32
  decodedSize: number;
33
33
  }
34
+
35
+ export const enum FunctionNames {
36
+ HistoryCompute = 1,
37
+ Restart = 2,
38
+ DiagnosticStart = 3,
39
+ ScriptHandler = 4,
40
+ ChangeRecompute = 5,
41
+ ClickHandler = 6,
42
+ ClipboardRecompute = 7,
43
+ InteractionStart = 8,
44
+ InputRecompute = 9,
45
+ PointerMouse = 10,
46
+ PointerTouch = 11,
47
+ ResizeRecompute = 12,
48
+ ScrollRecompute = 13,
49
+ ScrollCompute = 14,
50
+ SelectionRecompute = 15,
51
+ SubmitRecompute = 16,
52
+ UnloadRecompute = 17,
53
+ VisibilityRecompute = 18,
54
+ DocumentCompute = 19,
55
+ LayoutStart = 20,
56
+ MutationStart = 21,
57
+ MutationHandle = 22,
58
+ MutationGenerate = 23,
59
+ RegionCompute = 24,
60
+ PerformanceStart = 25,
61
+ ObserverObserve = 26,
62
+ ObserverHandle = 27
63
+ }
64
+
65
+ declare global { interface Function { dn?: FunctionNames; } }