clarity-js 0.7.2 → 0.7.4
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.insight.js +1 -0
- package/build/clarity.js +2054 -2076
- package/build/clarity.min.js +1 -1
- package/build/clarity.module.js +2051 -2071
- package/package.json +15 -13
- package/rollup.config.ts +29 -5
- package/src/core/blank.ts +9 -0
- package/src/core/config.ts +0 -1
- package/src/core/version.ts +1 -1
- package/src/data/encode.ts +1 -1
- package/src/data/extract.ts +45 -34
- package/src/data/upload.ts +22 -14
- package/src/diagnostic/index.ts +3 -3
- package/src/interaction/encode.ts +12 -12
- package/src/layout/dom.ts +4 -35
- package/src/layout/mutation.ts +4 -4
- package/src/performance/observer.ts +1 -6
- package/tsconfig.json +1 -1
- package/types/core.d.ts +0 -2
- package/types/data.d.ts +8 -3
- package/types/layout.d.ts +0 -1
package/package.json
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "clarity-js",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.4",
|
|
4
4
|
"description": "An analytics library that uses web page interactions to generate aggregated insights",
|
|
5
5
|
"author": "Microsoft Corp.",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"main": "build/clarity.js",
|
|
8
8
|
"module": "build/clarity.module.js",
|
|
9
9
|
"unpkg": "build/clarity.min.js",
|
|
10
|
+
"insight": "build/clarity.insight.js",
|
|
10
11
|
"types": "types/index.d.ts",
|
|
11
12
|
"keywords": [
|
|
12
13
|
"clarity",
|
|
@@ -26,28 +27,29 @@
|
|
|
26
27
|
"url": "https://github.com/microsoft/clarity/issues"
|
|
27
28
|
},
|
|
28
29
|
"devDependencies": {
|
|
29
|
-
"@rollup/plugin-
|
|
30
|
-
"@rollup/plugin-
|
|
30
|
+
"@rollup/plugin-alias": "^4.0.0",
|
|
31
|
+
"@rollup/plugin-commonjs": "^24.0.0",
|
|
32
|
+
"@rollup/plugin-node-resolve": "^15.0.0",
|
|
33
|
+
"@rollup/plugin-terser": "^0.4.0",
|
|
34
|
+
"@rollup/plugin-typescript": "^11.0.0",
|
|
31
35
|
"@types/chai": "^4.2.21",
|
|
32
|
-
"@types/mocha": "^
|
|
36
|
+
"@types/mocha": "^10.0.0",
|
|
33
37
|
"@types/resize-observer-browser": "^0.1.6",
|
|
34
38
|
"chai": "^4.2.0",
|
|
35
|
-
"del-cli": "^
|
|
36
|
-
"husky": "^
|
|
37
|
-
"lint-staged": "^
|
|
38
|
-
"mocha": "^
|
|
39
|
+
"del-cli": "^5.0.0",
|
|
40
|
+
"husky": "^8.0.0",
|
|
41
|
+
"lint-staged": "^13.1.0",
|
|
42
|
+
"mocha": "^10.2.0",
|
|
39
43
|
"playwright": "^1.6.2",
|
|
40
|
-
"rollup": "^
|
|
41
|
-
"
|
|
42
|
-
"rollup-plugin-typescript2": "^0.30.0",
|
|
43
|
-
"ts-mocha": "^8.0.0",
|
|
44
|
+
"rollup": "^3.0.0",
|
|
45
|
+
"ts-mocha": "^10.0.0",
|
|
44
46
|
"tslib": "^2.3.0",
|
|
45
47
|
"tslint": "^6.1.3",
|
|
46
48
|
"typescript": "^4.3.5"
|
|
47
49
|
},
|
|
48
50
|
"scripts": {
|
|
49
51
|
"build": "yarn build:clean && yarn build:main",
|
|
50
|
-
"build:main": "rollup -c rollup.config.ts",
|
|
52
|
+
"build:main": "rollup -c rollup.config.ts --configPlugin @rollup/plugin-typescript",
|
|
51
53
|
"build:clean": "del-cli build/*",
|
|
52
54
|
"test": "ts-mocha -p test/tsconfig.test.json test/**/*.test.ts",
|
|
53
55
|
"tslint": "tslint --project ./",
|
package/rollup.config.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
+
import alias from "@rollup/plugin-alias";
|
|
1
2
|
import commonjs from "@rollup/plugin-commonjs";
|
|
2
3
|
import resolve from "@rollup/plugin-node-resolve";
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import pkg from "./package.json";
|
|
4
|
+
import terser from "@rollup/plugin-terser";
|
|
5
|
+
import typescript from "@rollup/plugin-typescript";
|
|
6
|
+
import pkg from "./package.json" assert { type: 'json' };
|
|
6
7
|
|
|
7
8
|
export default [
|
|
8
9
|
{
|
|
@@ -13,7 +14,7 @@ export default [
|
|
|
13
14
|
],
|
|
14
15
|
plugins: [
|
|
15
16
|
resolve(),
|
|
16
|
-
typescript(
|
|
17
|
+
typescript(),
|
|
17
18
|
commonjs({ include: ["node_modules/**"] })
|
|
18
19
|
],
|
|
19
20
|
onwarn(message, warn) {
|
|
@@ -30,7 +31,30 @@ export default [
|
|
|
30
31
|
},
|
|
31
32
|
plugins: [
|
|
32
33
|
resolve(),
|
|
33
|
-
typescript(
|
|
34
|
+
typescript(),
|
|
35
|
+
terser({output: {comments: false}}),
|
|
36
|
+
commonjs({ include: ["node_modules/**"] })
|
|
37
|
+
]
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
input: "src/global.ts",
|
|
41
|
+
output: [ { file: pkg.insight, format: "iife", exports: "named" } ],
|
|
42
|
+
onwarn(message, warn) {
|
|
43
|
+
if (message.code === 'CIRCULAR_DEPENDENCY') { return; }
|
|
44
|
+
warn(message);
|
|
45
|
+
},
|
|
46
|
+
plugins: [
|
|
47
|
+
alias({
|
|
48
|
+
entries: [
|
|
49
|
+
{ find: '@src/interaction/change', replacement: '@src/core/blank' },
|
|
50
|
+
{ find: '@src/interaction/clipboard', replacement: '@src/core/blank' },
|
|
51
|
+
{ find: '@src/interaction/input', replacement: '@src/core/blank' },
|
|
52
|
+
{ find: '@src/interaction/pointer', replacement: '@src/core/blank' },
|
|
53
|
+
{ find: '@src/interaction/selection', replacement: '@src/core/blank' }
|
|
54
|
+
]
|
|
55
|
+
}),
|
|
56
|
+
resolve(),
|
|
57
|
+
typescript(),
|
|
34
58
|
terser({output: {comments: false}}),
|
|
35
59
|
commonjs({ include: ["node_modules/**"] })
|
|
36
60
|
]
|
package/src/core/config.ts
CHANGED
package/src/core/version.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
let version = "0.7.
|
|
1
|
+
let version = "0.7.4";
|
|
2
2
|
export default version;
|
package/src/data/encode.ts
CHANGED
|
@@ -110,7 +110,7 @@ export default function(event: Event): void {
|
|
|
110
110
|
let extractKeys = extract.keys;
|
|
111
111
|
for (let e of extractKeys) {
|
|
112
112
|
tokens.push(e);
|
|
113
|
-
tokens.push(extract.data[e]);
|
|
113
|
+
tokens.push([].concat(...extract.data[e]));
|
|
114
114
|
}
|
|
115
115
|
extract.reset();
|
|
116
116
|
queue(tokens, false);
|
package/src/data/extract.ts
CHANGED
|
@@ -1,38 +1,36 @@
|
|
|
1
1
|
import { ExtractSource, Syntax, Type } from "@clarity-types/core";
|
|
2
2
|
import { Event, Setting, ExtractData } from "@clarity-types/data";
|
|
3
|
-
import config from "@src/core/config";
|
|
4
3
|
import encode from "./encode";
|
|
5
4
|
import * as internal from "@src/diagnostic/internal";
|
|
6
5
|
import { Code, Constant, Severity } from "@clarity-types/data";
|
|
7
6
|
|
|
8
7
|
export let data: ExtractData = {};
|
|
9
|
-
export let keys:
|
|
10
|
-
|
|
11
|
-
let variables : { [key: number]: Syntax[] } = {};
|
|
12
|
-
let selectors : { [key: number]: string } = {};
|
|
13
|
-
export let fragments: string[] = [];
|
|
8
|
+
export let keys: number[] = [];
|
|
14
9
|
|
|
10
|
+
let variables : { [key: number]: { [key: number]: Syntax[] }} = {};
|
|
11
|
+
let selectors : { [key: number]: { [key: number]: string }} = {};
|
|
15
12
|
export function start(): void {
|
|
13
|
+
reset();
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function trigger(input: string): void {
|
|
16
17
|
try {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
18
|
+
var parts = input && input.length > 0 ? input.split(/ (.*)/) : [Constant.Empty];
|
|
19
|
+
var key = parseInt(parts[0]);
|
|
20
|
+
var values = parts.length > 1 ? JSON.parse(parts[1]) : {};
|
|
21
|
+
variables[key] = {};
|
|
22
|
+
selectors[key] = {};
|
|
23
|
+
for (var v in values) {
|
|
24
|
+
let id = parseInt(v);
|
|
25
|
+
let value = values[v] as string;
|
|
26
|
+
let source = value.startsWith(Constant.Tilde) ? ExtractSource.Javascript : ExtractSource.Text;
|
|
22
27
|
switch (source) {
|
|
23
28
|
case ExtractSource.Javascript:
|
|
24
|
-
let variable =
|
|
25
|
-
variables[key] = parse(variable);
|
|
26
|
-
break;
|
|
27
|
-
case ExtractSource.Cookie:
|
|
28
|
-
/*Todo: Add cookie extract logic*/
|
|
29
|
+
let variable = value.substring(1, value.length);
|
|
30
|
+
variables[key][id] = parse(variable);
|
|
29
31
|
break;
|
|
30
32
|
case ExtractSource.Text:
|
|
31
|
-
|
|
32
|
-
selectors[key] = match;
|
|
33
|
-
break;
|
|
34
|
-
case ExtractSource.Fragment:
|
|
35
|
-
fragments = e[i+2] as string[];
|
|
33
|
+
selectors[key][id] = value;
|
|
36
34
|
break;
|
|
37
35
|
}
|
|
38
36
|
}
|
|
@@ -49,13 +47,25 @@ export function clone(v: Syntax[]): Syntax[] {
|
|
|
49
47
|
export function compute(): void {
|
|
50
48
|
try {
|
|
51
49
|
for (let v in variables) {
|
|
52
|
-
let
|
|
53
|
-
if (
|
|
54
|
-
|
|
50
|
+
let key = parseInt(v);
|
|
51
|
+
if (!(key in keys)) {
|
|
52
|
+
let variableData = variables[key];
|
|
53
|
+
for (let v in variableData) {
|
|
54
|
+
let variableKey = parseInt(v);
|
|
55
|
+
let value = str(evaluate(clone(variableData[variableKey])));
|
|
56
|
+
if (value) { update(key, variableKey, value); }
|
|
57
|
+
}
|
|
55
58
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
+
let selectorData = selectors[key];
|
|
60
|
+
for (let s in selectorData) {
|
|
61
|
+
let selectorKey = parseInt(s);
|
|
62
|
+
let nodes = document.querySelectorAll(selectorData[selectorKey]) as NodeListOf<HTMLElement>;
|
|
63
|
+
if (nodes) {
|
|
64
|
+
let text = Array.from(nodes).map(e => e.innerText)
|
|
65
|
+
update(key, selectorKey, text.join(Constant.Seperator).substring(0, Setting.ExtractLimit));
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
59
69
|
}
|
|
60
70
|
}
|
|
61
71
|
catch (e) { internal.log(Code.Selector, Severity.Warning, e ? e.name : null); }
|
|
@@ -64,21 +74,22 @@ export function compute(): void {
|
|
|
64
74
|
}
|
|
65
75
|
|
|
66
76
|
export function reset(): void {
|
|
77
|
+
data = {};
|
|
67
78
|
keys = [];
|
|
79
|
+
variables = {};
|
|
80
|
+
selectors = {};
|
|
68
81
|
}
|
|
69
82
|
|
|
70
|
-
export function update(key:
|
|
71
|
-
if (!(key in data)
|
|
72
|
-
data[key] =
|
|
83
|
+
export function update(key: number, subkey: number, value: string): void {
|
|
84
|
+
if (!(key in data)) {
|
|
85
|
+
data[key] = []
|
|
73
86
|
keys.push(key);
|
|
74
87
|
}
|
|
88
|
+
data[key].push([subkey, value]);
|
|
75
89
|
}
|
|
76
90
|
|
|
77
91
|
export function stop(): void {
|
|
78
|
-
|
|
79
|
-
keys = [];
|
|
80
|
-
variables = {};
|
|
81
|
-
selectors = {};
|
|
92
|
+
reset();
|
|
82
93
|
}
|
|
83
94
|
|
|
84
95
|
function parse(variable: string): Syntax[] {
|
package/src/data/upload.ts
CHANGED
|
@@ -15,6 +15,7 @@ import * as metric from "@src/data/metric";
|
|
|
15
15
|
import * as ping from "@src/data/ping";
|
|
16
16
|
import * as timeline from "@src/interaction/timeline";
|
|
17
17
|
import * as region from "@src/layout/region";
|
|
18
|
+
import * as extract from "@src/data/extract";
|
|
18
19
|
|
|
19
20
|
let discoverBytes: number = 0;
|
|
20
21
|
let playbackBytes: number = 0;
|
|
@@ -242,19 +243,26 @@ function delay(): number {
|
|
|
242
243
|
}
|
|
243
244
|
|
|
244
245
|
function response(payload: string): void {
|
|
245
|
-
let
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
246
|
+
let lines = payload && payload.length > 0 ? payload.split("\n") : [];
|
|
247
|
+
for (var line of lines)
|
|
248
|
+
{
|
|
249
|
+
let parts = line && line.length > 0 ? line.split(/ (.*)/) : [Constant.Empty];
|
|
250
|
+
switch (parts[0]) {
|
|
251
|
+
case Constant.End:
|
|
252
|
+
// Clear out session storage and end the session so we can start fresh the next time
|
|
253
|
+
limit.trigger(Check.Server);
|
|
254
|
+
break;
|
|
255
|
+
case Constant.Upgrade:
|
|
256
|
+
// Upgrade current session to send back playback information
|
|
257
|
+
clarity.upgrade(Constant.Auto);
|
|
258
|
+
break;
|
|
259
|
+
case Constant.Action:
|
|
260
|
+
// Invoke action callback, if configured and has a valid value
|
|
261
|
+
if (config.action && parts.length > 1) { config.action(parts[1]); }
|
|
262
|
+
break;
|
|
263
|
+
case Constant.Extract:
|
|
264
|
+
if (parts.length > 1) { extract.trigger(parts[1]); }
|
|
265
|
+
break;
|
|
266
|
+
}
|
|
259
267
|
}
|
|
260
268
|
}
|
package/src/diagnostic/index.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import * as fraud from "
|
|
2
|
-
import * as internal from "
|
|
3
|
-
import * as script from "
|
|
1
|
+
import * as fraud from "@src/diagnostic/fraud";
|
|
2
|
+
import * as internal from "@src/diagnostic/internal";
|
|
3
|
+
import * as script from "@src/diagnostic/script";
|
|
4
4
|
|
|
5
5
|
export function start(): void {
|
|
6
6
|
fraud.start();
|
|
@@ -4,18 +4,18 @@ import { time } from "@src/core/time";
|
|
|
4
4
|
import * as baseline from "@src/data/baseline";
|
|
5
5
|
import { queue } from "@src/data/upload";
|
|
6
6
|
import { metadata } from "@src/layout/target";
|
|
7
|
-
import * as change from "
|
|
8
|
-
import * as click from "
|
|
9
|
-
import * as clipboard from "
|
|
10
|
-
import * as input from "
|
|
11
|
-
import * as pointer from "
|
|
12
|
-
import * as resize from "
|
|
13
|
-
import * as scroll from "
|
|
14
|
-
import * as selection from "
|
|
15
|
-
import * as submit from "
|
|
16
|
-
import * as timeline from "
|
|
17
|
-
import * as unload from "
|
|
18
|
-
import * as visibility from "
|
|
7
|
+
import * as change from "@src/interaction/change";
|
|
8
|
+
import * as click from "@src/interaction/click";
|
|
9
|
+
import * as clipboard from "@src/interaction/clipboard";
|
|
10
|
+
import * as input from "@src/interaction/input";
|
|
11
|
+
import * as pointer from "@src/interaction/pointer";
|
|
12
|
+
import * as resize from "@src/interaction/resize";
|
|
13
|
+
import * as scroll from "@src/interaction/scroll";
|
|
14
|
+
import * as selection from "@src/interaction/selection";
|
|
15
|
+
import * as submit from "@src/interaction/submit";
|
|
16
|
+
import * as timeline from "@src/interaction/timeline";
|
|
17
|
+
import * as unload from "@src/interaction/unload";
|
|
18
|
+
import * as visibility from "@src/interaction/visibility";
|
|
19
19
|
|
|
20
20
|
export default async function (type: Event, ts: number = null): Promise<void> {
|
|
21
21
|
let t = ts || time();
|
package/src/layout/dom.ts
CHANGED
|
@@ -6,8 +6,6 @@ import hash from "@src/core/hash";
|
|
|
6
6
|
import * as internal from "@src/diagnostic/internal";
|
|
7
7
|
import * as region from "@src/layout/region";
|
|
8
8
|
import * as selector from "@src/layout/selector";
|
|
9
|
-
import * as mutation from "@src/layout/mutation";
|
|
10
|
-
import * as extract from "@src/data/extract";
|
|
11
9
|
let index: number = 1;
|
|
12
10
|
let nodes: Node[] = [];
|
|
13
11
|
let values: NodeValue[] = [];
|
|
@@ -15,7 +13,6 @@ let updateMap: number[] = [];
|
|
|
15
13
|
let hashMap: { [hash: string]: number } = {};
|
|
16
14
|
let override = [];
|
|
17
15
|
let unmask = [];
|
|
18
|
-
let updatedFragments: { [fragment: number]: string } = {};
|
|
19
16
|
let maskText = [];
|
|
20
17
|
let maskExclude = [];
|
|
21
18
|
let maskDisable = [];
|
|
@@ -92,14 +89,12 @@ export function add(node: Node, parent: Node, data: NodeInfo, source: Source): v
|
|
|
92
89
|
let previousId = getPreviousId(node);
|
|
93
90
|
let parentValue: NodeValue = null;
|
|
94
91
|
let regionId = region.exists(node) ? id : null;
|
|
95
|
-
let fragmentId = null;
|
|
96
92
|
let fraudId = fraudMap.has(node) ? fraudMap.get(node) : null;
|
|
97
93
|
let privacyId = config.content ? Privacy.Sensitive : Privacy.TextImage
|
|
98
94
|
if (parentId >= 0 && values[parentId]) {
|
|
99
95
|
parentValue = values[parentId];
|
|
100
96
|
parentValue.children.push(id);
|
|
101
97
|
regionId = regionId === null ? parentValue.region : regionId;
|
|
102
|
-
fragmentId = parentValue.fragment;
|
|
103
98
|
fraudId = fraudId === null ? parentValue.metadata.fraud : fraudId;
|
|
104
99
|
privacyId = parentValue.metadata.privacy;
|
|
105
100
|
}
|
|
@@ -121,13 +116,12 @@ export function add(node: Node, parent: Node, data: NodeInfo, source: Source): v
|
|
|
121
116
|
hash: null,
|
|
122
117
|
region: regionId,
|
|
123
118
|
metadata: { active: true, suspend: false, privacy: privacyId, position: null, fraud: fraudId, size: null },
|
|
124
|
-
fragment: fragmentId,
|
|
125
119
|
};
|
|
126
120
|
|
|
127
121
|
privacy(node, values[id], parentValue);
|
|
128
122
|
updateSelector(values[id]);
|
|
129
123
|
size(values[id]);
|
|
130
|
-
track(id, source
|
|
124
|
+
track(id, source);
|
|
131
125
|
}
|
|
132
126
|
|
|
133
127
|
export function update(node: Node, parent: Node, data: NodeInfo, source: Source): void {
|
|
@@ -181,14 +175,9 @@ export function update(node: Node, parent: Node, data: NodeInfo, source: Source)
|
|
|
181
175
|
}
|
|
182
176
|
}
|
|
183
177
|
|
|
184
|
-
// track node if it is a part of scheduled fragment mutation
|
|
185
|
-
if(value.fragment && updatedFragments[value.fragment]) {
|
|
186
|
-
changed = true;
|
|
187
|
-
}
|
|
188
|
-
|
|
189
178
|
// Update selector
|
|
190
179
|
updateSelector(value);
|
|
191
|
-
track(id, source,
|
|
180
|
+
track(id, source, changed, parentChanged);
|
|
192
181
|
}
|
|
193
182
|
}
|
|
194
183
|
|
|
@@ -299,10 +288,6 @@ function updateSelector(value: NodeValue): void {
|
|
|
299
288
|
value.selector = [selector.get(s, Selector.Alpha), selector.get(s, Selector.Beta)];
|
|
300
289
|
value.hash = value.selector.map(x => x ? hash(x) : null) as [string, string];
|
|
301
290
|
value.hash.forEach(h => hashMap[h] = value.id);
|
|
302
|
-
// Match fragment configuration against both alpha and beta hash
|
|
303
|
-
if (value.hash.some(h => extract.fragments.indexOf(h) !== -1)) {
|
|
304
|
-
value.fragment = value.id;
|
|
305
|
-
}
|
|
306
291
|
}
|
|
307
292
|
|
|
308
293
|
export function hashText(hash: string): string {
|
|
@@ -344,11 +329,7 @@ export function updates(): NodeValue[] {
|
|
|
344
329
|
if (id in values) { output.push(values[id]); }
|
|
345
330
|
}
|
|
346
331
|
updateMap = [];
|
|
347
|
-
|
|
348
|
-
extract.update(updatedFragments[id], id, true)
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
updatedFragments = {}
|
|
332
|
+
|
|
352
333
|
return output;
|
|
353
334
|
}
|
|
354
335
|
|
|
@@ -377,19 +358,7 @@ function getPreviousId(node: Node): number {
|
|
|
377
358
|
return id;
|
|
378
359
|
}
|
|
379
360
|
|
|
380
|
-
function track(id: number, source: Source,
|
|
381
|
-
// if updated node is a part of fragment and the fragment is not being tracked currently, schedule a mutation on the fragment node
|
|
382
|
-
if (fragment && !updatedFragments[fragment]) {
|
|
383
|
-
let node = getNode(fragment)
|
|
384
|
-
let value = getValue(fragment);
|
|
385
|
-
if (node && value) {
|
|
386
|
-
mutation.schedule(node, true);
|
|
387
|
-
value.hash.forEach(h => {
|
|
388
|
-
if(extract.fragments.indexOf(h) !== -1) { updatedFragments[fragment] = h;}
|
|
389
|
-
});
|
|
390
|
-
}
|
|
391
|
-
}
|
|
392
|
-
|
|
361
|
+
function track(id: number, source: Source, changed: boolean = true, parentChanged: boolean = false): void {
|
|
393
362
|
// Keep track of the order in which mutations happened, they may not be sequential
|
|
394
363
|
// Edge case: If an element is added later on, and pre-discovered element is moved as a child.
|
|
395
364
|
// In that case, we need to reorder the pre-discovered element in the update list to keep visualization consistent.
|
package/src/layout/mutation.ts
CHANGED
|
@@ -210,7 +210,7 @@ async function processNodeList(list: NodeList, source: Source, timer: Timer): Pr
|
|
|
210
210
|
}
|
|
211
211
|
}
|
|
212
212
|
|
|
213
|
-
export function schedule(node: Node
|
|
213
|
+
export function schedule(node: Node): Node {
|
|
214
214
|
// Only schedule manual trigger for this node if it's not already in the queue
|
|
215
215
|
if (queue.indexOf(node) < 0) { queue.push(node); }
|
|
216
216
|
|
|
@@ -218,19 +218,19 @@ export function schedule(node: Node, fragment: boolean = false): Node {
|
|
|
218
218
|
// It's common for a webpage to call multiple synchronous "insertRule" / "deleteRule" calls.
|
|
219
219
|
// And in those cases we do not wish to monitor changes multiple times for the same node.
|
|
220
220
|
if (timeout) { clearTimeout(timeout); }
|
|
221
|
-
timeout = setTimeout(() => { trigger(
|
|
221
|
+
timeout = setTimeout(() => { trigger() }, Setting.LookAhead);
|
|
222
222
|
|
|
223
223
|
return node;
|
|
224
224
|
}
|
|
225
225
|
|
|
226
|
-
function trigger(
|
|
226
|
+
function trigger(): void {
|
|
227
227
|
for (let node of queue) {
|
|
228
228
|
// Generate a mutation for this node only if it still exists
|
|
229
229
|
if (node) {
|
|
230
230
|
let shadowRoot = node.nodeType === Node.DOCUMENT_FRAGMENT_NODE;
|
|
231
231
|
// Skip re-processing shadowRoot if it was already discovered
|
|
232
232
|
if (shadowRoot && dom.has(node)) { continue; }
|
|
233
|
-
generate(node, shadowRoot
|
|
233
|
+
generate(node, shadowRoot ? Constant.ChildList : Constant.CharacterData);
|
|
234
234
|
}
|
|
235
235
|
}
|
|
236
236
|
queue = [];
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Code, Constant, Dimension, Metric,
|
|
1
|
+
import { Code, Constant, Dimension, Metric, Severity } from "@clarity-types/data";
|
|
2
2
|
import config from "@src/core/config";
|
|
3
3
|
import { bind } from "@src/core/event";
|
|
4
4
|
import measure from "@src/core/measure";
|
|
@@ -81,11 +81,6 @@ function process(entries: PerformanceEntryList): void {
|
|
|
81
81
|
break;
|
|
82
82
|
}
|
|
83
83
|
}
|
|
84
|
-
if (performance && Constant.Memory in performance && performance[Constant.Memory].usedJSHeapSize) {
|
|
85
|
-
// Track consumed memory (MBs) where "memory" API is available
|
|
86
|
-
// Reference: https://developer.mozilla.org/en-US/docs/Web/API/Performance/memory
|
|
87
|
-
metric.max(Metric.UsedMemory, Math.abs(performance[Constant.Memory].usedJSHeapSize / Setting.MegaByte));
|
|
88
|
-
}
|
|
89
84
|
}
|
|
90
85
|
|
|
91
86
|
export function stop(): void {
|
package/tsconfig.json
CHANGED
package/types/core.d.ts
CHANGED
|
@@ -5,7 +5,6 @@ type TaskResolve = () => void;
|
|
|
5
5
|
type UploadCallback = (data: string) => void;
|
|
6
6
|
type Region = [number /* RegionId */, string /* Query Selector */];
|
|
7
7
|
type Checksum = [number /* FraudId */, string /* Query Selector */];
|
|
8
|
-
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
|
|
|
@@ -127,7 +126,6 @@ export interface Config {
|
|
|
127
126
|
mask?: string[];
|
|
128
127
|
unmask?: string[];
|
|
129
128
|
regions?: Region[];
|
|
130
|
-
extract?: Extract[];
|
|
131
129
|
cookies?: string[];
|
|
132
130
|
fraud?: boolean;
|
|
133
131
|
checksum?: Checksum[];
|
package/types/data.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Time } from "@clarity-types/core";
|
|
2
2
|
export type Target = (number | Node);
|
|
3
|
-
export type Token = (string | number | number[] | string[]);
|
|
3
|
+
export type Token = (string | number | number[] | string[] | (string | number)[]);
|
|
4
4
|
export type DecodedToken = (any | any[]);
|
|
5
5
|
|
|
6
6
|
export type MetadataCallback = (data: Metadata, playback: boolean) => void;
|
|
@@ -97,6 +97,9 @@ export const enum Metric {
|
|
|
97
97
|
Mobile = 27,
|
|
98
98
|
UploadTime = 28,
|
|
99
99
|
SinglePage = 29,
|
|
100
|
+
/**
|
|
101
|
+
* @deprecated Browser API is deprecated. Reference: https://developer.mozilla.org/en-US/docs/Web/API/Performance/memory
|
|
102
|
+
*/
|
|
100
103
|
UsedMemory = 30,
|
|
101
104
|
Iframed = 31,
|
|
102
105
|
MaxTouchPoints = 32,
|
|
@@ -260,6 +263,7 @@ export const enum Constant {
|
|
|
260
263
|
End = "END",
|
|
261
264
|
Upgrade = "UPGRADE",
|
|
262
265
|
Action = "ACTION",
|
|
266
|
+
Extract = "EXTRACT",
|
|
263
267
|
UserId = "userId",
|
|
264
268
|
SessionId = "sessionId",
|
|
265
269
|
PageId = "pageId",
|
|
@@ -281,7 +285,8 @@ export const enum Constant {
|
|
|
281
285
|
Tilde = "~",
|
|
282
286
|
ArrayStart = "[",
|
|
283
287
|
ConditionStart = "{",
|
|
284
|
-
ConditionEnd = "}"
|
|
288
|
+
ConditionEnd = "}",
|
|
289
|
+
Seperator = "<SEP>"
|
|
285
290
|
}
|
|
286
291
|
|
|
287
292
|
export const enum XMLReadyState {
|
|
@@ -401,7 +406,7 @@ export interface UpgradeData {
|
|
|
401
406
|
}
|
|
402
407
|
|
|
403
408
|
export interface ExtractData {
|
|
404
|
-
[key:
|
|
409
|
+
[key: number]: [number, string][]; // Array of [id, value] for every extracted data
|
|
405
410
|
}
|
|
406
411
|
|
|
407
412
|
export interface UploadData {
|