clarity-js 0.8.42 → 0.8.43
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/README.md +26 -26
- package/build/clarity.extended.js +1 -1
- package/build/clarity.insight.js +1 -1
- package/build/clarity.js +6043 -6030
- package/build/clarity.min.js +1 -1
- package/build/clarity.module.js +6043 -6030
- package/build/clarity.performance.js +1 -1
- package/package.json +70 -70
- package/rollup.config.ts +161 -161
- package/src/clarity.ts +65 -65
- package/src/core/api.ts +8 -8
- package/src/core/config.ts +29 -29
- package/src/core/copy.ts +3 -3
- package/src/core/dynamic.ts +13 -7
- package/src/core/event.ts +53 -53
- package/src/core/hash.ts +19 -19
- package/src/core/history.ts +71 -71
- package/src/core/index.ts +81 -81
- package/src/core/measure.ts +19 -19
- package/src/core/report.ts +28 -28
- package/src/core/scrub.ts +204 -202
- package/src/core/task.ts +181 -181
- package/src/core/throttle.ts +46 -46
- package/src/core/time.ts +26 -26
- package/src/core/timeout.ts +10 -10
- package/src/core/version.ts +2 -2
- package/src/data/baseline.ts +162 -162
- package/src/data/compress.ts +31 -31
- package/src/data/consent.ts +77 -77
- package/src/data/custom.ts +23 -23
- package/src/data/dimension.ts +53 -53
- package/src/data/encode.ts +155 -155
- package/src/data/envelope.ts +53 -53
- package/src/data/extract.ts +211 -211
- package/src/data/index.ts +50 -50
- package/src/data/limit.ts +44 -44
- package/src/data/metadata.ts +411 -408
- package/src/data/metric.ts +51 -51
- package/src/data/ping.ts +36 -36
- package/src/data/signal.ts +30 -30
- package/src/data/summary.ts +34 -34
- package/src/data/token.ts +39 -39
- package/src/data/upgrade.ts +44 -44
- package/src/data/upload.ts +333 -333
- package/src/data/variable.ts +83 -83
- package/src/diagnostic/encode.ts +40 -40
- package/src/diagnostic/fraud.ts +36 -36
- package/src/diagnostic/index.ts +13 -13
- package/src/diagnostic/internal.ts +28 -28
- package/src/diagnostic/script.ts +35 -35
- package/src/dynamic/agent/blank.ts +2 -2
- package/src/dynamic/agent/crisp.ts +40 -40
- package/src/dynamic/agent/encode.ts +25 -25
- package/src/dynamic/agent/index.ts +8 -8
- package/src/dynamic/agent/livechat.ts +58 -58
- package/src/dynamic/agent/tidio.ts +44 -44
- package/src/global.ts +6 -6
- package/src/index.ts +9 -9
- package/src/insight/blank.ts +14 -14
- package/src/insight/encode.ts +60 -60
- package/src/insight/snapshot.ts +114 -114
- package/src/interaction/change.ts +38 -38
- package/src/interaction/click.ts +173 -173
- package/src/interaction/clipboard.ts +32 -32
- package/src/interaction/encode.ts +210 -210
- package/src/interaction/index.ts +60 -60
- package/src/interaction/input.ts +57 -57
- package/src/interaction/pointer.ts +137 -137
- package/src/interaction/resize.ts +50 -50
- package/src/interaction/scroll.ts +129 -129
- package/src/interaction/selection.ts +66 -66
- package/src/interaction/submit.ts +30 -30
- package/src/interaction/timeline.ts +69 -69
- package/src/interaction/unload.ts +26 -26
- package/src/interaction/visibility.ts +27 -27
- package/src/layout/animation.ts +133 -133
- package/src/layout/custom.ts +42 -42
- package/src/layout/discover.ts +31 -31
- package/src/layout/document.ts +46 -46
- package/src/layout/dom.ts +439 -439
- package/src/layout/encode.ts +154 -154
- package/src/layout/index.ts +42 -42
- package/src/layout/mutation.ts +411 -411
- package/src/layout/node.ts +294 -294
- package/src/layout/offset.ts +19 -19
- package/src/layout/region.ts +151 -151
- package/src/layout/schema.ts +63 -63
- package/src/layout/selector.ts +82 -82
- package/src/layout/style.ts +159 -159
- package/src/layout/target.ts +32 -32
- package/src/layout/traverse.ts +27 -27
- package/src/performance/blank.ts +9 -9
- package/src/performance/encode.ts +31 -31
- package/src/performance/index.ts +12 -12
- package/src/performance/interaction.ts +125 -125
- package/src/performance/navigation.ts +31 -31
- package/src/performance/observer.ts +112 -112
- package/src/queue.ts +33 -33
- package/test/core.test.ts +139 -139
- package/test/helper.ts +162 -162
- package/test/html/core.html +27 -27
- package/test/stub.test.ts +7 -7
- package/test/tsconfig.test.json +5 -5
- package/tsconfig.json +21 -21
- package/tslint.json +32 -32
- package/types/agent.d.ts +39 -39
- package/types/core.d.ts +150 -150
- package/types/data.d.ts +572 -571
- package/types/diagnostic.d.ts +24 -24
- package/types/global.d.ts +30 -30
- package/types/index.d.ts +40 -40
- package/types/interaction.d.ts +177 -177
- package/types/layout.d.ts +276 -276
- package/types/performance.d.ts +31 -31
package/src/core/scrub.ts
CHANGED
|
@@ -1,202 +1,204 @@
|
|
|
1
|
-
import { Privacy } from "@clarity-types/core";
|
|
2
|
-
import * as Data from "@clarity-types/data";
|
|
3
|
-
import * as Layout from "@clarity-types/layout";
|
|
4
|
-
import config from "@src/core/config";
|
|
5
|
-
|
|
6
|
-
const catchallRegex = /\S/gi;
|
|
7
|
-
const maxUrlLength = 255;
|
|
8
|
-
let unicodeRegex = true;
|
|
9
|
-
let digitRegex = null;
|
|
10
|
-
let letterRegex = null;
|
|
11
|
-
let currencyRegex = null;
|
|
12
|
-
|
|
13
|
-
export function text(value: string, hint: string, privacy: Privacy, mangle: boolean = false, type?: string): string {
|
|
14
|
-
if (value) {
|
|
15
|
-
if (hint == "input" && (type === "checkbox" || type === "radio")) {
|
|
16
|
-
return value;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
switch (privacy) {
|
|
20
|
-
case Privacy.None:
|
|
21
|
-
return value;
|
|
22
|
-
case Privacy.Sensitive:
|
|
23
|
-
switch (hint) {
|
|
24
|
-
case Layout.Constant.TextTag:
|
|
25
|
-
case "value":
|
|
26
|
-
case "placeholder":
|
|
27
|
-
case "click":
|
|
28
|
-
return redact(value);
|
|
29
|
-
case "input":
|
|
30
|
-
case "change":
|
|
31
|
-
return mangleToken(value);
|
|
32
|
-
}
|
|
33
|
-
return value;
|
|
34
|
-
case Privacy.Text:
|
|
35
|
-
case Privacy.TextImage:
|
|
36
|
-
switch (hint) {
|
|
37
|
-
case Layout.Constant.TextTag:
|
|
38
|
-
case Layout.Constant.DataAttribute:
|
|
39
|
-
return mangle ? mangleText(value) : mask(value);
|
|
40
|
-
case "src":
|
|
41
|
-
case "srcset":
|
|
42
|
-
case "title":
|
|
43
|
-
case "alt":
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
case "
|
|
54
|
-
case "
|
|
55
|
-
|
|
56
|
-
case "
|
|
57
|
-
return
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
case
|
|
66
|
-
|
|
67
|
-
case "
|
|
68
|
-
case "
|
|
69
|
-
|
|
70
|
-
case "
|
|
71
|
-
return Data.Constant.
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
case
|
|
80
|
-
|
|
81
|
-
case "
|
|
82
|
-
case "
|
|
83
|
-
|
|
84
|
-
case "
|
|
85
|
-
|
|
86
|
-
case "
|
|
87
|
-
case "
|
|
88
|
-
case "
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
let
|
|
123
|
-
let
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
let
|
|
163
|
-
let
|
|
164
|
-
let
|
|
165
|
-
let
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
//
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
token =
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
}
|
|
1
|
+
import { Privacy } from "@clarity-types/core";
|
|
2
|
+
import * as Data from "@clarity-types/data";
|
|
3
|
+
import * as Layout from "@clarity-types/layout";
|
|
4
|
+
import config from "@src/core/config";
|
|
5
|
+
|
|
6
|
+
const catchallRegex = /\S/gi;
|
|
7
|
+
const maxUrlLength = 255;
|
|
8
|
+
let unicodeRegex = true;
|
|
9
|
+
let digitRegex = null;
|
|
10
|
+
let letterRegex = null;
|
|
11
|
+
let currencyRegex = null;
|
|
12
|
+
|
|
13
|
+
export function text(value: string, hint: string, privacy: Privacy, mangle: boolean = false, type?: string): string {
|
|
14
|
+
if (value) {
|
|
15
|
+
if (hint == "input" && (type === "checkbox" || type === "radio")) {
|
|
16
|
+
return value;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
switch (privacy) {
|
|
20
|
+
case Privacy.None:
|
|
21
|
+
return value;
|
|
22
|
+
case Privacy.Sensitive:
|
|
23
|
+
switch (hint) {
|
|
24
|
+
case Layout.Constant.TextTag:
|
|
25
|
+
case "value":
|
|
26
|
+
case "placeholder":
|
|
27
|
+
case "click":
|
|
28
|
+
return redact(value);
|
|
29
|
+
case "input":
|
|
30
|
+
case "change":
|
|
31
|
+
return mangleToken(value);
|
|
32
|
+
}
|
|
33
|
+
return value;
|
|
34
|
+
case Privacy.Text:
|
|
35
|
+
case Privacy.TextImage:
|
|
36
|
+
switch (hint) {
|
|
37
|
+
case Layout.Constant.TextTag:
|
|
38
|
+
case Layout.Constant.DataAttribute:
|
|
39
|
+
return mangle ? mangleText(value) : mask(value);
|
|
40
|
+
case "src":
|
|
41
|
+
case "srcset":
|
|
42
|
+
case "title":
|
|
43
|
+
case "alt":
|
|
44
|
+
case "href":
|
|
45
|
+
case "xlink:href":
|
|
46
|
+
if (privacy === Privacy.TextImage) {
|
|
47
|
+
if (hint === 'src' && value?.startsWith('blob:')) {
|
|
48
|
+
return 'blob:';
|
|
49
|
+
}
|
|
50
|
+
return Data.Constant.Empty;
|
|
51
|
+
}
|
|
52
|
+
return value;
|
|
53
|
+
case "value":
|
|
54
|
+
case "click":
|
|
55
|
+
case "input":
|
|
56
|
+
case "change":
|
|
57
|
+
return mangleToken(value);
|
|
58
|
+
case "placeholder":
|
|
59
|
+
return mask(value);
|
|
60
|
+
}
|
|
61
|
+
break;
|
|
62
|
+
case Privacy.Exclude:
|
|
63
|
+
switch (hint) {
|
|
64
|
+
case Layout.Constant.TextTag:
|
|
65
|
+
case Layout.Constant.DataAttribute:
|
|
66
|
+
return mangle ? mangleText(value) : mask(value);
|
|
67
|
+
case "value":
|
|
68
|
+
case "input":
|
|
69
|
+
case "click":
|
|
70
|
+
case "change":
|
|
71
|
+
return Array(Data.Setting.WordLength).join(Data.Constant.Mask);
|
|
72
|
+
case "checksum":
|
|
73
|
+
return Data.Constant.Empty;
|
|
74
|
+
}
|
|
75
|
+
break;
|
|
76
|
+
case Privacy.Snapshot:
|
|
77
|
+
switch (hint) {
|
|
78
|
+
case Layout.Constant.TextTag:
|
|
79
|
+
case Layout.Constant.DataAttribute:
|
|
80
|
+
return scrub(value, Data.Constant.Letter, Data.Constant.Digit);
|
|
81
|
+
case "value":
|
|
82
|
+
case "input":
|
|
83
|
+
case "click":
|
|
84
|
+
case "change":
|
|
85
|
+
return Array(Data.Setting.WordLength).join(Data.Constant.Mask);
|
|
86
|
+
case "checksum":
|
|
87
|
+
case "src":
|
|
88
|
+
case "srcset":
|
|
89
|
+
case "alt":
|
|
90
|
+
case "title":
|
|
91
|
+
return Data.Constant.Empty;
|
|
92
|
+
}
|
|
93
|
+
break;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return value;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export function url(input: string, electron: boolean = false, truncate: boolean = false): string {
|
|
100
|
+
let result = input;
|
|
101
|
+
// Replace the URL for Electron apps so we don't send back file:/// URL
|
|
102
|
+
if (electron) {
|
|
103
|
+
result = `${Data.Constant.HTTPS}${Data.Constant.Electron}`;
|
|
104
|
+
} else {
|
|
105
|
+
let drop = config.drop;
|
|
106
|
+
if (drop && drop.length > 0 && input && input.indexOf("?") > 0) {
|
|
107
|
+
let [path, query] = input.split("?");
|
|
108
|
+
let swap = Data.Constant.Dropped;
|
|
109
|
+
result = path + "?" + query.split("&").map(p => drop.some(x => p.indexOf(`${x}=`) === 0) ? `${p.split("=")[0]}=${swap}` : p).join("&");
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (truncate) {
|
|
114
|
+
result = result.substring(0, maxUrlLength);
|
|
115
|
+
}
|
|
116
|
+
return result;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function mangleText(value: string): string {
|
|
120
|
+
let trimmed = value.trim();
|
|
121
|
+
if (trimmed.length > 0) {
|
|
122
|
+
let first = trimmed[0];
|
|
123
|
+
let index = value.indexOf(first);
|
|
124
|
+
let prefix = value.substr(0, index);
|
|
125
|
+
let suffix = value.substr(index + trimmed.length);
|
|
126
|
+
return `${prefix}${trimmed.length.toString(36)}${suffix}`;
|
|
127
|
+
}
|
|
128
|
+
return value;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function mask(value: string): string {
|
|
132
|
+
return value.replace(catchallRegex, Data.Constant.Mask);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export function scrub(value: string, letter: string, digit: string): string {
|
|
136
|
+
regex(); // Initialize regular expressions
|
|
137
|
+
return value ? value.replace(letterRegex, letter).replace(digitRegex, digit) : value;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function mangleToken(value: string): string {
|
|
141
|
+
let length = ((Math.floor(value.length / Data.Setting.WordLength) + 1) * Data.Setting.WordLength);
|
|
142
|
+
let output: string = Layout.Constant.Empty;
|
|
143
|
+
for (let i = 0; i < length; i++) {
|
|
144
|
+
output += i > 0 && i % Data.Setting.WordLength === 0 ? Data.Constant.Space : Data.Constant.Mask;
|
|
145
|
+
}
|
|
146
|
+
return output;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function regex(): void {
|
|
150
|
+
// Initialize unicode regex, if supported by the browser
|
|
151
|
+
// Reference: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions/Unicode_Property_Escapes
|
|
152
|
+
if (unicodeRegex && digitRegex === null) {
|
|
153
|
+
try {
|
|
154
|
+
digitRegex = new RegExp("\\p{N}", "gu");
|
|
155
|
+
letterRegex = new RegExp("\\p{L}", "gu");
|
|
156
|
+
currencyRegex = new RegExp("\\p{Sc}", "gu");
|
|
157
|
+
} catch { unicodeRegex = false; }
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function redact(value: string): string {
|
|
162
|
+
let spaceIndex = -1;
|
|
163
|
+
let gap = 0;
|
|
164
|
+
let hasDigit = false;
|
|
165
|
+
let hasEmail = false;
|
|
166
|
+
let hasWhitespace = false;
|
|
167
|
+
let array = null;
|
|
168
|
+
|
|
169
|
+
regex(); // Initialize regular expressions
|
|
170
|
+
|
|
171
|
+
for (let i = 0; i < value.length; i++) {
|
|
172
|
+
let c = value.charCodeAt(i);
|
|
173
|
+
hasDigit = hasDigit || (c >= Data.Character.Zero && c <= Data.Character.Nine); // Check for digits in the current word
|
|
174
|
+
hasEmail = hasEmail || c === Data.Character.At; // Check for @ sign anywhere within the current word
|
|
175
|
+
hasWhitespace = c === Data.Character.Tab || c === Data.Character.NewLine || c === Data.Character.Return || c === Data.Character.Blank;
|
|
176
|
+
|
|
177
|
+
// Process each word as an individual token to redact any sensitive information
|
|
178
|
+
if (i === 0 || i === value.length - 1 || hasWhitespace) {
|
|
179
|
+
// Performance optimization: Lazy load string -> array conversion only when required
|
|
180
|
+
if (hasDigit || hasEmail) {
|
|
181
|
+
if (array === null) { array = value.split(Data.Constant.Empty); }
|
|
182
|
+
// Work on a token at a time so we don't have to apply regex to a larger string
|
|
183
|
+
let token = value.substring(spaceIndex + 1, hasWhitespace ? i : i + 1);
|
|
184
|
+
// Check if unicode regex is supported, otherwise fallback to calling mask function on this token
|
|
185
|
+
if (unicodeRegex && currencyRegex !== null) {
|
|
186
|
+
// Do not redact information if the token contains a currency symbol
|
|
187
|
+
token = token.match(currencyRegex) ? token : scrub(token, Data.Constant.Letter, Data.Constant.Digit);
|
|
188
|
+
} else {
|
|
189
|
+
token = mask(token);
|
|
190
|
+
}
|
|
191
|
+
// Merge token back into array at the right place
|
|
192
|
+
array.splice(spaceIndex + 1 - gap, token.length, token);
|
|
193
|
+
gap += token.length - 1;
|
|
194
|
+
}
|
|
195
|
+
// Reset digit and email flags after every word boundary, except the beginning of string
|
|
196
|
+
if (hasWhitespace) {
|
|
197
|
+
hasDigit = false;
|
|
198
|
+
hasEmail = false;
|
|
199
|
+
spaceIndex = i;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
return array ? array.join(Data.Constant.Empty) : value;
|
|
204
|
+
}
|