clarity-js 0.8.40 → 0.8.42

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 (113) 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 +6027 -6027
  5. package/build/clarity.min.js +1 -1
  6. package/build/clarity.module.js +6027 -6027
  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/event.ts +53 -53
  15. package/src/core/hash.ts +19 -19
  16. package/src/core/history.ts +71 -71
  17. package/src/core/index.ts +81 -81
  18. package/src/core/measure.ts +19 -19
  19. package/src/core/report.ts +28 -28
  20. package/src/core/scrub.ts +202 -202
  21. package/src/core/task.ts +181 -181
  22. package/src/core/throttle.ts +46 -46
  23. package/src/core/time.ts +26 -26
  24. package/src/core/timeout.ts +10 -10
  25. package/src/core/version.ts +2 -2
  26. package/src/data/baseline.ts +162 -162
  27. package/src/data/compress.ts +31 -31
  28. package/src/data/consent.ts +77 -77
  29. package/src/data/custom.ts +23 -23
  30. package/src/data/dimension.ts +53 -53
  31. package/src/data/encode.ts +155 -155
  32. package/src/data/envelope.ts +53 -53
  33. package/src/data/extract.ts +211 -211
  34. package/src/data/index.ts +50 -50
  35. package/src/data/limit.ts +44 -44
  36. package/src/data/metadata.ts +408 -408
  37. package/src/data/metric.ts +51 -51
  38. package/src/data/ping.ts +36 -36
  39. package/src/data/signal.ts +30 -30
  40. package/src/data/summary.ts +34 -34
  41. package/src/data/token.ts +39 -39
  42. package/src/data/upgrade.ts +44 -44
  43. package/src/data/upload.ts +333 -333
  44. package/src/data/variable.ts +83 -83
  45. package/src/diagnostic/encode.ts +40 -40
  46. package/src/diagnostic/fraud.ts +36 -36
  47. package/src/diagnostic/index.ts +13 -13
  48. package/src/diagnostic/internal.ts +28 -28
  49. package/src/diagnostic/script.ts +35 -35
  50. package/src/dynamic/agent/blank.ts +2 -2
  51. package/src/dynamic/agent/crisp.ts +40 -40
  52. package/src/dynamic/agent/encode.ts +25 -25
  53. package/src/dynamic/agent/index.ts +8 -8
  54. package/src/dynamic/agent/livechat.ts +58 -58
  55. package/src/dynamic/agent/tidio.ts +44 -44
  56. package/src/global.ts +6 -6
  57. package/src/index.ts +9 -9
  58. package/src/insight/blank.ts +14 -14
  59. package/src/insight/encode.ts +60 -60
  60. package/src/insight/snapshot.ts +114 -114
  61. package/src/interaction/change.ts +38 -38
  62. package/src/interaction/click.ts +173 -173
  63. package/src/interaction/clipboard.ts +32 -32
  64. package/src/interaction/encode.ts +210 -210
  65. package/src/interaction/index.ts +60 -60
  66. package/src/interaction/input.ts +57 -57
  67. package/src/interaction/pointer.ts +137 -137
  68. package/src/interaction/resize.ts +50 -50
  69. package/src/interaction/scroll.ts +129 -129
  70. package/src/interaction/selection.ts +66 -66
  71. package/src/interaction/submit.ts +30 -30
  72. package/src/interaction/timeline.ts +69 -69
  73. package/src/interaction/unload.ts +26 -26
  74. package/src/interaction/visibility.ts +27 -27
  75. package/src/layout/animation.ts +133 -133
  76. package/src/layout/custom.ts +42 -42
  77. package/src/layout/discover.ts +31 -31
  78. package/src/layout/document.ts +46 -46
  79. package/src/layout/dom.ts +439 -439
  80. package/src/layout/encode.ts +154 -154
  81. package/src/layout/index.ts +42 -42
  82. package/src/layout/mutation.ts +411 -411
  83. package/src/layout/node.ts +294 -294
  84. package/src/layout/offset.ts +19 -19
  85. package/src/layout/region.ts +151 -151
  86. package/src/layout/schema.ts +63 -63
  87. package/src/layout/selector.ts +82 -82
  88. package/src/layout/style.ts +159 -159
  89. package/src/layout/target.ts +32 -32
  90. package/src/layout/traverse.ts +27 -27
  91. package/src/performance/blank.ts +9 -9
  92. package/src/performance/encode.ts +31 -31
  93. package/src/performance/index.ts +12 -12
  94. package/src/performance/interaction.ts +125 -125
  95. package/src/performance/navigation.ts +31 -31
  96. package/src/performance/observer.ts +112 -112
  97. package/src/queue.ts +33 -33
  98. package/test/core.test.ts +139 -139
  99. package/test/helper.ts +162 -162
  100. package/test/html/core.html +27 -27
  101. package/test/stub.test.ts +7 -7
  102. package/test/tsconfig.test.json +5 -5
  103. package/tsconfig.json +21 -21
  104. package/tslint.json +32 -32
  105. package/types/agent.d.ts +39 -39
  106. package/types/core.d.ts +150 -150
  107. package/types/data.d.ts +571 -571
  108. package/types/diagnostic.d.ts +24 -24
  109. package/types/global.d.ts +30 -30
  110. package/types/index.d.ts +40 -40
  111. package/types/interaction.d.ts +177 -177
  112. package/types/layout.d.ts +276 -276
  113. package/types/performance.d.ts +31 -31
package/src/core/scrub.ts CHANGED
@@ -1,202 +1,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
- 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
+ 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
+ }