clarity-js 0.6.30 → 0.6.33
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 +2137 -2051
- package/build/clarity.min.js +1 -1
- package/build/clarity.module.js +2137 -2051
- package/package.json +1 -1
- package/src/core/api.ts +8 -0
- package/src/core/config.ts +1 -2
- package/src/core/event.ts +4 -3
- 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/upload.ts +11 -8
- package/src/diagnostic/internal.ts +1 -14
- package/src/layout/dom.ts +63 -21
- package/src/layout/mutation.ts +14 -12
- package/src/layout/node.ts +1 -0
- package/types/core.d.ts +25 -13
- package/types/data.d.ts +16 -3
- package/types/layout.d.ts +2 -2
- package/src/layout/extract.ts +0 -94
package/types/core.d.ts
CHANGED
|
@@ -3,9 +3,8 @@ import * as Data from "./data";
|
|
|
3
3
|
type TaskFunction = () => Promise<void>;
|
|
4
4
|
type TaskResolve = () => void;
|
|
5
5
|
type UploadCallback = (data: string) => void;
|
|
6
|
-
type Region = [number /* RegionId */, string /* Query Selector
|
|
7
|
-
type
|
|
8
|
-
type Dimension = [Data.Dimension /* DimensionId */, Extract /* Extract Filter */, string /* Match Value */];
|
|
6
|
+
type Region = [number /* RegionId */, string /* Query Selector */];
|
|
7
|
+
export type Extract = ExtractSource /* Extraction Source */ | number /* Extract Id */ | string | string[] /* Hash or Query Selector or String Token */;
|
|
9
8
|
|
|
10
9
|
/* Enum */
|
|
11
10
|
|
|
@@ -21,7 +20,6 @@ export const enum Time {
|
|
|
21
20
|
Day = 24 * 60 * 60 * 1000
|
|
22
21
|
}
|
|
23
22
|
|
|
24
|
-
|
|
25
23
|
export const enum Task {
|
|
26
24
|
Wait = 0,
|
|
27
25
|
Run = 1,
|
|
@@ -32,15 +30,23 @@ export const enum Setting {
|
|
|
32
30
|
LongTask = 30, // 30ms
|
|
33
31
|
}
|
|
34
32
|
|
|
35
|
-
export const enum
|
|
36
|
-
|
|
37
|
-
|
|
33
|
+
export const enum ExtractSource {
|
|
34
|
+
Javascript = 0,
|
|
35
|
+
Cookie = 1,
|
|
36
|
+
Text = 2,
|
|
37
|
+
Fragment = 3
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export const enum Type {
|
|
41
|
+
Array = 1,
|
|
42
|
+
Object = 2,
|
|
43
|
+
Simple = 3
|
|
38
44
|
}
|
|
39
45
|
|
|
40
|
-
export
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
46
|
+
export type Syntax = {
|
|
47
|
+
name: string,
|
|
48
|
+
type: Type,
|
|
49
|
+
condition: string
|
|
44
50
|
}
|
|
45
51
|
|
|
46
52
|
export const enum Privacy {
|
|
@@ -119,11 +125,17 @@ export interface Config {
|
|
|
119
125
|
mask?: string[];
|
|
120
126
|
unmask?: string[];
|
|
121
127
|
regions?: Region[];
|
|
122
|
-
|
|
123
|
-
dimensions?: Dimension[];
|
|
128
|
+
extract?: Extract[];
|
|
124
129
|
cookies?: string[];
|
|
125
130
|
report?: string;
|
|
126
131
|
upload?: string | UploadCallback;
|
|
127
132
|
fallback?: string;
|
|
128
133
|
upgrade?: (key: string) => void;
|
|
129
134
|
}
|
|
135
|
+
|
|
136
|
+
export const enum Constant {
|
|
137
|
+
Zone = "Zone",
|
|
138
|
+
Symbol = "__symbol__",
|
|
139
|
+
AddEventListener = "addEventListener",
|
|
140
|
+
RemoveEventListener = "removeEventListener"
|
|
141
|
+
}
|
package/types/data.d.ts
CHANGED
|
@@ -54,7 +54,8 @@ export const enum Event {
|
|
|
54
54
|
Summary = 36,
|
|
55
55
|
Box = 37,
|
|
56
56
|
Clipboard = 38,
|
|
57
|
-
Submit = 39
|
|
57
|
+
Submit = 39,
|
|
58
|
+
Extract = 40
|
|
58
59
|
}
|
|
59
60
|
|
|
60
61
|
export const enum Metric {
|
|
@@ -135,7 +136,11 @@ export const enum Code {
|
|
|
135
136
|
CallStackDepth = 4,
|
|
136
137
|
Selector = 5,
|
|
137
138
|
Metric = 6,
|
|
138
|
-
|
|
139
|
+
/**
|
|
140
|
+
* @deprecated No longer support ContentSecurityPolicy
|
|
141
|
+
*/
|
|
142
|
+
ContentSecurityPolicy = 7,
|
|
143
|
+
Config = 8
|
|
139
144
|
}
|
|
140
145
|
|
|
141
146
|
export const enum Severity {
|
|
@@ -184,7 +189,8 @@ export const enum Setting {
|
|
|
184
189
|
MaxFirstPayloadBytes = 1 * 1024 * 1024, // 1MB: Cap the very first payload to a maximum of 1MB
|
|
185
190
|
UploadFactor = 3, // Slow down sequence by specified factor
|
|
186
191
|
MinUploadDelay = 100, // Minimum time before we are ready to flush events to the server
|
|
187
|
-
MaxUploadDelay = 30 * Time.Second // Do flush out payload once every 30s
|
|
192
|
+
MaxUploadDelay = 30 * Time.Second, // Do flush out payload once every 30s,
|
|
193
|
+
ExtractLimit = 10000 // Do not extract more than 10000 characters
|
|
188
194
|
}
|
|
189
195
|
|
|
190
196
|
export const enum Character {
|
|
@@ -245,6 +251,9 @@ export const enum Constant {
|
|
|
245
251
|
Accept = "Accept",
|
|
246
252
|
ClarityGzip = "application/x-clarity-gzip",
|
|
247
253
|
Tilde = "~",
|
|
254
|
+
ArrayStart = "[",
|
|
255
|
+
ConditionStart = "{",
|
|
256
|
+
ConditionEnd = "}"
|
|
248
257
|
}
|
|
249
258
|
|
|
250
259
|
export const enum XMLReadyState {
|
|
@@ -363,6 +372,10 @@ export interface UpgradeData {
|
|
|
363
372
|
key: string;
|
|
364
373
|
}
|
|
365
374
|
|
|
375
|
+
export interface ExtractData {
|
|
376
|
+
[key: string]: string | number;
|
|
377
|
+
}
|
|
378
|
+
|
|
366
379
|
export interface UploadData {
|
|
367
380
|
sequence: number;
|
|
368
381
|
attempts: number;
|
package/types/layout.d.ts
CHANGED
|
@@ -40,6 +40,7 @@ export const enum Constant {
|
|
|
40
40
|
Src = "src",
|
|
41
41
|
Srcset = "srcset",
|
|
42
42
|
Box = "#",
|
|
43
|
+
Bang = "!",
|
|
43
44
|
Period = ".",
|
|
44
45
|
MaskData = "data-clarity-mask",
|
|
45
46
|
UnmaskData = "data-clarity-unmask",
|
|
@@ -74,8 +75,6 @@ export const enum Constant {
|
|
|
74
75
|
BorderBox = "border-box",
|
|
75
76
|
Value = "value",
|
|
76
77
|
MutationObserver = "MutationObserver",
|
|
77
|
-
Zone = "Zone",
|
|
78
|
-
Symbol = "__symbol__",
|
|
79
78
|
JsonLD = "application/ld+json",
|
|
80
79
|
String = "string",
|
|
81
80
|
Number = "number",
|
|
@@ -155,6 +154,7 @@ export interface NodeValue {
|
|
|
155
154
|
hash: [string, string];
|
|
156
155
|
region: number;
|
|
157
156
|
metadata: NodeMeta;
|
|
157
|
+
fragment: number;
|
|
158
158
|
}
|
|
159
159
|
|
|
160
160
|
export interface NodeMeta {
|
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
|
-
}
|