clarity-js 0.6.32 → 0.6.35
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/build/clarity.js +2080 -2100
- package/build/clarity.min.js +1 -1
- package/build/clarity.module.js +2080 -2100
- package/package.json +1 -1
- package/src/core/config.ts +2 -2
- package/src/core/history.ts +27 -27
- package/src/core/version.ts +1 -1
- package/src/data/encode.ts +9 -0
- package/src/data/extract.ts +143 -0
- package/src/data/index.ts +3 -1
- package/src/data/metadata.ts +15 -11
- package/src/data/metric.ts +3 -3
- package/src/diagnostic/encode.ts +9 -0
- package/src/diagnostic/fraud.ts +29 -0
- package/src/diagnostic/index.ts +2 -0
- package/src/diagnostic/script.ts +1 -11
- package/src/interaction/click.ts +2 -1
- package/src/interaction/encode.ts +4 -3
- package/src/interaction/input.ts +1 -8
- package/src/layout/dom.ts +105 -90
- package/src/layout/encode.ts +15 -15
- package/src/layout/index.ts +0 -3
- package/src/layout/mutation.ts +32 -44
- package/src/layout/target.ts +7 -4
- package/src/performance/observer.ts +10 -2
- package/types/core.d.ts +20 -13
- package/types/data.d.ts +27 -7
- package/types/diagnostic.d.ts +6 -0
- package/types/interaction.d.ts +1 -0
- package/types/layout.d.ts +8 -6
- package/types/performance.d.ts +0 -7
- package/src/layout/box.ts +0 -83
- package/src/layout/extract.ts +0 -94
package/types/data.d.ts
CHANGED
|
@@ -4,9 +4,12 @@ export type Token = (string | number | number[] | string[]);
|
|
|
4
4
|
export type DecodedToken = (any | any[]);
|
|
5
5
|
|
|
6
6
|
export type MetadataCallback = (data: Metadata, playback: boolean) => void;
|
|
7
|
+
export interface MetadataCallbackOptions {
|
|
8
|
+
callback: MetadataCallback,
|
|
9
|
+
wait: boolean
|
|
10
|
+
}
|
|
7
11
|
|
|
8
12
|
/* Enum */
|
|
9
|
-
|
|
10
13
|
export const enum Event {
|
|
11
14
|
/* Data */
|
|
12
15
|
Metric = 0,
|
|
@@ -52,9 +55,14 @@ export const enum Event {
|
|
|
52
55
|
Variable = 34,
|
|
53
56
|
Limit = 35,
|
|
54
57
|
Summary = 36,
|
|
58
|
+
/**
|
|
59
|
+
* @deprecated No longer support Box event
|
|
60
|
+
*/
|
|
55
61
|
Box = 37,
|
|
56
62
|
Clipboard = 38,
|
|
57
|
-
Submit = 39
|
|
63
|
+
Submit = 39,
|
|
64
|
+
Extract = 40,
|
|
65
|
+
Fraud = 41
|
|
58
66
|
}
|
|
59
67
|
|
|
60
68
|
export const enum Metric {
|
|
@@ -85,7 +93,10 @@ export const enum Metric {
|
|
|
85
93
|
CartTotal = 24,
|
|
86
94
|
EventCount = 25,
|
|
87
95
|
Automation = 26,
|
|
88
|
-
Mobile = 27
|
|
96
|
+
Mobile = 27,
|
|
97
|
+
UploadTime = 28,
|
|
98
|
+
SinglePage = 29,
|
|
99
|
+
UsedMemory = 30
|
|
89
100
|
}
|
|
90
101
|
|
|
91
102
|
export const enum Dimension {
|
|
@@ -138,7 +149,8 @@ export const enum Code {
|
|
|
138
149
|
/**
|
|
139
150
|
* @deprecated No longer support ContentSecurityPolicy
|
|
140
151
|
*/
|
|
141
|
-
ContentSecurityPolicy = 7
|
|
152
|
+
ContentSecurityPolicy = 7,
|
|
153
|
+
Config = 8
|
|
142
154
|
}
|
|
143
155
|
|
|
144
156
|
export const enum Severity {
|
|
@@ -175,7 +187,6 @@ export const enum Setting {
|
|
|
175
187
|
CollectionLimit = 128, // Number of unique entries for dimensions
|
|
176
188
|
ClickPrecision = 32767, // 2^15 - 1
|
|
177
189
|
BoxPrecision = 100, // Up to 2 decimal points (e.g. 34.56)
|
|
178
|
-
ResizeObserverThreshold = 15, // At least 15 characters before we attach a resize observer for the node
|
|
179
190
|
ScriptErrorLimit = 5, // Do not send the same script error more than 5 times per page
|
|
180
191
|
DimensionLimit = 256, // Do not extract dimensions which are over 256 characters
|
|
181
192
|
WordLength = 5, // Estimated average size of a word,
|
|
@@ -185,9 +196,11 @@ export const enum Setting {
|
|
|
185
196
|
ViewportIntersectionRatio = 0.05, // Ratio of intersection area in comparison to viewport area before it's marked visible
|
|
186
197
|
IntersectionRatio = 0.8, // Ratio of intersection area in comparison to element's area before it's marked visible
|
|
187
198
|
MaxFirstPayloadBytes = 1 * 1024 * 1024, // 1MB: Cap the very first payload to a maximum of 1MB
|
|
199
|
+
MegaByte = 1024 * 1024, // 1MB
|
|
188
200
|
UploadFactor = 3, // Slow down sequence by specified factor
|
|
189
201
|
MinUploadDelay = 100, // Minimum time before we are ready to flush events to the server
|
|
190
|
-
MaxUploadDelay = 30 * Time.Second // Do flush out payload once every 30s
|
|
202
|
+
MaxUploadDelay = 30 * Time.Second, // Do flush out payload once every 30s,
|
|
203
|
+
ExtractLimit = 10000 // Do not extract more than 10000 characters
|
|
191
204
|
}
|
|
192
205
|
|
|
193
206
|
export const enum Character {
|
|
@@ -209,6 +222,7 @@ export const enum Constant {
|
|
|
209
222
|
Pause = "pause",
|
|
210
223
|
Resume = "resume",
|
|
211
224
|
Report = "report",
|
|
225
|
+
Memory = "memory",
|
|
212
226
|
Empty = "",
|
|
213
227
|
Space = " ",
|
|
214
228
|
Expires = "expires=",
|
|
@@ -233,7 +247,6 @@ export const enum Constant {
|
|
|
233
247
|
UserId = "userId",
|
|
234
248
|
SessionId = "sessionId",
|
|
235
249
|
PageId = "pageId",
|
|
236
|
-
ResizeObserver = "ResizeObserver",
|
|
237
250
|
Mask = "•",
|
|
238
251
|
SessionStorage = "sessionStorage",
|
|
239
252
|
Cookie = "cookie",
|
|
@@ -248,6 +261,9 @@ export const enum Constant {
|
|
|
248
261
|
Accept = "Accept",
|
|
249
262
|
ClarityGzip = "application/x-clarity-gzip",
|
|
250
263
|
Tilde = "~",
|
|
264
|
+
ArrayStart = "[",
|
|
265
|
+
ConditionStart = "{",
|
|
266
|
+
ConditionEnd = "}"
|
|
251
267
|
}
|
|
252
268
|
|
|
253
269
|
export const enum XMLReadyState {
|
|
@@ -366,6 +382,10 @@ export interface UpgradeData {
|
|
|
366
382
|
key: string;
|
|
367
383
|
}
|
|
368
384
|
|
|
385
|
+
export interface ExtractData {
|
|
386
|
+
[key: string]: string | number;
|
|
387
|
+
}
|
|
388
|
+
|
|
369
389
|
export interface UploadData {
|
|
370
390
|
sequence: number;
|
|
371
391
|
attempts: number;
|
package/types/diagnostic.d.ts
CHANGED
package/types/interaction.d.ts
CHANGED
package/types/layout.d.ts
CHANGED
|
@@ -28,6 +28,11 @@ export const enum RegionVisibility {
|
|
|
28
28
|
ScrolledToEnd = 13
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
+
export const enum Mask {
|
|
32
|
+
Text = "password,secret,pass,social,ssn,name,code,dob,cell,mob,contact,hidden,account,cvv,ccv,email,tel,phone,address,addr,card,zip",
|
|
33
|
+
Disable = "radio,checkbox,range,button,reset,submit"
|
|
34
|
+
}
|
|
35
|
+
|
|
31
36
|
export const enum Constant {
|
|
32
37
|
Empty = "",
|
|
33
38
|
SvgPrefix = "svg:",
|
|
@@ -42,6 +47,7 @@ export const enum Constant {
|
|
|
42
47
|
Box = "#",
|
|
43
48
|
Bang = "!",
|
|
44
49
|
Period = ".",
|
|
50
|
+
Comma = ",",
|
|
45
51
|
MaskData = "data-clarity-mask",
|
|
46
52
|
UnmaskData = "data-clarity-unmask",
|
|
47
53
|
RegionData = "data-clarity-region",
|
|
@@ -154,6 +160,7 @@ export interface NodeValue {
|
|
|
154
160
|
hash: [string, string];
|
|
155
161
|
region: number;
|
|
156
162
|
metadata: NodeMeta;
|
|
163
|
+
fragment: number;
|
|
157
164
|
}
|
|
158
165
|
|
|
159
166
|
export interface NodeMeta {
|
|
@@ -161,6 +168,7 @@ export interface NodeMeta {
|
|
|
161
168
|
suspend: boolean;
|
|
162
169
|
privacy: Privacy;
|
|
163
170
|
position: number;
|
|
171
|
+
fraud: number;
|
|
164
172
|
size: number[];
|
|
165
173
|
}
|
|
166
174
|
|
|
@@ -197,12 +205,6 @@ export interface RegionData {
|
|
|
197
205
|
name: string;
|
|
198
206
|
}
|
|
199
207
|
|
|
200
|
-
export interface BoxData {
|
|
201
|
-
id: number;
|
|
202
|
-
width: number;
|
|
203
|
-
height: number;
|
|
204
|
-
}
|
|
205
|
-
|
|
206
208
|
export interface TargetMetadata {
|
|
207
209
|
id: number;
|
|
208
210
|
hash: [string, string];
|
package/types/performance.d.ts
CHANGED
package/src/layout/box.ts
DELETED
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
import { Event, Setting } from "@clarity-types/data";
|
|
2
|
-
import { BoxData } from "@clarity-types/layout";
|
|
3
|
-
import * as dom from "@src/layout/dom";
|
|
4
|
-
import encode from "@src/layout/encode";
|
|
5
|
-
|
|
6
|
-
export let data: BoxData[] = [];
|
|
7
|
-
let enabled = false;
|
|
8
|
-
let observer: ResizeObserver = null;
|
|
9
|
-
|
|
10
|
-
export function start(): void {
|
|
11
|
-
reset();
|
|
12
|
-
observer = null;
|
|
13
|
-
enabled = window["ResizeObserver"] ? true : false;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export function compute(id: number): void {
|
|
17
|
-
if (enabled === false) { return; }
|
|
18
|
-
observer = observer === null ? new ResizeObserver(handler) : observer;
|
|
19
|
-
if (observer) {
|
|
20
|
-
let value = dom.getValue(id);
|
|
21
|
-
// If this is the first time computing size for this node, go ahead and wire up ResizeObserver
|
|
22
|
-
// In all other cases, value.metadata.size will be null or an array with two elements [width, height]
|
|
23
|
-
// And, in those cases, we will skip through the following section and not attach the observer
|
|
24
|
-
if (value && value.metadata.size !== null && value.metadata.size.length === 0) {
|
|
25
|
-
let node = dom.getNode(id);
|
|
26
|
-
if (node && node.nodeType === Node.ELEMENT_NODE) {
|
|
27
|
-
let e = node as HTMLElement;
|
|
28
|
-
let r = e.getBoundingClientRect();
|
|
29
|
-
value.metadata.size = [Math.floor(r.width * Setting.BoxPrecision), Math.floor(r.height * Setting.BoxPrecision)];
|
|
30
|
-
observer.observe(e);
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
function handler(entries: ResizeObserverEntry[]): void {
|
|
37
|
-
window.requestAnimationFrame(() => {
|
|
38
|
-
for (let entry of entries) {
|
|
39
|
-
let target = entry.target;
|
|
40
|
-
let id = target ? dom.getId(target) : null;
|
|
41
|
-
if (id) {
|
|
42
|
-
let v = dom.getValue(id);
|
|
43
|
-
let s = v.metadata.size;
|
|
44
|
-
let b = entry.borderBoxSize as any;
|
|
45
|
-
let w = null;
|
|
46
|
-
let h = null;
|
|
47
|
-
// Check if browser supports borderBoxSize property on ResizeObserverEntry object
|
|
48
|
-
// Otherwise, fall back to using getBoundingClientRect() to be cross browser compatible
|
|
49
|
-
// Reference: https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserverEntry/borderBoxSize
|
|
50
|
-
if(b && b.length > 0) {
|
|
51
|
-
w = Math.floor(b[0].inlineSize * Setting.BoxPrecision);
|
|
52
|
-
h = Math.floor(b[0].blockSize * Setting.BoxPrecision);
|
|
53
|
-
} else {
|
|
54
|
-
let r = target.getBoundingClientRect();
|
|
55
|
-
w = Math.floor(r.width * Setting.BoxPrecision);
|
|
56
|
-
h = Math.floor(r.height * Setting.BoxPrecision);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
// Capture new width & height only if they are different from what we have in in-memory cache
|
|
60
|
-
if (w !== s[0] && h !== s[1]) {
|
|
61
|
-
s = [w,h];
|
|
62
|
-
data.push({ id, width: w, height: h });
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
// Schedule encode only when we have at least one valid data entry
|
|
68
|
-
if (data.length > 0) { encode(Event.Box); }
|
|
69
|
-
});
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
export function reset(): void {
|
|
73
|
-
data = [];
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
export function stop(): void {
|
|
77
|
-
reset();
|
|
78
|
-
if (observer) {
|
|
79
|
-
observer.disconnect();
|
|
80
|
-
observer = null;
|
|
81
|
-
}
|
|
82
|
-
enabled = false;
|
|
83
|
-
}
|
package/src/layout/extract.ts
DELETED
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
import { Dimension, Extract, Metric, Region, RegionFilter } from "@clarity-types/core";
|
|
2
|
-
import { Constant, Setting } from "@clarity-types/data";
|
|
3
|
-
import * as dimension from "@src/data/dimension";
|
|
4
|
-
import * as metric from "@src/data/metric";
|
|
5
|
-
import * as region from "@src/layout/region";
|
|
6
|
-
|
|
7
|
-
const formatRegex = /1/g;
|
|
8
|
-
const digitsRegex = /[^0-9\.]/g;
|
|
9
|
-
const digitsWithCommaRegex = /[^0-9\.,]/g;
|
|
10
|
-
const regexCache: {[key: string]: RegExp} = {};
|
|
11
|
-
|
|
12
|
-
export function regions(root: ParentNode, value: Region[]): void {
|
|
13
|
-
for (let v of value) {
|
|
14
|
-
const [regionId, selector, filter, match] = v;
|
|
15
|
-
let valid = true;
|
|
16
|
-
switch (filter) {
|
|
17
|
-
case RegionFilter.Url: valid = match && !!top.location.href.match(regex(match)); break;
|
|
18
|
-
case RegionFilter.Javascript: valid = match && !!evaluate(match); break;
|
|
19
|
-
}
|
|
20
|
-
if (valid) { root.querySelectorAll(selector).forEach(e => region.observe(e, regionId.toString())); }
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export function metrics(root: ParentNode, value: Metric[]): void {
|
|
25
|
-
for (let v of value) {
|
|
26
|
-
const [metricId, source, match, scale] = v;
|
|
27
|
-
if (match) {
|
|
28
|
-
switch (source) {
|
|
29
|
-
case Extract.Text: root.querySelectorAll(match).forEach(e => { metric.max(metricId, num((e as HTMLElement).innerText, scale)); }); break;
|
|
30
|
-
case Extract.Attribute: root.querySelectorAll(`[${match}]`).forEach(e => { metric.max(metricId, num(e.getAttribute(match), scale, false)); }); break;
|
|
31
|
-
case Extract.Javascript: metric.max(metricId, evaluate(match, Constant.Number) as number); break;
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export function dimensions(root: ParentNode, value: Dimension[]): void {
|
|
38
|
-
for (let v of value) {
|
|
39
|
-
const [dimensionId, source, match] = v;
|
|
40
|
-
if (match) {
|
|
41
|
-
switch (source) {
|
|
42
|
-
case Extract.Text: root.querySelectorAll(match).forEach(e => { dimension.log(dimensionId, str((e as HTMLElement).innerText)); }); break;
|
|
43
|
-
case Extract.Attribute: root.querySelectorAll(`[${match}]`).forEach(e => { dimension.log(dimensionId, str(e.getAttribute(match))); }); break;
|
|
44
|
-
case Extract.Javascript: dimension.log(dimensionId, str(evaluate(match, Constant.String))); break;
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
function regex(match: string): RegExp {
|
|
51
|
-
regexCache[match] = match in regexCache ? regexCache[match] : new RegExp(match);
|
|
52
|
-
return regexCache[match];
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// The function below takes in a variable name in following format: "a.b.c" and safely evaluates its value in javascript context
|
|
56
|
-
// For instance, for a.b.c, it will first check window["a"]. If it exists, it will recursively look at: window["a"]["b"] and finally,
|
|
57
|
-
// return the value for window["a"]["b"]["c"].
|
|
58
|
-
function evaluate(variable: string, type: string = null, base: Object = window): any {
|
|
59
|
-
let parts = variable.split(Constant.Dot);
|
|
60
|
-
let first = parts.shift();
|
|
61
|
-
if (base && base[first]) {
|
|
62
|
-
if (parts.length > 0) { return evaluate(parts.join(Constant.Dot), type, base[first]); }
|
|
63
|
-
let output = type === null || type === typeof base[first] ? base[first] : null;
|
|
64
|
-
return output;
|
|
65
|
-
}
|
|
66
|
-
return null;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
function str(input: string): string {
|
|
70
|
-
// Automatically trim string to max of Setting.DimensionLimit to avoid fetching long strings
|
|
71
|
-
return input ? input.substr(0, Setting.DimensionLimit) : input;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
function num(text: string, scale: number, localize: boolean = true): number {
|
|
75
|
-
try {
|
|
76
|
-
scale = scale || 1;
|
|
77
|
-
// Reference: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat
|
|
78
|
-
let lang = document.documentElement.lang;
|
|
79
|
-
if (Intl && Intl.NumberFormat && lang && localize) {
|
|
80
|
-
text = text.replace(digitsWithCommaRegex, Constant.Empty);
|
|
81
|
-
// Infer current group and decimal separator from current locale
|
|
82
|
-
let group = Intl.NumberFormat(lang).format(11111).replace(formatRegex, Constant.Empty);
|
|
83
|
-
let decimal = Intl.NumberFormat(lang).format(1.1).replace(formatRegex, Constant.Empty);
|
|
84
|
-
|
|
85
|
-
// Parse number using inferred group and decimal separators
|
|
86
|
-
return Math.round(parseFloat(text
|
|
87
|
-
.replace(new RegExp('\\' + group, 'g'), Constant.Empty)
|
|
88
|
-
.replace(new RegExp('\\' + decimal), Constant.Dot)
|
|
89
|
-
) * scale);
|
|
90
|
-
}
|
|
91
|
-
// Fallback to en locale
|
|
92
|
-
return Math.round(parseFloat(text.replace(digitsRegex, Constant.Empty)) * scale);
|
|
93
|
-
} catch { return null; }
|
|
94
|
-
}
|