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