clarity-js 0.8.5 → 0.8.6-beta

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