clarity-js 0.6.27 → 0.6.31

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.js CHANGED
@@ -4,10 +4,49 @@ Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var upload$1 = /*#__PURE__*/Object.freeze({
6
6
  __proto__: null,
7
- get track () { return track; },
8
- get start () { return start$9; },
7
+ get track () { return track$1; },
8
+ get start () { return start$c; },
9
9
  get queue () { return queue; },
10
- get stop () { return stop$8; }
10
+ get stop () { return stop$b; }
11
+ });
12
+ var limit = /*#__PURE__*/Object.freeze({
13
+ __proto__: null,
14
+ get data () { return data$4; },
15
+ get start () { return start$b; },
16
+ get check () { return check$2; },
17
+ get trigger () { return trigger; },
18
+ get compute () { return compute$3; },
19
+ get stop () { return stop$a; }
20
+ });
21
+ var dimension = /*#__PURE__*/Object.freeze({
22
+ __proto__: null,
23
+ get data () { return data$3; },
24
+ get updates () { return updates; },
25
+ get start () { return start$a; },
26
+ get stop () { return stop$9; },
27
+ get log () { return log; },
28
+ get compute () { return compute$2; },
29
+ get reset () { return reset$3; }
30
+ });
31
+ var metadata$1 = /*#__PURE__*/Object.freeze({
32
+ __proto__: null,
33
+ get data () { return data$2; },
34
+ get callback () { return callback; },
35
+ get start () { return start$9; },
36
+ get userAgentData () { return userAgentData; },
37
+ get stop () { return stop$8; },
38
+ get metadata () { return metadata; },
39
+ get id () { return id; },
40
+ get consent () { return consent; },
41
+ get clear () { return clear; },
42
+ get save () { return save; }
43
+ });
44
+ var envelope$1 = /*#__PURE__*/Object.freeze({
45
+ __proto__: null,
46
+ get data () { return data$1; },
47
+ get start () { return start$8; },
48
+ get stop () { return stop$7; },
49
+ get envelope () { return envelope; }
11
50
  });
12
51
 
13
52
  var config$1 = {
@@ -41,6 +80,28 @@ function stop$B() {
41
80
  startTime = 0;
42
81
  }
43
82
 
83
+ var version$1 = "0.6.31";
84
+
85
+ // tslint:disable: no-bitwise
86
+ function hash (input) {
87
+ // Code inspired from C# GetHashCode: https://github.com/Microsoft/referencesource/blob/master/mscorlib/system/string.cs
88
+ var hash = 0;
89
+ var hashOne = 5381;
90
+ var hashTwo = hashOne;
91
+ for (var i = 0; i < input.length; i += 2) {
92
+ var charOne = input.charCodeAt(i);
93
+ hashOne = ((hashOne << 5) + hashOne) ^ charOne;
94
+ if (i + 1 < input.length) {
95
+ var charTwo = input.charCodeAt(i + 1);
96
+ hashTwo = ((hashTwo << 5) + hashTwo) ^ charTwo;
97
+ }
98
+ }
99
+ // Replace the magic number from C# implementation (1566083941) with a smaller prime number (11579)
100
+ // This ensures we don't hit integer overflow and prevent collisions
101
+ hash = Math.abs(hashOne + (hashTwo * 11579));
102
+ return hash.toString(36);
103
+ }
104
+
44
105
  var state$9 = null;
45
106
  var buffer = null;
46
107
  var update$1 = false;
@@ -145,29 +206,187 @@ function event(key, value) {
145
206
  }
146
207
  }
147
208
 
148
- // tslint:disable: no-bitwise
149
- function hash (input) {
150
- // Code inspired from C# GetHashCode: https://github.com/Microsoft/referencesource/blob/master/mscorlib/system/string.cs
151
- var hash = 0;
152
- var hashOne = 5381;
153
- var hashTwo = hashOne;
154
- for (var i = 0; i < input.length; i += 2) {
155
- var charOne = input.charCodeAt(i);
156
- hashOne = ((hashOne << 5) + hashOne) ^ charOne;
157
- if (i + 1 < input.length) {
158
- var charTwo = input.charCodeAt(i + 1);
159
- hashTwo = ((hashTwo << 5) + hashTwo) ^ charTwo;
209
+ var data$h = null;
210
+ var updates$3 = null;
211
+ function start$C() {
212
+ data$h = {};
213
+ updates$3 = {};
214
+ count$1(5 /* InvokeCount */);
215
+ }
216
+ function stop$z() {
217
+ data$h = {};
218
+ updates$3 = {};
219
+ }
220
+ function count$1(metric, increment) {
221
+ if (increment === void 0) { increment = 1; }
222
+ if (!(metric in data$h)) {
223
+ data$h[metric] = 0;
224
+ }
225
+ if (!(metric in updates$3)) {
226
+ updates$3[metric] = 0;
227
+ }
228
+ data$h[metric] += increment;
229
+ updates$3[metric] += increment;
230
+ }
231
+ function sum(metric, value) {
232
+ if (value !== null) {
233
+ if (!(metric in data$h)) {
234
+ data$h[metric] = 0;
235
+ }
236
+ if (!(metric in updates$3)) {
237
+ updates$3[metric] = 0;
160
238
  }
239
+ data$h[metric] += value;
240
+ updates$3[metric] += value;
161
241
  }
162
- // Replace the magic number from C# implementation (1566083941) with a smaller prime number (11579)
163
- // This ensures we don't hit integer overflow and prevent collisions
164
- hash = Math.abs(hashOne + (hashTwo * 11579));
165
- return hash.toString(36);
242
+ }
243
+ function max(metric, value) {
244
+ // Ensure that we do not process null or NaN values
245
+ if (value !== null && isNaN(value) === false) {
246
+ if (!(metric in data$h)) {
247
+ data$h[metric] = 0;
248
+ }
249
+ if (value > data$h[metric] || data$h[metric] === 0) {
250
+ updates$3[metric] = value;
251
+ data$h[metric] = value;
252
+ }
253
+ }
254
+ }
255
+ function compute$b() {
256
+ encode$1(0 /* Metric */);
257
+ }
258
+ function reset$n() {
259
+ updates$3 = {};
166
260
  }
167
261
 
168
- var data$h = null;
169
- function start$C() {
170
- reset$n();
262
+ function setTimeout(handler, timeout, event) {
263
+ return window.setTimeout(measure(handler), timeout, event);
264
+ }
265
+ function clearTimeout(handle) {
266
+ return window.clearTimeout(handle);
267
+ }
268
+
269
+ var data$g;
270
+ var last = 0;
271
+ var interval = 0;
272
+ var timeout$6 = null;
273
+ function start$B() {
274
+ interval = 60000 /* PingInterval */;
275
+ last = 0;
276
+ }
277
+ function reset$m() {
278
+ if (timeout$6) {
279
+ clearTimeout(timeout$6);
280
+ }
281
+ timeout$6 = setTimeout(ping, interval);
282
+ last = time();
283
+ }
284
+ function ping() {
285
+ var now = time();
286
+ data$g = { gap: now - last };
287
+ encode$1(25 /* Ping */);
288
+ if (data$g.gap < 300000 /* PingTimeout */) {
289
+ timeout$6 = setTimeout(ping, interval);
290
+ }
291
+ else {
292
+ suspend();
293
+ }
294
+ }
295
+ function stop$y() {
296
+ clearTimeout(timeout$6);
297
+ last = 0;
298
+ interval = 0;
299
+ }
300
+
301
+ var ping$1 = /*#__PURE__*/Object.freeze({
302
+ __proto__: null,
303
+ get data () { return data$g; },
304
+ start: start$B,
305
+ reset: reset$m,
306
+ stop: stop$y
307
+ });
308
+
309
+ var data$f = null;
310
+ function start$A() {
311
+ data$f = {};
312
+ }
313
+ function stop$x() {
314
+ data$f = {};
315
+ }
316
+ function track$6(event, time) {
317
+ if (!(event in data$f)) {
318
+ data$f[event] = [[time, 0]];
319
+ }
320
+ else {
321
+ var e = data$f[event];
322
+ var last = e[e.length - 1];
323
+ // Add a new entry only if the new event occurs after configured interval
324
+ // Otherwise, extend the duration of the previous entry
325
+ if (time - last[0] > 100 /* SummaryInterval */) {
326
+ data$f[event].push([time, 0]);
327
+ }
328
+ else {
329
+ last[1] = time - last[0];
330
+ }
331
+ }
332
+ }
333
+ function compute$a() {
334
+ encode$1(36 /* Summary */);
335
+ }
336
+ function reset$l() {
337
+ data$f = {};
338
+ }
339
+
340
+ var summary = /*#__PURE__*/Object.freeze({
341
+ __proto__: null,
342
+ get data () { return data$f; },
343
+ start: start$A,
344
+ stop: stop$x,
345
+ track: track$6,
346
+ compute: compute$a,
347
+ reset: reset$l
348
+ });
349
+
350
+ var data$e = null;
351
+ function start$z() {
352
+ if (!config$1.lean && config$1.upgrade) {
353
+ config$1.upgrade("Config" /* Config */);
354
+ }
355
+ data$e = null;
356
+ }
357
+ // Following call will upgrade the session from lean mode into the full mode retroactively from the start of the page.
358
+ // As part of the lean mode, we do not send back any layout information - including discovery of DOM and mutations.
359
+ // However, if there's a need for full fidelity playback, calling this function will disable lean mode
360
+ // and send all backed up layout events to the server.
361
+ function upgrade(key) {
362
+ // Upgrade only if Clarity was successfully activated on the page
363
+ if (active() && config$1.lean) {
364
+ config$1.lean = false;
365
+ data$e = { key: key };
366
+ // Update metadata to track we have upgraded this session
367
+ save();
368
+ // Callback upgrade handler, if configured
369
+ if (config$1.upgrade) {
370
+ config$1.upgrade(key);
371
+ }
372
+ encode$1(3 /* Upgrade */);
373
+ }
374
+ }
375
+ function stop$w() {
376
+ data$e = null;
377
+ }
378
+
379
+ var upgrade$1 = /*#__PURE__*/Object.freeze({
380
+ __proto__: null,
381
+ get data () { return data$e; },
382
+ start: start$z,
383
+ upgrade: upgrade,
384
+ stop: stop$w
385
+ });
386
+
387
+ var data$d = null;
388
+ function start$y() {
389
+ reset$k();
171
390
  }
172
391
  function set(variable, value) {
173
392
  var values = typeof value === "string" /* String */ ? [value] : value;
@@ -186,1505 +405,978 @@ function log$2(variable, value) {
186
405
  value &&
187
406
  typeof variable === "string" /* String */ &&
188
407
  variable.length < 255) {
189
- var validValues = variable in data$h ? data$h[variable] : [];
408
+ var validValues = variable in data$d ? data$d[variable] : [];
190
409
  for (var i = 0; i < value.length; i++) {
191
410
  if (typeof value[i] === "string" /* String */ && value[i].length < 255) {
192
411
  validValues.push(value[i]);
193
412
  }
194
413
  }
195
- data$h[variable] = validValues;
414
+ data$d[variable] = validValues;
196
415
  }
197
416
  }
198
- function compute$b() {
417
+ function compute$9() {
199
418
  encode$1(34 /* Variable */);
200
419
  }
201
- function reset$n() {
202
- data$h = {};
420
+ function reset$k() {
421
+ data$d = {};
203
422
  }
204
- function stop$z() {
205
- reset$n();
423
+ function stop$v() {
424
+ reset$k();
206
425
  }
207
426
 
208
427
  var variable = /*#__PURE__*/Object.freeze({
209
428
  __proto__: null,
210
- get data () { return data$h; },
211
- start: start$C,
429
+ get data () { return data$d; },
430
+ start: start$y,
212
431
  set: set,
213
432
  identify: identify,
214
- compute: compute$b,
215
- reset: reset$n,
216
- stop: stop$z
433
+ compute: compute$9,
434
+ reset: reset$k,
435
+ stop: stop$v
217
436
  });
218
437
 
219
- var data$g = null;
220
- var callback = null;
221
- var rootDomain = null;
222
- function start$B() {
223
- callback = null;
224
- rootDomain = null;
225
- var ua = navigator && "userAgent" in navigator ? navigator.userAgent : "" /* Empty */;
226
- var title = document && document.title ? document.title : "" /* Empty */;
227
- // Populate ids for this page
228
- var s = session();
229
- var u = user();
230
- data$g = {
231
- projectId: config$1.projectId || hash(location.host),
232
- userId: u.id,
233
- sessionId: s.session,
234
- pageNum: s.count
235
- };
236
- // Override configuration based on what's in the session storage, unless it is blank (e.g. using upload callback, like in devtools)
237
- config$1.lean = config$1.track && s.upgrade !== null ? s.upgrade === 0 /* False */ : config$1.lean;
238
- config$1.upload = config$1.track && typeof config$1.upload === "string" /* String */ && s.upload && s.upload.length > "https://" /* HTTPS */.length ? s.upload : config$1.upload;
239
- // Log dimensions
240
- log$1(0 /* UserAgent */, ua);
241
- log$1(3 /* PageTitle */, title);
242
- log$1(1 /* Url */, location.href);
243
- log$1(2 /* Referrer */, document.referrer);
244
- log$1(15 /* TabId */, tab());
245
- log$1(16 /* PageLanguage */, document.documentElement.lang);
246
- log$1(17 /* DocumentDirection */, document.dir);
247
- if (navigator) {
248
- log$1(9 /* Language */, navigator.userLanguage || navigator.language);
249
- max(26 /* Automation */, navigator.webdriver ? 1 /* True */ : 0 /* False */);
250
- }
251
- // Metrics
252
- max(0 /* ClientTimestamp */, s.ts);
253
- max(1 /* Playback */, 0 /* False */);
254
- if (screen) {
255
- max(14 /* ScreenWidth */, Math.round(screen.width));
256
- max(15 /* ScreenHeight */, Math.round(screen.height));
257
- max(16 /* ColorDepth */, Math.round(screen.colorDepth));
258
- }
259
- // Read cookies specified in configuration
260
- for (var _i = 0, _a = config$1.cookies; _i < _a.length; _i++) {
261
- var key = _a[_i];
262
- var value = getCookie(key);
263
- if (value) {
264
- set(key, value);
265
- }
266
- }
267
- // Track ids using a cookie if configuration allows it
268
- track$6(u);
269
- }
270
- function stop$y() {
271
- callback = null;
272
- rootDomain = null;
273
- }
274
- function metadata$1(cb) {
275
- callback = cb;
276
- }
277
- function id() {
278
- return data$g ? [data$g.userId, data$g.sessionId, data$g.pageNum].join("." /* Dot */) : "" /* Empty */;
279
- }
280
- function consent() {
281
- if (active()) {
282
- config$1.track = true;
283
- track$6(user(), 1 /* True */);
438
+ /*! *****************************************************************************
439
+ Copyright (c) Microsoft Corporation.
440
+
441
+ Permission to use, copy, modify, and/or distribute this software for any
442
+ purpose with or without fee is hereby granted.
443
+
444
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
445
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
446
+ AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
447
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
448
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
449
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
450
+ PERFORMANCE OF THIS SOFTWARE.
451
+ ***************************************************************************** */
452
+
453
+ function __awaiter(thisArg, _arguments, P, generator) {
454
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
455
+ return new (P || (P = Promise))(function (resolve, reject) {
456
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
457
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
458
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
459
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
460
+ });
461
+ }
462
+
463
+ function __generator(thisArg, body) {
464
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
465
+ return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
466
+ function verb(n) { return function (v) { return step([n, v]); }; }
467
+ function step(op) {
468
+ if (f) throw new TypeError("Generator is already executing.");
469
+ while (_) try {
470
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
471
+ if (y = 0, t) op = [op[0] & 2, t.value];
472
+ switch (op[0]) {
473
+ case 0: case 1: t = op; break;
474
+ case 4: _.label++; return { value: op[1], done: false };
475
+ case 5: _.label++; y = op[1]; op = [0]; continue;
476
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
477
+ default:
478
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
479
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
480
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
481
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
482
+ if (t[2]) _.ops.pop();
483
+ _.trys.pop(); continue;
484
+ }
485
+ op = body.call(thisArg, _);
486
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
487
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
284
488
  }
489
+ }
490
+
491
+ var supported$1 = "CompressionStream" /* CompressionStream */ in window;
492
+ function compress (input) {
493
+ return __awaiter(this, void 0, void 0, function () {
494
+ var stream, _a;
495
+ return __generator(this, function (_c) {
496
+ switch (_c.label) {
497
+ case 0:
498
+ _c.trys.push([0, 3, , 4]);
499
+ if (!supported$1) return [3 /*break*/, 2];
500
+ stream = new ReadableStream({ start: function (controller) {
501
+ return __awaiter(this, void 0, void 0, function () {
502
+ return __generator(this, function (_a) {
503
+ controller.enqueue(input);
504
+ controller.close();
505
+ return [2 /*return*/];
506
+ });
507
+ });
508
+ } }).pipeThrough(new TextEncoderStream()).pipeThrough(new window["CompressionStream" /* CompressionStream */]("gzip"));
509
+ _a = Uint8Array.bind;
510
+ return [4 /*yield*/, read(stream)];
511
+ case 1: return [2 /*return*/, new (_a.apply(Uint8Array, [void 0, _c.sent()]))()];
512
+ case 2: return [3 /*break*/, 4];
513
+ case 3:
514
+ _c.sent();
515
+ return [3 /*break*/, 4];
516
+ case 4: return [2 /*return*/, null];
517
+ }
518
+ });
519
+ });
285
520
  }
286
- function clear() {
287
- // Clear any stored information in the cookie that tracks session information so we can restart fresh the next time
288
- setCookie("_clsk" /* SessionKey */, "" /* Empty */, 0);
521
+ function read(stream) {
522
+ return __awaiter(this, void 0, void 0, function () {
523
+ var reader, chunks, done, value;
524
+ var _a;
525
+ return __generator(this, function (_b) {
526
+ switch (_b.label) {
527
+ case 0:
528
+ reader = stream.getReader();
529
+ chunks = [];
530
+ done = false;
531
+ value = [];
532
+ _b.label = 1;
533
+ case 1:
534
+ if (!!done) return [3 /*break*/, 3];
535
+ return [4 /*yield*/, reader.read()];
536
+ case 2:
537
+ (_a = _b.sent(), done = _a.done, value = _a.value);
538
+ if (done) {
539
+ return [2 /*return*/, chunks];
540
+ }
541
+ chunks.push.apply(chunks, value);
542
+ return [3 /*break*/, 1];
543
+ case 3: return [2 /*return*/, chunks];
544
+ }
545
+ });
546
+ });
547
+ }
548
+
549
+ var modules$1 = [baseline, dimension, variable, limit, summary, metadata$1, envelope$1, upload$1, ping$1, upgrade$1];
550
+ function start$x() {
551
+ // Metric needs to be initialized before we can start measuring. so metric is not wrapped in measure
552
+ start$C();
553
+ modules$1.forEach(function (x) { return measure(x.start)(); });
289
554
  }
290
- function tab() {
291
- var id = shortid();
292
- if (config$1.track && supported$1(window, "sessionStorage" /* SessionStorage */)) {
293
- var value = sessionStorage.getItem("_cltk" /* TabKey */);
294
- id = value ? value : id;
295
- sessionStorage.setItem("_cltk" /* TabKey */, id);
296
- }
297
- return id;
555
+ function stop$u() {
556
+ // Stop modules in the reverse order of their initialization
557
+ // The ordering below should respect inter-module dependency.
558
+ // E.g. if upgrade depends on upload, then upgrade needs to end before upload.
559
+ // Similarly, if upload depends on metadata, upload needs to end before metadata.
560
+ modules$1.slice().reverse().forEach(function (x) { return measure(x.stop)(); });
561
+ stop$z();
298
562
  }
299
- function save() {
300
- var ts = Math.round(Date.now());
301
- var upgrade = config$1.lean ? 0 /* False */ : 1 /* True */;
302
- var upload = config$1.upload && typeof config$1.upload === "string" /* String */ ? config$1.upload.replace("https://" /* HTTPS */, "" /* Empty */) : "" /* Empty */;
303
- if (upgrade && callback) {
304
- callback(data$g, !config$1.lean);
563
+ function compute$8() {
564
+ compute$9();
565
+ compute$c();
566
+ compute$2();
567
+ compute$b();
568
+ compute$a();
569
+ compute$3();
570
+ }
571
+
572
+ function scrub (value, hint, privacy, mangle) {
573
+ if (mangle === void 0) { mangle = false; }
574
+ if (value) {
575
+ switch (privacy) {
576
+ case 0 /* None */:
577
+ return value;
578
+ case 1 /* Sensitive */:
579
+ switch (hint) {
580
+ case "*T" /* TextTag */:
581
+ case "value":
582
+ case "placeholder":
583
+ return redact(value);
584
+ case "input":
585
+ return mangleToken(value);
586
+ }
587
+ return value;
588
+ case 2 /* Text */:
589
+ case 3 /* TextImage */:
590
+ switch (hint) {
591
+ case "*T" /* TextTag */:
592
+ return mangle ? mangleText(value) : mask(value);
593
+ case "src":
594
+ case "srcset":
595
+ case "title":
596
+ case "alt":
597
+ return privacy === 3 /* TextImage */ ? "" /* Empty */ : value;
598
+ case "value":
599
+ case "click":
600
+ case "input":
601
+ return mangleToken(value);
602
+ case "placeholder":
603
+ return mask(value);
604
+ }
605
+ break;
606
+ }
305
607
  }
306
- setCookie("_clsk" /* SessionKey */, [data$g.sessionId, ts, data$g.pageNum, upgrade, upload].join("|" /* Pipe */), 1 /* SessionExpire */);
608
+ return value;
307
609
  }
308
- function supported$1(target, api) {
309
- try {
310
- return !!target[api];
311
- }
312
- catch (_a) {
313
- return false;
610
+ function mangleText(value) {
611
+ var trimmed = value.trim();
612
+ if (trimmed.length > 0) {
613
+ var first = trimmed[0];
614
+ var index = value.indexOf(first);
615
+ var prefix = value.substr(0, index);
616
+ var suffix = value.substr(index + trimmed.length);
617
+ return "" + prefix + trimmed.length.toString(36) + suffix;
314
618
  }
619
+ return value;
315
620
  }
316
- function track$6(u, consent) {
317
- if (consent === void 0) { consent = null; }
318
- // If consent is not explicitly specified, infer it from the user object
319
- consent = consent === null ? u.consent : consent;
320
- // Convert time precision into days to reduce number of bytes we have to write in a cookie
321
- // E.g. Math.ceil(1628735962643 / (24*60*60*1000)) => 18852 (days) => ejo in base36 (13 bytes => 3 bytes)
322
- var end = Math.ceil((Date.now() + (365 /* Expire */ * 86400000 /* Day */)) / 86400000 /* Day */);
323
- // To avoid cookie churn, write user id cookie only once every day
324
- if (u.expiry === null || Math.abs(end - u.expiry) >= 1 /* CookieInterval */ || u.consent !== consent) {
325
- setCookie("_clck" /* CookieKey */, [data$g.userId, 1 /* CookieVersion */, end.toString(36), consent].join("|" /* Pipe */), 365 /* Expire */);
326
- }
621
+ function mask(value) {
622
+ return value.replace(/\S/gi, "\u2022" /* Mask */);
327
623
  }
328
- function shortid() {
329
- var id = Math.floor(Math.random() * Math.pow(2, 32));
330
- if (window && window.crypto && window.crypto.getRandomValues && Uint32Array) {
331
- id = window.crypto.getRandomValues(new Uint32Array(1))[0];
624
+ function mangleToken(value) {
625
+ var length = ((Math.floor(value.length / 5 /* WordLength */) + 1) * 5 /* WordLength */);
626
+ var output = "" /* Empty */;
627
+ for (var i = 0; i < length; i++) {
628
+ output += i > 0 && i % 5 /* WordLength */ === 0 ? " " /* Space */ : "\u2022" /* Mask */;
332
629
  }
333
- return id.toString(36);
630
+ return output;
334
631
  }
335
- function session() {
336
- var output = { session: shortid(), ts: Math.round(Date.now()), count: 1, upgrade: null, upload: "" /* Empty */ };
337
- var value = getCookie("_clsk" /* SessionKey */);
338
- if (value) {
339
- var parts = value.split("|" /* Pipe */);
340
- // Making it backward & forward compatible by using greater than comparison (v0.6.21)
341
- // In future version, we can reduce the parts length to be 5 where the last part contains the full upload URL
342
- if (parts.length >= 5 && output.ts - num$2(parts[1]) < 1800000 /* SessionTimeout */) {
343
- output.session = parts[0];
344
- output.count = num$2(parts[2]) + 1;
345
- output.upgrade = num$2(parts[3]);
346
- output.upload = parts.length >= 6 ? "" + "https://" /* HTTPS */ + parts[5] + "/" + parts[4] : "" + "https://" /* HTTPS */ + parts[4];
632
+ function redact(value) {
633
+ var spaceIndex = -1;
634
+ var hasDigit = false;
635
+ var hasEmail = false;
636
+ var hasWhitespace = false;
637
+ var array = null;
638
+ for (var i = 0; i < value.length; i++) {
639
+ var c = value.charCodeAt(i);
640
+ hasDigit = hasDigit || (c >= 48 /* Zero */ && c <= 57 /* Nine */); // Check for digits in the current word
641
+ hasEmail = hasEmail || c === 64 /* At */; // Check for @ sign anywhere within the current word
642
+ hasWhitespace = c === 9 /* Tab */ || c === 10 /* NewLine */ || c === 13 /* Return */ || c === 32 /* Blank */;
643
+ // Process each word as an individual token to redact any sensitive information
644
+ if (i === 0 || i === value.length - 1 || hasWhitespace) {
645
+ // Performance optimization: Lazy load string -> array conversion only when required
646
+ if (hasDigit || hasEmail) {
647
+ if (array === null) {
648
+ array = value.split("" /* Empty */);
649
+ }
650
+ mutate(array, spaceIndex, hasWhitespace ? i : i + 1);
651
+ }
652
+ // Reset digit and email flags after every word boundary, except the beginning of string
653
+ if (hasWhitespace) {
654
+ hasDigit = false;
655
+ hasEmail = false;
656
+ spaceIndex = i;
657
+ }
347
658
  }
348
659
  }
349
- return output;
350
- }
351
- function num$2(string, base) {
352
- if (base === void 0) { base = 10; }
353
- return parseInt(string, base);
660
+ return array ? array.join("" /* Empty */) : value;
354
661
  }
355
- function user() {
356
- var output = { id: shortid(), expiry: null, consent: 0 /* False */ };
357
- var cookie = getCookie("_clck" /* CookieKey */);
358
- if (cookie && cookie.length > 0) {
359
- // Splitting and looking up first part for forward compatibility, in case we wish to store additional information in a cookie
360
- var parts = cookie.split("|" /* Pipe */);
361
- // For backward compatibility introduced in v0.6.18; following code can be removed with future iterations
362
- // Count number of times Clarity's user cookie crumb appears in document.cookie (could be on different sub-domains e.g. www.domain.com and .domain.com)
363
- var count = 0;
364
- for (var _i = 0, _a = document.cookie.split(";" /* Semicolon */); _i < _a.length; _i++) {
365
- var c = _a[_i];
366
- count += c.split("=" /* Equals */)[0].trim() === "_clck" /* CookieKey */ ? 1 : 0;
367
- }
368
- // Check if we either got version-less cookie value or saw multiple copies of the user cookie crumbs
369
- // In both these cases, we go ahead and delete the existing cookie set on current domain
370
- if (parts.length === 1 || count > 1) {
371
- var deleted = "" + ";" /* Semicolon */ + "expires=" /* Expires */ + (new Date(0)).toUTCString() + ";path=/" /* Path */;
372
- // First, delete current user cookie which might be set on current sub-domain vs. root domain
373
- document.cookie = "_clck" /* CookieKey */ + "=" + deleted;
374
- // Second, same thing for current session cookie so it can be re-written later with the root domain
375
- document.cookie = "_clsk" /* SessionKey */ + "=" + deleted;
376
- }
377
- // End code for backward compatibility
378
- // Read version information and timestamp from cookie, if available
379
- if (parts.length > 2) {
380
- output.expiry = num$2(parts[2], 36);
381
- }
382
- // Check if we have explicit consent to track this user
383
- if (parts.length > 3 && num$2(parts[3]) === 1) {
384
- output.consent = 1 /* True */;
385
- }
386
- // Set track configuration to true for this user if we have explicit consent, regardless of project setting
387
- config$1.track = config$1.track || output.consent === 1 /* True */;
388
- // Get user id from cookie only if we tracking is enabled, otherwise fallback to a random id
389
- output.id = config$1.track ? parts[0] : output.id;
662
+ function mutate(array, start, end) {
663
+ for (var i = start + 1; i < end; i++) {
664
+ array[i] = "\u2022" /* Mask */;
665
+ }
666
+ }
667
+
668
+ // Track the start time to be able to compute duration at the end of the task
669
+ var idleTimeout = 5000;
670
+ var tracker = {};
671
+ var queuedTasks = [];
672
+ var activeTask = null;
673
+ var pauseTask = null;
674
+ var resumeResolve = null;
675
+ function pause$1() {
676
+ if (pauseTask === null) {
677
+ pauseTask = new Promise(function (resolve) {
678
+ resumeResolve = resolve;
679
+ });
390
680
  }
391
- return output;
392
681
  }
393
- function getCookie(key) {
394
- if (supported$1(document, "cookie" /* Cookie */)) {
395
- var cookies = document.cookie.split(";" /* Semicolon */);
396
- if (cookies) {
397
- for (var i = 0; i < cookies.length; i++) {
398
- var pair = cookies[i].split("=" /* Equals */);
399
- if (pair.length > 1 && pair[0] && pair[0].trim() === key) {
400
- return pair[1];
401
- }
402
- }
682
+ function resume$1() {
683
+ if (pauseTask) {
684
+ resumeResolve();
685
+ pauseTask = null;
686
+ if (activeTask === null) {
687
+ run();
403
688
  }
404
689
  }
405
- return null;
406
690
  }
407
- function setCookie(key, value, time) {
408
- if (config$1.track && ((navigator && navigator.cookieEnabled) || supported$1(document, "cookie" /* Cookie */))) {
409
- var expiry = new Date();
410
- expiry.setDate(expiry.getDate() + time);
411
- var expires = expiry ? "expires=" /* Expires */ + expiry.toUTCString() : "" /* Empty */;
412
- var cookie = key + "=" + value + ";" /* Semicolon */ + expires + ";path=/" /* Path */;
413
- try {
414
- // Attempt to get the root domain only once and fall back to writing cookie on the current domain.
415
- if (rootDomain === null) {
416
- var hostname = location.hostname ? location.hostname.split("." /* Dot */) : [];
417
- // Walk backwards on a domain and attempt to set a cookie, until successful
418
- for (var i = hostname.length - 1; i >= 0; i--) {
419
- rootDomain = "." + hostname[i] + (rootDomain ? rootDomain : "" /* Empty */);
420
- // We do not wish to attempt writing a cookie on the absolute last part of the domain, e.g. .com or .net.
421
- // So we start attempting after second-last part, e.g. .domain.com (PASS) or .co.uk (FAIL)
422
- if (i < hostname.length - 1) {
423
- // Write the cookie on the current computed top level domain
424
- document.cookie = "" + cookie + ";" /* Semicolon */ + "domain=" /* Domain */ + rootDomain;
425
- // Once written, check if the cookie exists and its value matches exactly with what we intended to set
426
- // Checking for exact value match helps us eliminate a corner case where the cookie may already be present with a different value
427
- // If the check is successful, no more action is required and we can return from the function since rootDomain cookie is already set
428
- // If the check fails, continue with the for loop until we can successfully set and verify the cookie
429
- if (getCookie(key) === value) {
430
- return;
431
- }
432
- }
691
+ function reset$j() {
692
+ tracker = {};
693
+ queuedTasks = [];
694
+ activeTask = null;
695
+ pauseTask = null;
696
+ }
697
+ function schedule$1(task, priority) {
698
+ if (priority === void 0) { priority = 0 /* Normal */; }
699
+ return __awaiter(this, void 0, void 0, function () {
700
+ var _i, queuedTasks_1, q, promise;
701
+ return __generator(this, function (_a) {
702
+ // If this task is already scheduled, skip it
703
+ for (_i = 0, queuedTasks_1 = queuedTasks; _i < queuedTasks_1.length; _i++) {
704
+ q = queuedTasks_1[_i];
705
+ if (q.task === task) {
706
+ return [2 /*return*/];
433
707
  }
434
- // Finally, if we were not successful and gone through all the options, play it safe and reset rootDomain to be empty
435
- // This forces our code to fall back to always writing cookie to the current domain
436
- rootDomain = "" /* Empty */;
437
708
  }
438
- }
439
- catch (_a) {
440
- rootDomain = "" /* Empty */;
441
- }
442
- document.cookie = rootDomain ? "" + cookie + ";" /* Semicolon */ + "domain=" /* Domain */ + rootDomain : cookie;
443
- }
444
- }
445
-
446
- var metadata$2 = /*#__PURE__*/Object.freeze({
447
- __proto__: null,
448
- get data () { return data$g; },
449
- get callback () { return callback; },
450
- start: start$B,
451
- stop: stop$y,
452
- metadata: metadata$1,
453
- id: id,
454
- consent: consent,
455
- clear: clear,
456
- save: save
457
- });
458
-
459
- var history$4;
460
- function reset$m() {
461
- history$4 = [];
709
+ promise = new Promise(function (resolve) {
710
+ var insert = priority === 1 /* High */ ? "unshift" : "push";
711
+ // Queue this task for asynchronous execution later
712
+ // We also store a unique page identifier (id) along with the task to ensure
713
+ // ensure that we do not accidentally execute this task in context of a different page
714
+ queuedTasks[insert]({ task: task, resolve: resolve, id: id() });
715
+ });
716
+ // If there is no active task running, and Clarity is not in pause state,
717
+ // invoke the first task in the queue synchronously. This ensures that we don't yield the thread during unload event
718
+ if (activeTask === null && pauseTask === null) {
719
+ run();
720
+ }
721
+ return [2 /*return*/, promise];
722
+ });
723
+ });
462
724
  }
463
- function report(check, message) {
464
- if (message === void 0) { message = null; }
465
- // Do not report the same message twice for the same page
466
- if (history$4 && history$4.indexOf(message) === -1) {
467
- var url = config$1.report;
468
- if (url && url.length > 0) {
469
- var payload = { c: check, p: data$g.projectId, u: data$g.userId, s: data$g.sessionId, n: data$g.pageNum };
470
- if (message)
471
- payload.m = message;
472
- // Using POST request instead of a GET request (img-src) to not violate existing CSP rules
473
- // Since, Clarity already uses XHR to upload data, we stick with similar POST mechanism for reporting too
474
- var xhr = new XMLHttpRequest();
475
- xhr.open("POST", url);
476
- xhr.send(JSON.stringify(payload));
477
- history$4.push(message);
478
- }
725
+ function run() {
726
+ var entry = queuedTasks.shift();
727
+ if (entry) {
728
+ activeTask = entry;
729
+ entry.task().then(function () {
730
+ // Bail out if the context in which this task was operating is different from the current page
731
+ // An example scenario where task could span across pages is Single Page Applications (SPA)
732
+ // A task that started on page #1, but completes on page #2
733
+ if (entry.id !== id()) {
734
+ return;
735
+ }
736
+ entry.resolve();
737
+ activeTask = null; // Reset active task back to null now that the promise is resolved
738
+ run();
739
+ }).catch(function (error) {
740
+ // If one of the scheduled tasks failed, log, recover and continue processing rest of the tasks
741
+ if (entry.id !== id()) {
742
+ return;
743
+ }
744
+ if (error) {
745
+ log$1(0 /* RunTask */, 1 /* Warning */, error.name, error.message, error.stack);
746
+ }
747
+ activeTask = null;
748
+ run();
749
+ });
479
750
  }
480
- }
481
-
482
- var version$1 = "0.6.27";
483
-
484
- var data$f = null;
485
- function start$A() {
486
- var m = data$g;
487
- data$f = {
488
- version: version$1,
489
- sequence: 0,
490
- start: 0,
491
- duration: 0,
492
- projectId: m.projectId,
493
- userId: m.userId,
494
- sessionId: m.sessionId,
495
- pageNum: m.pageNum,
496
- upload: 0 /* Async */,
497
- end: 0 /* False */
498
- };
499
- }
500
- function stop$x() {
501
- data$f = null;
502
751
  }
503
- function envelope(last) {
504
- data$f.start = data$f.start + data$f.duration;
505
- data$f.duration = time() - data$f.start;
506
- data$f.sequence++;
507
- data$f.upload = last && "sendBeacon" in navigator ? 1 /* Beacon */ : 0 /* Async */;
508
- data$f.end = last ? 1 /* True */ : 0 /* False */;
509
- return [
510
- data$f.version,
511
- data$f.sequence,
512
- data$f.start,
513
- data$f.duration,
514
- data$f.projectId,
515
- data$f.userId,
516
- data$f.sessionId,
517
- data$f.pageNum,
518
- data$f.upload,
519
- data$f.end
520
- ];
521
- }
522
-
523
- var envelope$1 = /*#__PURE__*/Object.freeze({
524
- __proto__: null,
525
- get data () { return data$f; },
526
- start: start$A,
527
- stop: stop$x,
528
- envelope: envelope
529
- });
530
-
531
- var data$e;
532
- function start$z() {
533
- data$e = { check: 0 /* None */ };
534
- }
535
- function check$3(bytes) {
536
- if (data$e.check === 0 /* None */) {
537
- var reason = data$e.check;
538
- reason = data$f.sequence >= 128 /* PayloadLimit */ ? 1 /* Payload */ : reason;
539
- reason = time() > 7200000 /* ShutdownLimit */ ? 2 /* Shutdown */ : reason;
540
- reason = bytes > 10485760 /* PlaybackBytesLimit */ ? 2 /* Shutdown */ : reason;
541
- if (reason !== data$e.check) {
542
- trigger$1(reason);
543
- }
752
+ function state$8(timer) {
753
+ var id = key(timer);
754
+ if (id in tracker) {
755
+ var elapsed = performance.now() - tracker[id].start;
756
+ return (elapsed > tracker[id].yield) ? 0 /* Wait */ : 1 /* Run */;
544
757
  }
758
+ // If this task is no longer being tracked, send stop message to the caller
759
+ return 2 /* Stop */;
545
760
  }
546
- function trigger$1(reason) {
547
- report(reason);
548
- data$e.check = reason;
549
- clear();
550
- stop();
761
+ function start$w(timer) {
762
+ tracker[key(timer)] = { start: performance.now(), calls: 0, yield: 30 /* LongTask */ };
551
763
  }
552
- function compute$a() {
553
- if (data$e.check !== 0 /* None */) {
554
- encode$1(35 /* Limit */);
764
+ function restart$1(timer) {
765
+ var id = key(timer);
766
+ if (tracker && tracker[id]) {
767
+ var c = tracker[id].calls;
768
+ var y = tracker[id].yield;
769
+ start$w(timer);
770
+ tracker[id].calls = c + 1;
771
+ tracker[id].yield = y;
555
772
  }
556
773
  }
557
- function stop$w() {
558
- data$e = null;
559
- }
560
-
561
- var limit = /*#__PURE__*/Object.freeze({
562
- __proto__: null,
563
- get data () { return data$e; },
564
- start: start$z,
565
- check: check$3,
566
- trigger: trigger$1,
567
- compute: compute$a,
568
- stop: stop$w
569
- });
570
-
571
- var data$d = null;
572
- var updates$3 = null;
573
- function start$y() {
574
- data$d = {};
575
- updates$3 = {};
774
+ function stop$t(timer) {
775
+ var end = performance.now();
776
+ var id = key(timer);
777
+ var duration = end - tracker[id].start;
778
+ sum(timer.cost, duration);
779
+ count$1(5 /* InvokeCount */);
780
+ // For the first execution, which is synchronous, time is automatically counted towards TotalDuration.
781
+ // However, for subsequent asynchronous runs, we need to manually update TotalDuration metric.
782
+ if (tracker[id].calls > 0) {
783
+ sum(4 /* TotalCost */, duration);
784
+ }
576
785
  }
577
- function stop$v() {
578
- data$d = {};
579
- updates$3 = {};
580
- }
581
- function log$1(dimension, value) {
582
- // Check valid value before moving ahead
583
- if (value) {
584
- // Ensure received value is casted into a string if it wasn't a string to begin with
585
- value = "" + value;
586
- if (!(dimension in data$d)) {
587
- data$d[dimension] = [];
588
- }
589
- if (data$d[dimension].indexOf(value) < 0) {
590
- data$d[dimension].push(value);
591
- // If this is a new value, track it as part of updates object
592
- // This allows us to only send back new values in subsequent payloads
593
- if (!(dimension in updates$3)) {
594
- updates$3[dimension] = [];
595
- }
596
- updates$3[dimension].push(value);
597
- // Limit check to ensure we have a cap on number of dimensions we can collect
598
- if (data$d[dimension].length > 128 /* CollectionLimit */) {
599
- trigger$1(5 /* Collection */);
786
+ function suspend$1(timer) {
787
+ return __awaiter(this, void 0, void 0, function () {
788
+ var id, _a;
789
+ return __generator(this, function (_b) {
790
+ switch (_b.label) {
791
+ case 0:
792
+ id = key(timer);
793
+ if (!(id in tracker)) return [3 /*break*/, 2];
794
+ stop$t(timer);
795
+ _a = tracker[id];
796
+ return [4 /*yield*/, wait()];
797
+ case 1:
798
+ _a.yield = (_b.sent()).timeRemaining();
799
+ restart$1(timer);
800
+ _b.label = 2;
801
+ case 2:
802
+ // After we are done with suspending task, ensure that we are still operating in the right context
803
+ // If the task is still being tracked, continue running the task, otherwise ask caller to stop execution
804
+ return [2 /*return*/, id in tracker ? 1 /* Run */ : 2 /* Stop */];
600
805
  }
601
- }
602
- }
603
- }
604
- function compute$9() {
605
- encode$1(1 /* Dimension */);
606
- }
607
- function reset$l() {
608
- updates$3 = {};
609
- }
610
-
611
- var dimension = /*#__PURE__*/Object.freeze({
612
- __proto__: null,
613
- get data () { return data$d; },
614
- get updates () { return updates$3; },
615
- start: start$y,
616
- stop: stop$v,
617
- log: log$1,
618
- compute: compute$9,
619
- reset: reset$l
620
- });
621
-
622
- function setTimeout(handler, timeout, event) {
623
- return window.setTimeout(measure(handler), timeout, event);
806
+ });
807
+ });
624
808
  }
625
- function clearTimeout(handle) {
626
- return window.clearTimeout(handle);
627
- }
628
-
629
- var data$c;
630
- var last = 0;
631
- var interval = 0;
632
- var timeout$6 = null;
633
- function start$x() {
634
- interval = 60000 /* PingInterval */;
635
- last = 0;
809
+ function key(timer) {
810
+ return timer.id + "." + timer.cost;
636
811
  }
637
- function reset$k() {
638
- if (timeout$6) {
639
- clearTimeout(timeout$6);
640
- }
641
- timeout$6 = setTimeout(ping, interval);
642
- last = time();
812
+ function wait() {
813
+ return __awaiter(this, void 0, void 0, function () {
814
+ return __generator(this, function (_a) {
815
+ switch (_a.label) {
816
+ case 0:
817
+ if (!pauseTask) return [3 /*break*/, 2];
818
+ return [4 /*yield*/, pauseTask];
819
+ case 1:
820
+ _a.sent();
821
+ _a.label = 2;
822
+ case 2: return [2 /*return*/, new Promise(function (resolve) {
823
+ requestIdleCallback(resolve, { timeout: idleTimeout });
824
+ })];
825
+ }
826
+ });
827
+ });
643
828
  }
644
- function ping() {
645
- var now = time();
646
- data$c = { gap: now - last };
647
- encode$1(25 /* Ping */);
648
- if (data$c.gap < 300000 /* PingTimeout */) {
649
- timeout$6 = setTimeout(ping, interval);
650
- }
651
- else {
652
- suspend();
653
- }
829
+ // Use native implementation of requestIdleCallback if it exists.
830
+ // Otherwise, fall back to a custom implementation using requestAnimationFrame & MessageChannel.
831
+ // While it's not possible to build a perfect polyfill given the nature of this API, the following code attempts to get close.
832
+ // Background context: requestAnimationFrame invokes the js code right before: style, layout and paint computation within the frame.
833
+ // This means, that any code that runs as part of requestAnimationFrame will by default be blocking in nature. Not what we want.
834
+ // For non-blocking behavior, We need to know when browser has finished painiting. This can be accomplished in two different ways (hacks):
835
+ // (1) Use MessageChannel to pass the message, and browser will receive the message right after pain event has occured.
836
+ // (2) Use setTimeout call within requestAnimationFrame. This also works, but there's a risk that browser may throttle setTimeout calls.
837
+ // Given this information, we are currently using (1) from above. More information on (2) as well as some additional context is below:
838
+ // https://developer.mozilla.org/en-US/docs/Mozilla/Firefox/Performance_best_practices_for_Firefox_fe_engineers
839
+ function requestIdleCallbackPolyfill(callback, options) {
840
+ var startTime = performance.now();
841
+ var channel = new MessageChannel();
842
+ var incoming = channel.port1;
843
+ var outgoing = channel.port2;
844
+ incoming.onmessage = function (event) {
845
+ var currentTime = performance.now();
846
+ var elapsed = currentTime - startTime;
847
+ var duration = currentTime - event.data;
848
+ if (duration > 30 /* LongTask */ && elapsed < options.timeout) {
849
+ requestAnimationFrame(function () { outgoing.postMessage(currentTime); });
850
+ }
851
+ else {
852
+ var didTimeout_1 = elapsed > options.timeout;
853
+ callback({
854
+ didTimeout: didTimeout_1,
855
+ timeRemaining: function () { return didTimeout_1 ? 30 /* LongTask */ : Math.max(0, 30 /* LongTask */ - duration); }
856
+ });
857
+ }
858
+ };
859
+ requestAnimationFrame(function () { outgoing.postMessage(performance.now()); });
654
860
  }
655
- function stop$u() {
656
- clearTimeout(timeout$6);
657
- last = 0;
658
- interval = 0;
659
- }
660
-
661
- var ping$1 = /*#__PURE__*/Object.freeze({
662
- __proto__: null,
663
- get data () { return data$c; },
664
- start: start$x,
665
- reset: reset$k,
666
- stop: stop$u
667
- });
861
+ var requestIdleCallback = window["requestIdleCallback"] || requestIdleCallbackPolyfill;
668
862
 
669
- var data$b = null;
670
- function start$w() {
671
- data$b = {};
672
- }
673
- function stop$t() {
674
- data$b = {};
675
- }
676
- function track$5(event, time) {
677
- if (!(event in data$b)) {
678
- data$b[event] = [[time, 0]];
679
- }
680
- else {
681
- var e = data$b[event];
682
- var last = e[e.length - 1];
683
- // Add a new entry only if the new event occurs after configured interval
684
- // Otherwise, extend the duration of the previous entry
685
- if (time - last[0] > 100 /* SummaryInterval */) {
686
- data$b[event].push([time, 0]);
863
+ // Following code takes an array of tokens and transforms it to optimize for repeating tokens and make it efficient to send over the wire
864
+ // The way it works is that it iterate over all tokens and checks if the current token was already seen in the tokens array so far
865
+ // If so, it replaces the token with its reference (index). This helps us save bytes by not repeating the same value twice.
866
+ // E.g. If tokens array is: ["hello", "world", "coding", "language", "world", "language", "example"]
867
+ // Then the resulting tokens array after following code execution would be: ["hello", "world", "coding", "language", [1, 3], "example"]
868
+ // Where [1,3] points to tokens[1] => "world" and tokens[3] => "language"
869
+ function tokenize (tokens) {
870
+ var output = [];
871
+ var lookup = {};
872
+ var pointer = 0;
873
+ var reference = null;
874
+ for (var i = 0; i < tokens.length; i++) {
875
+ // Only optimize for string values
876
+ if (typeof tokens[i] === "string" /* String */) {
877
+ var token = tokens[i];
878
+ var index = lookup[token] || -1;
879
+ if (index >= 0) {
880
+ if (reference) {
881
+ reference.push(index);
882
+ }
883
+ else {
884
+ reference = [index];
885
+ output.push(reference);
886
+ pointer++;
887
+ }
888
+ }
889
+ else {
890
+ reference = null;
891
+ output.push(token);
892
+ lookup[token] = pointer++;
893
+ }
687
894
  }
688
895
  else {
689
- last[1] = time - last[0];
896
+ // If the value is anything other than string, append it as it is to the output array
897
+ // And, also increment the pointer to stay in sync with output array
898
+ reference = null;
899
+ output.push(tokens[i]);
900
+ pointer++;
690
901
  }
691
902
  }
692
- }
693
- function compute$8() {
694
- encode$1(36 /* Summary */);
695
- }
696
- function reset$j() {
697
- data$b = {};
903
+ return output;
698
904
  }
699
905
 
700
- var summary = /*#__PURE__*/Object.freeze({
701
- __proto__: null,
702
- get data () { return data$b; },
703
- start: start$w,
704
- stop: stop$t,
705
- track: track$5,
706
- compute: compute$8,
707
- reset: reset$j
708
- });
709
-
710
- var data$a = null;
906
+ var data$c;
907
+ function reset$i() {
908
+ data$c = null;
909
+ }
711
910
  function start$v() {
712
- if (!config$1.lean && config$1.upgrade) {
713
- config$1.upgrade("Config" /* Config */);
714
- }
715
- data$a = null;
911
+ reset$i();
912
+ compute$7();
716
913
  }
717
- // Following call will upgrade the session from lean mode into the full mode retroactively from the start of the page.
718
- // As part of the lean mode, we do not send back any layout information - including discovery of DOM and mutations.
719
- // However, if there's a need for full fidelity playback, calling this function will disable lean mode
720
- // and send all backed up layout events to the server.
721
- function upgrade(key) {
722
- // Upgrade only if Clarity was successfully activated on the page
723
- if (active() && config$1.lean) {
724
- config$1.lean = false;
725
- data$a = { key: key };
726
- // Update metadata to track we have upgraded this session
727
- save();
728
- // Callback upgrade handler, if configured
729
- if (config$1.upgrade) {
730
- config$1.upgrade(key);
731
- }
732
- encode$1(3 /* Upgrade */);
914
+ function compute$7() {
915
+ var body = document.body;
916
+ var d = document.documentElement;
917
+ var bodyClientWidth = body ? body.clientWidth : null;
918
+ var bodyScrollWidth = body ? body.scrollWidth : null;
919
+ var bodyOffsetWidth = body ? body.offsetWidth : null;
920
+ var documentClientWidth = d ? d.clientWidth : null;
921
+ var documentScrollWidth = d ? d.scrollWidth : null;
922
+ var documentOffsetWidth = d ? d.offsetWidth : null;
923
+ var width = Math.max(bodyClientWidth, bodyScrollWidth, bodyOffsetWidth, documentClientWidth, documentScrollWidth, documentOffsetWidth);
924
+ var bodyClientHeight = body ? body.clientHeight : null;
925
+ var bodyScrollHeight = body ? body.scrollHeight : null;
926
+ var bodyOffsetHeight = body ? body.offsetHeight : null;
927
+ var documentClientHeight = d ? d.clientHeight : null;
928
+ var documentScrollHeight = d ? d.scrollHeight : null;
929
+ var documentOffsetHeight = d ? d.offsetHeight : null;
930
+ var height = Math.max(bodyClientHeight, bodyScrollHeight, bodyOffsetHeight, documentClientHeight, documentScrollHeight, documentOffsetHeight);
931
+ // Check that width or height has changed from before, and also that width & height are not null values
932
+ if ((data$c === null || width !== data$c.width || height !== data$c.height) && width !== null && height !== null) {
933
+ data$c = { width: width, height: height };
934
+ encode$4(8 /* Document */);
733
935
  }
734
936
  }
735
- function stop$s() {
736
- data$a = null;
937
+ function end() {
938
+ reset$i();
737
939
  }
738
940
 
739
- var upgrade$1 = /*#__PURE__*/Object.freeze({
740
- __proto__: null,
741
- get data () { return data$a; },
742
- start: start$v,
743
- upgrade: upgrade,
744
- stop: stop$s
745
- });
746
-
747
- /*! *****************************************************************************
748
- Copyright (c) Microsoft Corporation.
749
-
750
- Permission to use, copy, modify, and/or distribute this software for any
751
- purpose with or without fee is hereby granted.
752
-
753
- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
754
- REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
755
- AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
756
- INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
757
- LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
758
- OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
759
- PERFORMANCE OF THIS SOFTWARE.
760
- ***************************************************************************** */
761
-
762
- function __awaiter(thisArg, _arguments, P, generator) {
763
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
764
- return new (P || (P = Promise))(function (resolve, reject) {
765
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
766
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
767
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
768
- step((generator = generator.apply(thisArg, _arguments || [])).next());
769
- });
770
- }
771
-
772
- function __generator(thisArg, body) {
773
- var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
774
- return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
775
- function verb(n) { return function (v) { return step([n, v]); }; }
776
- function step(op) {
777
- if (f) throw new TypeError("Generator is already executing.");
778
- while (_) try {
779
- if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
780
- if (y = 0, t) op = [op[0] & 2, t.value];
781
- switch (op[0]) {
782
- case 0: case 1: t = op; break;
783
- case 4: _.label++; return { value: op[1], done: false };
784
- case 5: _.label++; y = op[1]; op = [0]; continue;
785
- case 7: op = _.ops.pop(); _.trys.pop(); continue;
786
- default:
787
- if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
788
- if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
789
- if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
790
- if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
791
- if (t[2]) _.ops.pop();
792
- _.trys.pop(); continue;
793
- }
794
- op = body.call(thisArg, _);
795
- } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
796
- if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
797
- }
798
- }
799
-
800
- var supported = "CompressionStream" /* CompressionStream */ in window;
801
- function compress (input) {
802
- return __awaiter(this, void 0, void 0, function () {
803
- var stream, _a;
804
- return __generator(this, function (_c) {
805
- switch (_c.label) {
806
- case 0:
807
- _c.trys.push([0, 3, , 4]);
808
- if (!supported) return [3 /*break*/, 2];
809
- stream = new ReadableStream({ start: function (controller) {
810
- return __awaiter(this, void 0, void 0, function () {
811
- return __generator(this, function (_a) {
812
- controller.enqueue(input);
813
- controller.close();
814
- return [2 /*return*/];
815
- });
816
- });
817
- } }).pipeThrough(new TextEncoderStream()).pipeThrough(new window["CompressionStream" /* CompressionStream */]("gzip"));
818
- _a = Uint8Array.bind;
819
- return [4 /*yield*/, read(stream)];
820
- case 1: return [2 /*return*/, new (_a.apply(Uint8Array, [void 0, _c.sent()]))()];
821
- case 2: return [3 /*break*/, 4];
822
- case 3:
823
- _c.sent();
824
- return [3 /*break*/, 4];
825
- case 4: return [2 /*return*/, null];
826
- }
827
- });
828
- });
829
- }
830
- function read(stream) {
941
+ function encode$4 (type, timer, ts) {
942
+ if (timer === void 0) { timer = null; }
943
+ if (ts === void 0) { ts = null; }
831
944
  return __awaiter(this, void 0, void 0, function () {
832
- var reader, chunks, done, value;
833
- var _a;
834
- return __generator(this, function (_b) {
835
- switch (_b.label) {
945
+ var eventTime, tokens, _a, d, _i, _b, r, b, _c, b_1, entry, values, _d, values_1, value, state, data, active, suspend, privacy, mangle, keys, _e, keys_1, key, size, factor, attr;
946
+ return __generator(this, function (_f) {
947
+ switch (_f.label) {
836
948
  case 0:
837
- reader = stream.getReader();
838
- chunks = [];
839
- done = false;
840
- value = [];
841
- _b.label = 1;
949
+ eventTime = ts || time();
950
+ tokens = [eventTime, type];
951
+ _a = type;
952
+ switch (_a) {
953
+ case 8 /* Document */: return [3 /*break*/, 1];
954
+ case 7 /* Region */: return [3 /*break*/, 2];
955
+ case 37 /* Box */: return [3 /*break*/, 3];
956
+ case 5 /* Discover */: return [3 /*break*/, 4];
957
+ case 6 /* Mutation */: return [3 /*break*/, 4];
958
+ }
959
+ return [3 /*break*/, 11];
842
960
  case 1:
843
- if (!!done) return [3 /*break*/, 3];
844
- return [4 /*yield*/, reader.read()];
961
+ d = data$c;
962
+ tokens.push(d.width);
963
+ tokens.push(d.height);
964
+ track$7(type, d.width, d.height);
965
+ queue(tokens);
966
+ return [3 /*break*/, 11];
845
967
  case 2:
846
- (_a = _b.sent(), done = _a.done, value = _a.value);
847
- if (done) {
848
- return [2 /*return*/, chunks];
968
+ for (_i = 0, _b = state$7; _i < _b.length; _i++) {
969
+ r = _b[_i];
970
+ tokens = [r.time, 7 /* Region */];
971
+ tokens.push(r.data.id);
972
+ tokens.push(r.data.interaction);
973
+ tokens.push(r.data.visibility);
974
+ tokens.push(r.data.name);
975
+ queue(tokens);
849
976
  }
850
- chunks.push.apply(chunks, value);
851
- return [3 /*break*/, 1];
852
- case 3: return [2 /*return*/, chunks];
977
+ reset$f();
978
+ return [3 /*break*/, 11];
979
+ case 3:
980
+ b = data$b;
981
+ for (_c = 0, b_1 = b; _c < b_1.length; _c++) {
982
+ entry = b_1[_c];
983
+ tokens.push(entry.id);
984
+ tokens.push(entry.width);
985
+ tokens.push(entry.height);
986
+ }
987
+ reset$h();
988
+ queue(tokens);
989
+ return [3 /*break*/, 11];
990
+ case 4:
991
+ // Check if we are operating within the context of the current page
992
+ if (state$8(timer) === 2 /* Stop */) {
993
+ return [3 /*break*/, 11];
994
+ }
995
+ values = updates$2();
996
+ if (!(values.length > 0)) return [3 /*break*/, 10];
997
+ _d = 0, values_1 = values;
998
+ _f.label = 5;
999
+ case 5:
1000
+ if (!(_d < values_1.length)) return [3 /*break*/, 9];
1001
+ value = values_1[_d];
1002
+ state = state$8(timer);
1003
+ if (!(state === 0 /* Wait */)) return [3 /*break*/, 7];
1004
+ return [4 /*yield*/, suspend$1(timer)];
1005
+ case 6:
1006
+ state = _f.sent();
1007
+ _f.label = 7;
1008
+ case 7:
1009
+ if (state === 2 /* Stop */) {
1010
+ return [3 /*break*/, 9];
1011
+ }
1012
+ data = value.data;
1013
+ active = value.metadata.active;
1014
+ suspend = value.metadata.suspend;
1015
+ privacy = value.metadata.privacy;
1016
+ mangle = shouldMangle(value);
1017
+ keys = active ? ["tag", "attributes", "value"] : ["tag"];
1018
+ compute$6(value.id);
1019
+ for (_e = 0, keys_1 = keys; _e < keys_1.length; _e++) {
1020
+ key = keys_1[_e];
1021
+ if (data[key]) {
1022
+ switch (key) {
1023
+ case "tag":
1024
+ size = value.metadata.size;
1025
+ factor = mangle ? -1 : 1;
1026
+ tokens.push(value.id * factor);
1027
+ if (value.parent && active) {
1028
+ tokens.push(value.parent);
1029
+ }
1030
+ if (value.previous && active) {
1031
+ tokens.push(value.previous);
1032
+ }
1033
+ tokens.push(suspend ? "*M" /* SuspendMutationTag */ : data[key]);
1034
+ if (size && size.length === 2) {
1035
+ tokens.push("" + "#" /* Box */ + str$1(size[0]) + "." + str$1(size[1]));
1036
+ }
1037
+ break;
1038
+ case "attributes":
1039
+ for (attr in data[key]) {
1040
+ if (data[key][attr] !== undefined) {
1041
+ tokens.push(attribute(attr, data[key][attr], privacy));
1042
+ }
1043
+ }
1044
+ break;
1045
+ case "value":
1046
+ tokens.push(scrub(data[key], data.tag, privacy, mangle));
1047
+ break;
1048
+ }
1049
+ }
1050
+ }
1051
+ _f.label = 8;
1052
+ case 8:
1053
+ _d++;
1054
+ return [3 /*break*/, 5];
1055
+ case 9:
1056
+ if (type === 6 /* Mutation */) {
1057
+ activity(eventTime);
1058
+ }
1059
+ queue(tokenize(tokens), !config$1.lean);
1060
+ _f.label = 10;
1061
+ case 10: return [3 /*break*/, 11];
1062
+ case 11: return [2 /*return*/];
853
1063
  }
854
1064
  });
855
1065
  });
1066
+ }
1067
+ function shouldMangle(value) {
1068
+ var privacy = value.metadata.privacy;
1069
+ return value.data.tag === "*T" /* TextTag */ && !(privacy === 0 /* None */ || privacy === 1 /* Sensitive */);
1070
+ }
1071
+ function str$1(input) {
1072
+ return input.toString(36);
1073
+ }
1074
+ function attribute(key, value, privacy) {
1075
+ return key + "=" + scrub(value, key, privacy);
856
1076
  }
857
1077
 
858
- var modules$1 = [baseline, dimension, variable, limit, summary, metadata$2, envelope$1, upload$1, ping$1, upgrade$1];
1078
+ var data$b = [];
1079
+ var enabled = false;
1080
+ var observer$2 = null;
859
1081
  function start$u() {
860
- // Metric needs to be initialized before we can start measuring. so metric is not wrapped in measure
861
- start$8();
862
- modules$1.forEach(function (x) { return measure(x.start)(); });
1082
+ reset$h();
1083
+ observer$2 = null;
1084
+ enabled = window["ResizeObserver"] ? true : false;
863
1085
  }
864
- function stop$r() {
865
- // Stop modules in the reverse order of their initialization
866
- // The ordering below should respect inter-module dependency.
867
- // E.g. if upgrade depends on upload, then upgrade needs to end before upload.
868
- // Similarly, if upload depends on metadata, upload needs to end before metadata.
869
- modules$1.slice().reverse().forEach(function (x) { return measure(x.stop)(); });
870
- stop$7();
1086
+ function compute$6(id) {
1087
+ if (enabled === false) {
1088
+ return;
1089
+ }
1090
+ observer$2 = observer$2 === null ? new ResizeObserver(handler$4) : observer$2;
1091
+ if (observer$2) {
1092
+ var value = getValue(id);
1093
+ // If this is the first time computing size for this node, go ahead and wire up ResizeObserver
1094
+ // In all other cases, value.metadata.size will be null or an array with two elements [width, height]
1095
+ // And, in those cases, we will skip through the following section and not attach the observer
1096
+ if (value && value.metadata.size !== null && value.metadata.size.length === 0) {
1097
+ var node = getNode(id);
1098
+ if (node && node.nodeType === Node.ELEMENT_NODE) {
1099
+ var e = node;
1100
+ var r = e.getBoundingClientRect();
1101
+ value.metadata.size = [Math.floor(r.width * 100 /* BoxPrecision */), Math.floor(r.height * 100 /* BoxPrecision */)];
1102
+ observer$2.observe(e);
1103
+ }
1104
+ }
1105
+ }
871
1106
  }
872
- function compute$7() {
873
- compute$b();
874
- compute$c();
875
- compute$9();
876
- compute$2();
877
- compute$8();
878
- compute$a();
879
- }
880
-
881
- function scrub (value, hint, privacy, mangle) {
882
- if (mangle === void 0) { mangle = false; }
883
- if (value) {
884
- switch (privacy) {
885
- case 0 /* None */:
886
- return value;
887
- case 1 /* Sensitive */:
888
- switch (hint) {
889
- case "*T" /* TextTag */:
890
- case "value":
891
- case "placeholder":
892
- return redact(value);
893
- case "input":
894
- return mangleToken(value);
1107
+ function handler$4(entries) {
1108
+ window.requestAnimationFrame(function () {
1109
+ for (var _i = 0, entries_1 = entries; _i < entries_1.length; _i++) {
1110
+ var entry = entries_1[_i];
1111
+ var target = entry.target;
1112
+ var id = target ? getId(target) : null;
1113
+ if (id) {
1114
+ var v = getValue(id);
1115
+ var s = v.metadata.size;
1116
+ var b = entry.borderBoxSize;
1117
+ var w = null;
1118
+ var h = null;
1119
+ // Check if browser supports borderBoxSize property on ResizeObserverEntry object
1120
+ // Otherwise, fall back to using getBoundingClientRect() to be cross browser compatible
1121
+ // Reference: https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserverEntry/borderBoxSize
1122
+ if (b && b.length > 0) {
1123
+ w = Math.floor(b[0].inlineSize * 100 /* BoxPrecision */);
1124
+ h = Math.floor(b[0].blockSize * 100 /* BoxPrecision */);
895
1125
  }
896
- return value;
897
- case 2 /* Text */:
898
- case 3 /* TextImage */:
899
- switch (hint) {
900
- case "*T" /* TextTag */:
901
- return mangle ? mangleText(value) : mask(value);
902
- case "src":
903
- case "srcset":
904
- case "title":
905
- case "alt":
906
- return privacy === 3 /* TextImage */ ? "" /* Empty */ : value;
907
- case "value":
908
- case "click":
909
- case "input":
910
- return mangleToken(value);
911
- case "placeholder":
912
- return mask(value);
1126
+ else {
1127
+ var r = target.getBoundingClientRect();
1128
+ w = Math.floor(r.width * 100 /* BoxPrecision */);
1129
+ h = Math.floor(r.height * 100 /* BoxPrecision */);
913
1130
  }
914
- break;
915
- }
916
- }
917
- return value;
918
- }
919
- function mangleText(value) {
920
- var trimmed = value.trim();
921
- if (trimmed.length > 0) {
922
- var first = trimmed[0];
923
- var index = value.indexOf(first);
924
- var prefix = value.substr(0, index);
925
- var suffix = value.substr(index + trimmed.length);
926
- return "" + prefix + trimmed.length.toString(36) + suffix;
927
- }
928
- return value;
929
- }
930
- function mask(value) {
931
- return value.replace(/\S/gi, "\u2022" /* Mask */);
932
- }
933
- function mangleToken(value) {
934
- var length = ((Math.floor(value.length / 5 /* WordLength */) + 1) * 5 /* WordLength */);
935
- var output = "" /* Empty */;
936
- for (var i = 0; i < length; i++) {
937
- output += i > 0 && i % 5 /* WordLength */ === 0 ? " " /* Space */ : "\u2022" /* Mask */;
938
- }
939
- return output;
940
- }
941
- function redact(value) {
942
- var spaceIndex = -1;
943
- var hasDigit = false;
944
- var hasEmail = false;
945
- var hasWhitespace = false;
946
- var array = null;
947
- for (var i = 0; i < value.length; i++) {
948
- var c = value.charCodeAt(i);
949
- hasDigit = hasDigit || (c >= 48 /* Zero */ && c <= 57 /* Nine */); // Check for digits in the current word
950
- hasEmail = hasEmail || c === 64 /* At */; // Check for @ sign anywhere within the current word
951
- hasWhitespace = c === 9 /* Tab */ || c === 10 /* NewLine */ || c === 13 /* Return */ || c === 32 /* Blank */;
952
- // Process each word as an individual token to redact any sensitive information
953
- if (i === 0 || i === value.length - 1 || hasWhitespace) {
954
- // Performance optimization: Lazy load string -> array conversion only when required
955
- if (hasDigit || hasEmail) {
956
- if (array === null) {
957
- array = value.split("" /* Empty */);
1131
+ // Capture new width & height only if they are different from what we have in in-memory cache
1132
+ if (w !== s[0] && h !== s[1]) {
1133
+ s = [w, h];
1134
+ data$b.push({ id: id, width: w, height: h });
958
1135
  }
959
- mutate(array, spaceIndex, hasWhitespace ? i : i + 1);
960
- }
961
- // Reset digit and email flags after every word boundary, except the beginning of string
962
- if (hasWhitespace) {
963
- hasDigit = false;
964
- hasEmail = false;
965
- spaceIndex = i;
966
1136
  }
967
1137
  }
968
- }
969
- return array ? array.join("" /* Empty */) : value;
1138
+ // Schedule encode only when we have at least one valid data entry
1139
+ if (data$b.length > 0) {
1140
+ encode$4(37 /* Box */);
1141
+ }
1142
+ });
970
1143
  }
971
- function mutate(array, start, end) {
972
- for (var i = start + 1; i < end; i++) {
973
- array[i] = "\u2022" /* Mask */;
1144
+ function reset$h() {
1145
+ data$b = [];
1146
+ }
1147
+ function stop$s() {
1148
+ reset$h();
1149
+ if (observer$2) {
1150
+ observer$2.disconnect();
1151
+ observer$2 = null;
974
1152
  }
1153
+ enabled = false;
975
1154
  }
976
1155
 
977
- // Track the start time to be able to compute duration at the end of the task
978
- var idleTimeout = 5000;
979
- var tracker = {};
980
- var queuedTasks = [];
981
- var activeTask = null;
982
- var pauseTask = null;
983
- var resumeResolve = null;
984
- function pause$1() {
985
- if (pauseTask === null) {
986
- pauseTask = new Promise(function (resolve) {
987
- resumeResolve = resolve;
988
- });
989
- }
1156
+ var history$4 = {};
1157
+ var data$a;
1158
+ function start$t() {
1159
+ bind(window, "error", handler$3);
1160
+ history$4 = {};
990
1161
  }
991
- function resume$1() {
992
- if (pauseTask) {
993
- resumeResolve();
994
- pauseTask = null;
995
- if (activeTask === null) {
996
- run();
1162
+ function handler$3(error) {
1163
+ var e = error["error"] || error;
1164
+ // While rare, it's possible for code to fail repeatedly during the lifetime of the same page
1165
+ // In those cases, we only want to log the failure first few times and not spam logs with redundant information.
1166
+ if (!(e.message in history$4)) {
1167
+ history$4[e.message] = 0;
1168
+ }
1169
+ if (history$4[e.message]++ >= 5 /* ScriptErrorLimit */) {
1170
+ return true;
1171
+ }
1172
+ // Send back information only if the handled error has valid information
1173
+ if (e && e.message) {
1174
+ data$a = {
1175
+ message: e.message,
1176
+ line: error["lineno"],
1177
+ column: error["colno"],
1178
+ stack: e.stack,
1179
+ source: error["filename"]
1180
+ };
1181
+ // In certain cases, ResizeObserver could lead to flood of benign errors - especially when video element is involved.
1182
+ // Reference Chromium issue: https://bugs.chromium.org/p/chromium/issues/detail?id=809574
1183
+ // Even though it doesn't impact user experience, or show up in console, it can still flood error reporting through on error
1184
+ // To mitigate that, we turn off Clarity's ResizeObserver on getting the first instance of this error
1185
+ if (e.message.indexOf("ResizeObserver" /* ResizeObserver */) >= 0) {
1186
+ stop$s();
1187
+ return false;
997
1188
  }
1189
+ encode$3(31 /* ScriptError */);
998
1190
  }
999
- }
1000
- function reset$i() {
1001
- tracker = {};
1002
- queuedTasks = [];
1003
- activeTask = null;
1004
- pauseTask = null;
1005
- }
1006
- function schedule$1(task, priority) {
1007
- if (priority === void 0) { priority = 0 /* Normal */; }
1191
+ return true;
1192
+ }
1193
+
1194
+ function encode$3 (type) {
1008
1195
  return __awaiter(this, void 0, void 0, function () {
1009
- var _i, queuedTasks_1, q, promise;
1196
+ var tokens;
1010
1197
  return __generator(this, function (_a) {
1011
- // If this task is already scheduled, skip it
1012
- for (_i = 0, queuedTasks_1 = queuedTasks; _i < queuedTasks_1.length; _i++) {
1013
- q = queuedTasks_1[_i];
1014
- if (q.task === task) {
1015
- return [2 /*return*/];
1016
- }
1017
- }
1018
- promise = new Promise(function (resolve) {
1019
- var insert = priority === 1 /* High */ ? "unshift" : "push";
1020
- // Queue this task for asynchronous execution later
1021
- // We also store a unique page identifier (id) along with the task to ensure
1022
- // ensure that we do not accidentally execute this task in context of a different page
1023
- queuedTasks[insert]({ task: task, resolve: resolve, id: id() });
1024
- });
1025
- // If there is no active task running, and Clarity is not in pause state,
1026
- // invoke the first task in the queue synchronously. This ensures that we don't yield the thread during unload event
1027
- if (activeTask === null && pauseTask === null) {
1028
- run();
1198
+ tokens = [time(), type];
1199
+ switch (type) {
1200
+ case 31 /* ScriptError */:
1201
+ tokens.push(data$a.message);
1202
+ tokens.push(data$a.line);
1203
+ tokens.push(data$a.column);
1204
+ tokens.push(data$a.stack);
1205
+ tokens.push(data$a.source);
1206
+ queue(tokens);
1207
+ break;
1208
+ case 33 /* Log */:
1209
+ if (data$9) {
1210
+ tokens.push(data$9.code);
1211
+ tokens.push(data$9.name);
1212
+ tokens.push(data$9.message);
1213
+ tokens.push(data$9.stack);
1214
+ tokens.push(data$9.severity);
1215
+ queue(tokens, false);
1216
+ }
1217
+ break;
1029
1218
  }
1030
- return [2 /*return*/, promise];
1219
+ return [2 /*return*/];
1031
1220
  });
1032
1221
  });
1222
+ }
1223
+
1224
+ var history$3 = {};
1225
+ var data$9;
1226
+ function start$s() {
1227
+ history$3 = {};
1228
+ bind(document, "securitypolicyviolation", csp);
1033
1229
  }
1034
- function run() {
1035
- var entry = queuedTasks.shift();
1036
- if (entry) {
1037
- activeTask = entry;
1038
- entry.task().then(function () {
1039
- // Bail out if the context in which this task was operating is different from the current page
1040
- // An example scenario where task could span across pages is Single Page Applications (SPA)
1041
- // A task that started on page #1, but completes on page #2
1042
- if (entry.id !== id()) {
1043
- return;
1044
- }
1045
- entry.resolve();
1046
- activeTask = null; // Reset active task back to null now that the promise is resolved
1047
- run();
1048
- }).catch(function (error) {
1049
- // If one of the scheduled tasks failed, log, recover and continue processing rest of the tasks
1050
- if (entry.id !== id()) {
1051
- return;
1052
- }
1053
- if (error) {
1054
- log(0 /* RunTask */, 1 /* Warning */, error.name, error.message, error.stack);
1055
- }
1056
- activeTask = null;
1057
- run();
1058
- });
1230
+ function log$1(code, severity, name, message, stack) {
1231
+ if (name === void 0) { name = null; }
1232
+ if (message === void 0) { message = null; }
1233
+ if (stack === void 0) { stack = null; }
1234
+ var key = name ? name + "|" + message : "";
1235
+ // While rare, it's possible for code to fail repeatedly during the lifetime of the same page
1236
+ // In those cases, we only want to log the failure once and not spam logs with redundant information.
1237
+ if (code in history$3 && history$3[code].indexOf(key) >= 0) {
1238
+ return;
1239
+ }
1240
+ data$9 = { code: code, name: name, message: message, stack: stack, severity: severity };
1241
+ // Maintain history of errors in memory to avoid sending redundant information
1242
+ if (code in history$3) {
1243
+ history$3[code].push(key);
1059
1244
  }
1245
+ else {
1246
+ history$3[code] = [key];
1247
+ }
1248
+ encode$3(33 /* Log */);
1060
1249
  }
1061
- function state$8(timer) {
1062
- var id = key(timer);
1063
- if (id in tracker) {
1064
- var elapsed = performance.now() - tracker[id].start;
1065
- return (elapsed > tracker[id].yield) ? 0 /* Wait */ : 1 /* Run */;
1250
+ function csp(e) {
1251
+ var upload = config$1.upload;
1252
+ // Look for first "/" starting after initial "https://" string
1253
+ var parts = upload && typeof upload === "string" /* String */ ? upload.substr(0, upload.indexOf("/", "https://" /* HTTPS */.length)).split("." /* Dot */) : [];
1254
+ var domain = parts.length >= 2 ? parts.splice(-2).join("." /* Dot */) : null;
1255
+ // Capture content security policy violation only if disposition value is not explicitly set to "report"
1256
+ if (domain && e.blockedURI && e.blockedURI.indexOf(domain) >= 0 && e["disposition"] !== "report" /* Report */) {
1257
+ log$1(7 /* ContentSecurityPolicy */, 1 /* Warning */, e.blockedURI);
1066
1258
  }
1067
- // If this task is no longer being tracked, send stop message to the caller
1068
- return 2 /* Stop */;
1069
1259
  }
1070
- function start$t(timer) {
1071
- tracker[key(timer)] = { start: performance.now(), calls: 0, yield: 30 /* LongTask */ };
1072
- }
1073
- function restart$1(timer) {
1074
- var id = key(timer);
1075
- if (tracker && tracker[id]) {
1076
- var c = tracker[id].calls;
1077
- var y = tracker[id].yield;
1078
- start$t(timer);
1079
- tracker[id].calls = c + 1;
1080
- tracker[id].yield = y;
1081
- }
1082
- }
1083
- function stop$q(timer) {
1084
- var end = performance.now();
1085
- var id = key(timer);
1086
- var duration = end - tracker[id].start;
1087
- sum(timer.cost, duration);
1088
- count$1(5 /* InvokeCount */);
1089
- // For the first execution, which is synchronous, time is automatically counted towards TotalDuration.
1090
- // However, for subsequent asynchronous runs, we need to manually update TotalDuration metric.
1091
- if (tracker[id].calls > 0) {
1092
- sum(4 /* TotalCost */, duration);
1260
+ function stop$r() {
1261
+ history$3 = {};
1262
+ }
1263
+
1264
+ var formatRegex = /1/g;
1265
+ var digitsRegex$1 = /[^0-9\.]/g;
1266
+ var digitsWithCommaRegex = /[^0-9\.,]/g;
1267
+ var regexCache = {};
1268
+ function regions$1(root, value) {
1269
+ var _loop_1 = function (v) {
1270
+ var regionId = v[0], selector = v[1], filter = v[2], match = v[3];
1271
+ var valid = true;
1272
+ switch (filter) {
1273
+ case 0 /* Url */:
1274
+ valid = match && !!top.location.href.match(regex(match));
1275
+ break;
1276
+ case 1 /* Javascript */:
1277
+ valid = match && !!evaluate(match);
1278
+ break;
1279
+ }
1280
+ if (valid) {
1281
+ root.querySelectorAll(selector).forEach(function (e) { return observe$b(e, regionId.toString()); });
1282
+ }
1283
+ };
1284
+ for (var _i = 0, value_1 = value; _i < value_1.length; _i++) {
1285
+ var v = value_1[_i];
1286
+ _loop_1(v);
1093
1287
  }
1094
1288
  }
1095
- function suspend$1(timer) {
1096
- return __awaiter(this, void 0, void 0, function () {
1097
- var id, _a;
1098
- return __generator(this, function (_b) {
1099
- switch (_b.label) {
1100
- case 0:
1101
- id = key(timer);
1102
- if (!(id in tracker)) return [3 /*break*/, 2];
1103
- stop$q(timer);
1104
- _a = tracker[id];
1105
- return [4 /*yield*/, wait()];
1106
- case 1:
1107
- _a.yield = (_b.sent()).timeRemaining();
1108
- restart$1(timer);
1109
- _b.label = 2;
1110
- case 2:
1111
- // After we are done with suspending task, ensure that we are still operating in the right context
1112
- // If the task is still being tracked, continue running the task, otherwise ask caller to stop execution
1113
- return [2 /*return*/, id in tracker ? 1 /* Run */ : 2 /* Stop */];
1114
- }
1115
- });
1116
- });
1117
- }
1118
- function key(timer) {
1119
- return timer.id + "." + timer.cost;
1120
- }
1121
- function wait() {
1122
- return __awaiter(this, void 0, void 0, function () {
1123
- return __generator(this, function (_a) {
1124
- switch (_a.label) {
1125
- case 0:
1126
- if (!pauseTask) return [3 /*break*/, 2];
1127
- return [4 /*yield*/, pauseTask];
1128
- case 1:
1129
- _a.sent();
1130
- _a.label = 2;
1131
- case 2: return [2 /*return*/, new Promise(function (resolve) {
1132
- requestIdleCallback(resolve, { timeout: idleTimeout });
1133
- })];
1289
+ function metrics(root, value) {
1290
+ var _loop_2 = function (v) {
1291
+ var metricId = v[0], source = v[1], match = v[2], scale = v[3];
1292
+ if (match) {
1293
+ switch (source) {
1294
+ case 0 /* Text */:
1295
+ root.querySelectorAll(match).forEach(function (e) { max(metricId, num$2(e.innerText, scale)); });
1296
+ break;
1297
+ case 2 /* Attribute */:
1298
+ root.querySelectorAll("[" + match + "]").forEach(function (e) { max(metricId, num$2(e.getAttribute(match), scale, false)); });
1299
+ break;
1300
+ case 1 /* Javascript */:
1301
+ max(metricId, evaluate(match, "number" /* Number */));
1302
+ break;
1134
1303
  }
1135
- });
1136
- });
1137
- }
1138
- // Use native implementation of requestIdleCallback if it exists.
1139
- // Otherwise, fall back to a custom implementation using requestAnimationFrame & MessageChannel.
1140
- // While it's not possible to build a perfect polyfill given the nature of this API, the following code attempts to get close.
1141
- // Background context: requestAnimationFrame invokes the js code right before: style, layout and paint computation within the frame.
1142
- // This means, that any code that runs as part of requestAnimationFrame will by default be blocking in nature. Not what we want.
1143
- // For non-blocking behavior, We need to know when browser has finished painiting. This can be accomplished in two different ways (hacks):
1144
- // (1) Use MessageChannel to pass the message, and browser will receive the message right after pain event has occured.
1145
- // (2) Use setTimeout call within requestAnimationFrame. This also works, but there's a risk that browser may throttle setTimeout calls.
1146
- // Given this information, we are currently using (1) from above. More information on (2) as well as some additional context is below:
1147
- // https://developer.mozilla.org/en-US/docs/Mozilla/Firefox/Performance_best_practices_for_Firefox_fe_engineers
1148
- function requestIdleCallbackPolyfill(callback, options) {
1149
- var startTime = performance.now();
1150
- var channel = new MessageChannel();
1151
- var incoming = channel.port1;
1152
- var outgoing = channel.port2;
1153
- incoming.onmessage = function (event) {
1154
- var currentTime = performance.now();
1155
- var elapsed = currentTime - startTime;
1156
- var duration = currentTime - event.data;
1157
- if (duration > 30 /* LongTask */ && elapsed < options.timeout) {
1158
- requestAnimationFrame(function () { outgoing.postMessage(currentTime); });
1159
- }
1160
- else {
1161
- var didTimeout_1 = elapsed > options.timeout;
1162
- callback({
1163
- didTimeout: didTimeout_1,
1164
- timeRemaining: function () { return didTimeout_1 ? 30 /* LongTask */ : Math.max(0, 30 /* LongTask */ - duration); }
1165
- });
1166
1304
  }
1167
1305
  };
1168
- requestAnimationFrame(function () { outgoing.postMessage(performance.now()); });
1306
+ for (var _i = 0, value_2 = value; _i < value_2.length; _i++) {
1307
+ var v = value_2[_i];
1308
+ _loop_2(v);
1309
+ }
1169
1310
  }
1170
- var requestIdleCallback = window["requestIdleCallback"] || requestIdleCallbackPolyfill;
1171
-
1172
- // Following code takes an array of tokens and transforms it to optimize for repeating tokens and make it efficient to send over the wire
1173
- // The way it works is that it iterate over all tokens and checks if the current token was already seen in the tokens array so far
1174
- // If so, it replaces the token with its reference (index). This helps us save bytes by not repeating the same value twice.
1175
- // E.g. If tokens array is: ["hello", "world", "coding", "language", "world", "language", "example"]
1176
- // Then the resulting tokens array after following code execution would be: ["hello", "world", "coding", "language", [1, 3], "example"]
1177
- // Where [1,3] points to tokens[1] => "world" and tokens[3] => "language"
1178
- function tokenize (tokens) {
1179
- var output = [];
1180
- var lookup = {};
1181
- var pointer = 0;
1182
- var reference = null;
1183
- for (var i = 0; i < tokens.length; i++) {
1184
- // Only optimize for string values
1185
- if (typeof tokens[i] === "string" /* String */) {
1186
- var token = tokens[i];
1187
- var index = lookup[token] || -1;
1188
- if (index >= 0) {
1189
- if (reference) {
1190
- reference.push(index);
1191
- }
1192
- else {
1193
- reference = [index];
1194
- output.push(reference);
1195
- pointer++;
1196
- }
1197
- }
1198
- else {
1199
- reference = null;
1200
- output.push(token);
1201
- lookup[token] = pointer++;
1311
+ function dimensions(root, value) {
1312
+ var _loop_3 = function (v) {
1313
+ var dimensionId = v[0], source = v[1], match = v[2];
1314
+ if (match) {
1315
+ switch (source) {
1316
+ case 0 /* Text */:
1317
+ root.querySelectorAll(match).forEach(function (e) { log(dimensionId, str(e.innerText)); });
1318
+ break;
1319
+ case 2 /* Attribute */:
1320
+ root.querySelectorAll("[" + match + "]").forEach(function (e) { log(dimensionId, str(e.getAttribute(match))); });
1321
+ break;
1322
+ case 1 /* Javascript */:
1323
+ log(dimensionId, str(evaluate(match, "string" /* String */)));
1324
+ break;
1202
1325
  }
1203
1326
  }
1204
- else {
1205
- // If the value is anything other than string, append it as it is to the output array
1206
- // And, also increment the pointer to stay in sync with output array
1207
- reference = null;
1208
- output.push(tokens[i]);
1209
- pointer++;
1210
- }
1327
+ };
1328
+ for (var _i = 0, value_3 = value; _i < value_3.length; _i++) {
1329
+ var v = value_3[_i];
1330
+ _loop_3(v);
1211
1331
  }
1212
- return output;
1213
- }
1214
-
1215
- var data$9;
1216
- function reset$h() {
1217
- data$9 = null;
1218
1332
  }
1219
- function start$s() {
1220
- reset$h();
1221
- compute$6();
1333
+ function regex(match) {
1334
+ regexCache[match] = match in regexCache ? regexCache[match] : new RegExp(match);
1335
+ return regexCache[match];
1222
1336
  }
1223
- function compute$6() {
1224
- var body = document.body;
1225
- var d = document.documentElement;
1226
- var bodyClientWidth = body ? body.clientWidth : null;
1227
- var bodyScrollWidth = body ? body.scrollWidth : null;
1228
- var bodyOffsetWidth = body ? body.offsetWidth : null;
1229
- var documentClientWidth = d ? d.clientWidth : null;
1230
- var documentScrollWidth = d ? d.scrollWidth : null;
1231
- var documentOffsetWidth = d ? d.offsetWidth : null;
1232
- var width = Math.max(bodyClientWidth, bodyScrollWidth, bodyOffsetWidth, documentClientWidth, documentScrollWidth, documentOffsetWidth);
1233
- var bodyClientHeight = body ? body.clientHeight : null;
1234
- var bodyScrollHeight = body ? body.scrollHeight : null;
1235
- var bodyOffsetHeight = body ? body.offsetHeight : null;
1236
- var documentClientHeight = d ? d.clientHeight : null;
1237
- var documentScrollHeight = d ? d.scrollHeight : null;
1238
- var documentOffsetHeight = d ? d.offsetHeight : null;
1239
- var height = Math.max(bodyClientHeight, bodyScrollHeight, bodyOffsetHeight, documentClientHeight, documentScrollHeight, documentOffsetHeight);
1240
- // Check that width or height has changed from before, and also that width & height are not null values
1241
- if ((data$9 === null || width !== data$9.width || height !== data$9.height) && width !== null && height !== null) {
1242
- data$9 = { width: width, height: height };
1243
- encode$4(8 /* Document */);
1337
+ // The function below takes in a variable name in following format: "a.b.c" and safely evaluates its value in javascript context
1338
+ // For instance, for a.b.c, it will first check window["a"]. If it exists, it will recursively look at: window["a"]["b"] and finally,
1339
+ // return the value for window["a"]["b"]["c"].
1340
+ function evaluate(variable, type, base) {
1341
+ if (type === void 0) { type = null; }
1342
+ if (base === void 0) { base = window; }
1343
+ var parts = variable.split("." /* Dot */);
1344
+ var first = parts.shift();
1345
+ if (base && base[first]) {
1346
+ if (parts.length > 0) {
1347
+ return evaluate(parts.join("." /* Dot */), type, base[first]);
1348
+ }
1349
+ var output = type === null || type === typeof base[first] ? base[first] : null;
1350
+ return output;
1244
1351
  }
1352
+ return null;
1245
1353
  }
1246
- function end() {
1247
- reset$h();
1248
- }
1249
-
1250
- function encode$4 (type, timer, ts) {
1251
- if (timer === void 0) { timer = null; }
1252
- if (ts === void 0) { ts = null; }
1253
- return __awaiter(this, void 0, void 0, function () {
1254
- var eventTime, tokens, _a, d, _i, _b, r, b, _c, b_1, entry, values, _d, values_1, value, state, data, active, suspend, privacy, mangle, keys, _e, keys_1, key, size, factor, attr;
1255
- return __generator(this, function (_f) {
1256
- switch (_f.label) {
1257
- case 0:
1258
- eventTime = ts || time();
1259
- tokens = [eventTime, type];
1260
- _a = type;
1261
- switch (_a) {
1262
- case 8 /* Document */: return [3 /*break*/, 1];
1263
- case 7 /* Region */: return [3 /*break*/, 2];
1264
- case 37 /* Box */: return [3 /*break*/, 3];
1265
- case 5 /* Discover */: return [3 /*break*/, 4];
1266
- case 6 /* Mutation */: return [3 /*break*/, 4];
1267
- }
1268
- return [3 /*break*/, 11];
1269
- case 1:
1270
- d = data$9;
1271
- tokens.push(d.width);
1272
- tokens.push(d.height);
1273
- track$7(type, d.width, d.height);
1274
- queue(tokens);
1275
- return [3 /*break*/, 11];
1276
- case 2:
1277
- for (_i = 0, _b = state$7; _i < _b.length; _i++) {
1278
- r = _b[_i];
1279
- tokens = [r.time, 7 /* Region */];
1280
- tokens.push(r.data.id);
1281
- tokens.push(r.data.interaction);
1282
- tokens.push(r.data.visibility);
1283
- tokens.push(r.data.name);
1284
- queue(tokens);
1285
- }
1286
- reset$e();
1287
- return [3 /*break*/, 11];
1288
- case 3:
1289
- b = data$8;
1290
- for (_c = 0, b_1 = b; _c < b_1.length; _c++) {
1291
- entry = b_1[_c];
1292
- tokens.push(entry.id);
1293
- tokens.push(entry.width);
1294
- tokens.push(entry.height);
1295
- }
1296
- reset$g();
1297
- queue(tokens);
1298
- return [3 /*break*/, 11];
1299
- case 4:
1300
- // Check if we are operating within the context of the current page
1301
- if (state$8(timer) === 2 /* Stop */) {
1302
- return [3 /*break*/, 11];
1303
- }
1304
- values = updates$2();
1305
- if (!(values.length > 0)) return [3 /*break*/, 10];
1306
- _d = 0, values_1 = values;
1307
- _f.label = 5;
1308
- case 5:
1309
- if (!(_d < values_1.length)) return [3 /*break*/, 9];
1310
- value = values_1[_d];
1311
- state = state$8(timer);
1312
- if (!(state === 0 /* Wait */)) return [3 /*break*/, 7];
1313
- return [4 /*yield*/, suspend$1(timer)];
1314
- case 6:
1315
- state = _f.sent();
1316
- _f.label = 7;
1317
- case 7:
1318
- if (state === 2 /* Stop */) {
1319
- return [3 /*break*/, 9];
1320
- }
1321
- data = value.data;
1322
- active = value.metadata.active;
1323
- suspend = value.metadata.suspend;
1324
- privacy = value.metadata.privacy;
1325
- mangle = shouldMangle(value);
1326
- keys = active ? ["tag", "attributes", "value"] : ["tag"];
1327
- compute$5(value.id);
1328
- for (_e = 0, keys_1 = keys; _e < keys_1.length; _e++) {
1329
- key = keys_1[_e];
1330
- if (data[key]) {
1331
- switch (key) {
1332
- case "tag":
1333
- size = value.metadata.size;
1334
- factor = mangle ? -1 : 1;
1335
- tokens.push(value.id * factor);
1336
- if (value.parent && active) {
1337
- tokens.push(value.parent);
1338
- }
1339
- if (value.previous && active) {
1340
- tokens.push(value.previous);
1341
- }
1342
- tokens.push(suspend ? "*M" /* SuspendMutationTag */ : data[key]);
1343
- if (size && size.length === 2) {
1344
- tokens.push("" + "#" /* Box */ + str$1(size[0]) + "." + str$1(size[1]));
1345
- }
1346
- break;
1347
- case "attributes":
1348
- for (attr in data[key]) {
1349
- if (data[key][attr] !== undefined) {
1350
- tokens.push(attribute(attr, data[key][attr], privacy));
1351
- }
1352
- }
1353
- break;
1354
- case "value":
1355
- tokens.push(scrub(data[key], data.tag, privacy, mangle));
1356
- break;
1357
- }
1358
- }
1359
- }
1360
- _f.label = 8;
1361
- case 8:
1362
- _d++;
1363
- return [3 /*break*/, 5];
1364
- case 9:
1365
- if (type === 6 /* Mutation */) {
1366
- activity(eventTime);
1367
- }
1368
- queue(tokenize(tokens), !config$1.lean);
1369
- _f.label = 10;
1370
- case 10: return [3 /*break*/, 11];
1371
- case 11: return [2 /*return*/];
1372
- }
1373
- });
1374
- });
1375
- }
1376
- function shouldMangle(value) {
1377
- var privacy = value.metadata.privacy;
1378
- return value.data.tag === "*T" /* TextTag */ && !(privacy === 0 /* None */ || privacy === 1 /* Sensitive */);
1379
- }
1380
- function str$1(input) {
1381
- return input.toString(36);
1382
- }
1383
- function attribute(key, value, privacy) {
1384
- return key + "=" + scrub(value, key, privacy);
1385
- }
1386
-
1387
- var data$8 = [];
1388
- var enabled = false;
1389
- var observer$2 = null;
1390
- function start$r() {
1391
- reset$g();
1392
- observer$2 = null;
1393
- enabled = window["ResizeObserver"] ? true : false;
1394
- }
1395
- function compute$5(id) {
1396
- if (enabled === false) {
1397
- return;
1398
- }
1399
- observer$2 = observer$2 === null ? new ResizeObserver(handler$4) : observer$2;
1400
- if (observer$2) {
1401
- var value = getValue(id);
1402
- // If this is the first time computing size for this node, go ahead and wire up ResizeObserver
1403
- // In all other cases, value.metadata.size will be null or an array with two elements [width, height]
1404
- // And, in those cases, we will skip through the following section and not attach the observer
1405
- if (value && value.metadata.size !== null && value.metadata.size.length === 0) {
1406
- var node = getNode(id);
1407
- if (node && node.nodeType === Node.ELEMENT_NODE) {
1408
- var e = node;
1409
- var r = e.getBoundingClientRect();
1410
- value.metadata.size = [Math.floor(r.width * 100 /* BoxPrecision */), Math.floor(r.height * 100 /* BoxPrecision */)];
1411
- observer$2.observe(e);
1412
- }
1413
- }
1414
- }
1415
- }
1416
- function handler$4(entries) {
1417
- window.requestAnimationFrame(function () {
1418
- for (var _i = 0, entries_1 = entries; _i < entries_1.length; _i++) {
1419
- var entry = entries_1[_i];
1420
- var target = entry.target;
1421
- var id = target ? getId(target) : null;
1422
- if (id) {
1423
- var v = getValue(id);
1424
- var s = v.metadata.size;
1425
- var b = entry.borderBoxSize;
1426
- var w = null;
1427
- var h = null;
1428
- // Check if browser supports borderBoxSize property on ResizeObserverEntry object
1429
- // Otherwise, fall back to using getBoundingClientRect() to be cross browser compatible
1430
- // Reference: https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserverEntry/borderBoxSize
1431
- if (b && b.length > 0) {
1432
- w = Math.floor(b[0].inlineSize * 100 /* BoxPrecision */);
1433
- h = Math.floor(b[0].blockSize * 100 /* BoxPrecision */);
1434
- }
1435
- else {
1436
- var r = target.getBoundingClientRect();
1437
- w = Math.floor(r.width * 100 /* BoxPrecision */);
1438
- h = Math.floor(r.height * 100 /* BoxPrecision */);
1439
- }
1440
- // Capture new width & height only if they are different from what we have in in-memory cache
1441
- if (w !== s[0] && h !== s[1]) {
1442
- s = [w, h];
1443
- data$8.push({ id: id, width: w, height: h });
1444
- }
1445
- }
1446
- }
1447
- // Schedule encode only when we have at least one valid data entry
1448
- if (data$8.length > 0) {
1449
- encode$4(37 /* Box */);
1450
- }
1451
- });
1452
- }
1453
- function reset$g() {
1454
- data$8 = [];
1455
- }
1456
- function stop$p() {
1457
- reset$g();
1458
- if (observer$2) {
1459
- observer$2.disconnect();
1460
- observer$2 = null;
1461
- }
1462
- enabled = false;
1463
- }
1464
-
1465
- var history$3 = {};
1466
- var data$7;
1467
- function start$q() {
1468
- bind(window, "error", handler$3);
1469
- history$3 = {};
1470
- }
1471
- function handler$3(error) {
1472
- var e = error["error"] || error;
1473
- // While rare, it's possible for code to fail repeatedly during the lifetime of the same page
1474
- // In those cases, we only want to log the failure first few times and not spam logs with redundant information.
1475
- if (!(e.message in history$3)) {
1476
- history$3[e.message] = 0;
1477
- }
1478
- if (history$3[e.message]++ >= 5 /* ScriptErrorLimit */) {
1479
- return true;
1480
- }
1481
- // Send back information only if the handled error has valid information
1482
- if (e && e.message) {
1483
- data$7 = {
1484
- message: e.message,
1485
- line: error["lineno"],
1486
- column: error["colno"],
1487
- stack: e.stack,
1488
- source: error["filename"]
1489
- };
1490
- // In certain cases, ResizeObserver could lead to flood of benign errors - especially when video element is involved.
1491
- // Reference Chromium issue: https://bugs.chromium.org/p/chromium/issues/detail?id=809574
1492
- // Even though it doesn't impact user experience, or show up in console, it can still flood error reporting through on error
1493
- // To mitigate that, we turn off Clarity's ResizeObserver on getting the first instance of this error
1494
- if (e.message.indexOf("ResizeObserver" /* ResizeObserver */) >= 0) {
1495
- stop$p();
1496
- return false;
1497
- }
1498
- encode$3(31 /* ScriptError */);
1499
- }
1500
- return true;
1501
- }
1502
-
1503
- function encode$3 (type) {
1504
- return __awaiter(this, void 0, void 0, function () {
1505
- var tokens;
1506
- return __generator(this, function (_a) {
1507
- tokens = [time(), type];
1508
- switch (type) {
1509
- case 31 /* ScriptError */:
1510
- tokens.push(data$7.message);
1511
- tokens.push(data$7.line);
1512
- tokens.push(data$7.column);
1513
- tokens.push(data$7.stack);
1514
- tokens.push(data$7.source);
1515
- queue(tokens);
1516
- break;
1517
- case 33 /* Log */:
1518
- if (data$6) {
1519
- tokens.push(data$6.code);
1520
- tokens.push(data$6.name);
1521
- tokens.push(data$6.message);
1522
- tokens.push(data$6.stack);
1523
- tokens.push(data$6.severity);
1524
- queue(tokens, false);
1525
- }
1526
- break;
1527
- }
1528
- return [2 /*return*/];
1529
- });
1530
- });
1531
- }
1532
-
1533
- var history$2 = {};
1534
- var data$6;
1535
- function start$p() {
1536
- history$2 = {};
1537
- bind(document, "securitypolicyviolation", csp);
1538
- }
1539
- function log(code, severity, name, message, stack) {
1540
- if (name === void 0) { name = null; }
1541
- if (message === void 0) { message = null; }
1542
- if (stack === void 0) { stack = null; }
1543
- var key = name ? name + "|" + message : "";
1544
- // While rare, it's possible for code to fail repeatedly during the lifetime of the same page
1545
- // In those cases, we only want to log the failure once and not spam logs with redundant information.
1546
- if (code in history$2 && history$2[code].indexOf(key) >= 0) {
1547
- return;
1548
- }
1549
- data$6 = { code: code, name: name, message: message, stack: stack, severity: severity };
1550
- // Maintain history of errors in memory to avoid sending redundant information
1551
- if (code in history$2) {
1552
- history$2[code].push(key);
1553
- }
1554
- else {
1555
- history$2[code] = [key];
1556
- }
1557
- encode$3(33 /* Log */);
1558
- }
1559
- function csp(e) {
1560
- var upload = config$1.upload;
1561
- var parts = upload ? upload.substr(0, upload.indexOf("/", "https://" /* HTTPS */.length)).split("." /* Dot */) : []; // Look for first "/" starting after initial "https://" string
1562
- var domain = parts.length >= 2 ? parts.splice(-2).join("." /* Dot */) : null;
1563
- // Capture content security policy violation only if disposition value is not explicitly set to "report"
1564
- if (domain && e.blockedURI && e.blockedURI.indexOf(domain) >= 0 && e["disposition"] !== "report" /* Report */) {
1565
- log(7 /* ContentSecurityPolicy */, 1 /* Warning */, e.blockedURI);
1566
- }
1567
- }
1568
- function stop$o() {
1569
- history$2 = {};
1570
- }
1571
-
1572
- var formatRegex = /1/g;
1573
- var digitsRegex$1 = /[^0-9\.]/g;
1574
- var digitsWithCommaRegex = /[^0-9\.,]/g;
1575
- var regexCache = {};
1576
- function regions$1(root, value) {
1577
- var _loop_1 = function (v) {
1578
- var regionId = v[0], selector = v[1], filter = v[2], match = v[3];
1579
- var valid = true;
1580
- switch (filter) {
1581
- case 0 /* Url */:
1582
- valid = match && !!top.location.href.match(regex(match));
1583
- break;
1584
- case 1 /* Javascript */:
1585
- valid = match && !!evaluate(match);
1586
- break;
1587
- }
1588
- if (valid) {
1589
- root.querySelectorAll(selector).forEach(function (e) { return observe$b(e, regionId.toString()); });
1590
- }
1591
- };
1592
- for (var _i = 0, value_1 = value; _i < value_1.length; _i++) {
1593
- var v = value_1[_i];
1594
- _loop_1(v);
1595
- }
1596
- }
1597
- function metrics(root, value) {
1598
- var _loop_2 = function (v) {
1599
- var metricId = v[0], source = v[1], match = v[2], scale = v[3];
1600
- if (match) {
1601
- switch (source) {
1602
- case 0 /* Text */:
1603
- root.querySelectorAll(match).forEach(function (e) { max(metricId, num$1(e.innerText, scale)); });
1604
- break;
1605
- case 2 /* Attribute */:
1606
- root.querySelectorAll("[" + match + "]").forEach(function (e) { max(metricId, num$1(e.getAttribute(match), scale, false)); });
1607
- break;
1608
- case 1 /* Javascript */:
1609
- max(metricId, evaluate(match, "number" /* Number */));
1610
- break;
1611
- }
1612
- }
1613
- };
1614
- for (var _i = 0, value_2 = value; _i < value_2.length; _i++) {
1615
- var v = value_2[_i];
1616
- _loop_2(v);
1617
- }
1618
- }
1619
- function dimensions(root, value) {
1620
- var _loop_3 = function (v) {
1621
- var dimensionId = v[0], source = v[1], match = v[2];
1622
- if (match) {
1623
- switch (source) {
1624
- case 0 /* Text */:
1625
- root.querySelectorAll(match).forEach(function (e) { log$1(dimensionId, str(e.innerText)); });
1626
- break;
1627
- case 2 /* Attribute */:
1628
- root.querySelectorAll("[" + match + "]").forEach(function (e) { log$1(dimensionId, str(e.getAttribute(match))); });
1629
- break;
1630
- case 1 /* Javascript */:
1631
- log$1(dimensionId, str(evaluate(match, "string" /* String */)));
1632
- break;
1633
- }
1634
- }
1635
- };
1636
- for (var _i = 0, value_3 = value; _i < value_3.length; _i++) {
1637
- var v = value_3[_i];
1638
- _loop_3(v);
1639
- }
1640
- }
1641
- function regex(match) {
1642
- regexCache[match] = match in regexCache ? regexCache[match] : new RegExp(match);
1643
- return regexCache[match];
1644
- }
1645
- // The function below takes in a variable name in following format: "a.b.c" and safely evaluates its value in javascript context
1646
- // For instance, for a.b.c, it will first check window["a"]. If it exists, it will recursively look at: window["a"]["b"] and finally,
1647
- // return the value for window["a"]["b"]["c"].
1648
- function evaluate(variable, type, base) {
1649
- if (type === void 0) { type = null; }
1650
- if (base === void 0) { base = window; }
1651
- var parts = variable.split("." /* Dot */);
1652
- var first = parts.shift();
1653
- if (base && base[first]) {
1654
- if (parts.length > 0) {
1655
- return evaluate(parts.join("." /* Dot */), type, base[first]);
1656
- }
1657
- var output = type === null || type === typeof base[first] ? base[first] : null;
1658
- return output;
1659
- }
1660
- return null;
1661
- }
1662
- function str(input) {
1663
- // Automatically trim string to max of Setting.DimensionLimit to avoid fetching long strings
1664
- return input ? input.substr(0, 256 /* DimensionLimit */) : input;
1665
- }
1666
- function num$1(text, scale, localize) {
1667
- if (localize === void 0) { localize = true; }
1668
- try {
1669
- scale = scale || 1;
1670
- // Reference: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat
1671
- var lang = document.documentElement.lang;
1672
- if (Intl && Intl.NumberFormat && lang && localize) {
1673
- text = text.replace(digitsWithCommaRegex, "" /* Empty */);
1674
- // Infer current group and decimal separator from current locale
1675
- var group = Intl.NumberFormat(lang).format(11111).replace(formatRegex, "" /* Empty */);
1676
- var decimal = Intl.NumberFormat(lang).format(1.1).replace(formatRegex, "" /* Empty */);
1677
- // Parse number using inferred group and decimal separators
1678
- return Math.round(parseFloat(text
1679
- .replace(new RegExp('\\' + group, 'g'), "" /* Empty */)
1680
- .replace(new RegExp('\\' + decimal), "." /* Dot */)) * scale);
1681
- }
1682
- // Fallback to en locale
1683
- return Math.round(parseFloat(text.replace(digitsRegex$1, "" /* Empty */)) * scale);
1684
- }
1685
- catch (_a) {
1686
- return null;
1687
- }
1354
+ function str(input) {
1355
+ // Automatically trim string to max of Setting.DimensionLimit to avoid fetching long strings
1356
+ return input ? input.substr(0, 256 /* DimensionLimit */) : input;
1357
+ }
1358
+ function num$2(text, scale, localize) {
1359
+ if (localize === void 0) { localize = true; }
1360
+ try {
1361
+ scale = scale || 1;
1362
+ // Reference: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat
1363
+ var lang = document.documentElement.lang;
1364
+ if (Intl && Intl.NumberFormat && lang && localize) {
1365
+ text = text.replace(digitsWithCommaRegex, "" /* Empty */);
1366
+ // Infer current group and decimal separator from current locale
1367
+ var group = Intl.NumberFormat(lang).format(11111).replace(formatRegex, "" /* Empty */);
1368
+ var decimal = Intl.NumberFormat(lang).format(1.1).replace(formatRegex, "" /* Empty */);
1369
+ // Parse number using inferred group and decimal separators
1370
+ return Math.round(parseFloat(text
1371
+ .replace(new RegExp('\\' + group, 'g'), "" /* Empty */)
1372
+ .replace(new RegExp('\\' + decimal), "." /* Dot */)) * scale);
1373
+ }
1374
+ // Fallback to en locale
1375
+ return Math.round(parseFloat(text.replace(digitsRegex$1, "" /* Empty */)) * scale);
1376
+ }
1377
+ catch (_a) {
1378
+ return null;
1379
+ }
1688
1380
  }
1689
1381
 
1690
1382
  var TAGS = ["DIV", "TR", "P", "LI", "UL", "A", "BUTTON"];
@@ -1712,12 +1404,13 @@ function selector (input, beta) {
1712
1404
  var selector = "" + prefix + input.tag + suffix;
1713
1405
  var classes = "class" /* Class */ in a && a["class" /* Class */].length > 0 ? a["class" /* Class */].trim().split(/\s+/) : null;
1714
1406
  if (beta) {
1715
- // In beta mode, update selector to use "id" field when available
1716
- // The only exception is if "id" appears to be an auto generated string token, e.g. guid or a random id
1407
+ // In beta mode, update selector to use "id" field when available. There are two exceptions:
1408
+ // (1) if "id" appears to be an auto generated string token, e.g. guid or a random id containing digits
1409
+ // (2) if "id" appears inside a shadow DOM, in which case we continue to prefix up to shadow DOM to prevent conflicts
1717
1410
  var id = "id" /* Id */ in a && a["id" /* Id */].length > 0 ? a["id" /* Id */] : null;
1718
1411
  classes = input.tag !== "BODY" /* BodyTag */ && classes ? classes.filter(function (c) { return !hasDigits(c); }) : [];
1719
1412
  selector = classes.length > 0 ? "" + prefix + input.tag + "." + classes.join(".") + suffix : selector;
1720
- selector = id && hasDigits(id) === false ? "#" + id : selector;
1413
+ selector = id && hasDigits(id) === false ? getDomPrefix(prefix) + "#" + id : selector;
1721
1414
  }
1722
1415
  else {
1723
1416
  // Otherwise, fallback to stable mode, where we include class names as part of the selector
@@ -1726,11 +1419,23 @@ function selector (input, beta) {
1726
1419
  return selector;
1727
1420
  }
1728
1421
  }
1422
+ function getDomPrefix(prefix) {
1423
+ var shadowDomStart = prefix.lastIndexOf("*S" /* ShadowDomTag */);
1424
+ var iframeDomStart = prefix.lastIndexOf("" + "iframe:" /* IFramePrefix */ + "HTML" /* HTML */);
1425
+ var domStart = Math.max(shadowDomStart, iframeDomStart);
1426
+ if (domStart < 0) {
1427
+ return "";
1428
+ }
1429
+ var domEnd = prefix.indexOf(">", domStart) + 1;
1430
+ return prefix.substr(0, domEnd);
1431
+ }
1729
1432
  // Check if the given input string has digits or not
1730
1433
  function hasDigits(value) {
1731
1434
  for (var i = 0; i < value.length; i++) {
1732
1435
  var c = value.charCodeAt(i);
1733
- return c >= 48 /* Zero */ && c <= 57 /* Nine */;
1436
+ if (c >= 48 /* Zero */ && c <= 57 /* Nine */) {
1437
+ return true;
1438
+ }
1734
1439
  }
1735
1440
  return false;
1736
1441
  }
@@ -1738,39 +1443,48 @@ function hasDigits(value) {
1738
1443
  var index = 1;
1739
1444
  // Reference: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Input#%3Cinput%3E_types
1740
1445
  var DISALLOWED_TYPES = ["password", "hidden", "email", "tel"];
1741
- var DISALLOWED_NAMES = ["addr", "cell", "code", "dob", "email", "mob", "name", "phone", "secret", "social", "ssn", "tel", "zip", "pass"];
1446
+ var DISALLOWED_NAMES = ["addr", "cell", "code", "dob", "email", "mob", "name", "phone", "secret", "social", "ssn", "tel", "zip", "pass", "card", "account", "cvv", "ccv"];
1742
1447
  var DISALLOWED_MATCH = ["address", "password", "contact"];
1743
1448
  var nodes = [];
1744
1449
  var values = [];
1745
1450
  var updateMap = [];
1746
1451
  var hashMap = {};
1452
+ var override = [];
1453
+ var unmask = [];
1747
1454
  // The WeakMap object is a collection of key/value pairs in which the keys are weakly referenced
1748
1455
  var idMap = null; // Maps node => id.
1749
1456
  var iframeMap = null; // Maps iframe's contentDocument => parent iframe element
1750
1457
  var privacyMap = null; // Maps node => Privacy (enum)
1751
- function start$o() {
1752
- reset$f();
1753
- parse(document);
1458
+ function start$r() {
1459
+ reset$g();
1460
+ parse(document, true);
1754
1461
  }
1755
- function stop$n() {
1756
- reset$f();
1462
+ function stop$q() {
1463
+ reset$g();
1757
1464
  }
1758
- function reset$f() {
1465
+ function reset$g() {
1759
1466
  index = 1;
1760
1467
  nodes = [];
1761
1468
  values = [];
1762
1469
  updateMap = [];
1763
1470
  hashMap = {};
1471
+ override = [];
1472
+ unmask = [];
1764
1473
  idMap = new WeakMap();
1765
1474
  iframeMap = new WeakMap();
1766
1475
  privacyMap = new WeakMap();
1767
1476
  }
1768
1477
  // We parse new root nodes for any regions or masked nodes in the beginning (document) and
1769
1478
  // later whenever there are new additions or modifications to DOM (mutations)
1770
- function parse(root) {
1479
+ function parse(root, init) {
1480
+ if (init === void 0) { init = false; }
1771
1481
  // Wrap selectors in a try / catch block.
1772
1482
  // It's possible for script to receive invalid selectors, e.g. "'#id'" with extra quotes, and cause the code below to fail
1773
1483
  try {
1484
+ // Parse unmask configuration into separate query selectors and override tokens as part of initialization
1485
+ if (init) {
1486
+ config$1.unmask.forEach(function (x) { return x.indexOf("!" /* Bang */) < 0 ? unmask.push(x) : override.push(x.substr(1)); });
1487
+ }
1774
1488
  // Since mutations may happen on leaf nodes too, e.g. text nodes, which may not support all selector APIs.
1775
1489
  // We ensure that the root note supports querySelectorAll API before executing the code below to identify new regions.
1776
1490
  if ("querySelectorAll" in root) {
@@ -1778,11 +1492,11 @@ function parse(root) {
1778
1492
  metrics(root, config$1.metrics);
1779
1493
  dimensions(root, config$1.dimensions);
1780
1494
  config$1.mask.forEach(function (x) { return root.querySelectorAll(x).forEach(function (e) { return privacyMap.set(e, 3 /* TextImage */); }); }); // Masked Elements
1781
- config$1.unmask.forEach(function (x) { return root.querySelectorAll(x).forEach(function (e) { return privacyMap.set(e, 0 /* None */); }); }); // Unmasked Elements
1495
+ unmask.forEach(function (x) { return root.querySelectorAll(x).forEach(function (e) { return privacyMap.set(e, 0 /* None */); }); }); // Unmasked Elements
1782
1496
  }
1783
1497
  }
1784
1498
  catch (e) {
1785
- log(5 /* Selector */, 1 /* Warning */, e ? e.name : null);
1499
+ log$1(5 /* Selector */, 1 /* Warning */, e ? e.name : null);
1786
1500
  }
1787
1501
  }
1788
1502
  function getId(node, autogen) {
@@ -1803,17 +1517,15 @@ function add(node, parent, data, source) {
1803
1517
  var previousId = getPreviousId(node);
1804
1518
  var privacy = config$1.content ? 1 /* Sensitive */ : 2 /* Text */;
1805
1519
  var parentValue = null;
1806
- var parentTag = "" /* Empty */;
1807
1520
  var regionId = exists(node) ? id : null;
1808
1521
  if (parentId >= 0 && values[parentId]) {
1809
1522
  parentValue = values[parentId];
1810
- parentTag = parentValue.data.tag;
1811
1523
  parentValue.children.push(id);
1812
1524
  regionId = regionId === null ? parentValue.region : regionId;
1813
1525
  privacy = parentValue.metadata.privacy;
1814
1526
  }
1815
1527
  // Check to see if this particular node should be masked or not
1816
- privacy = getPrivacy(node, data, parentTag, privacy);
1528
+ privacy = getPrivacy(node, data, parentValue, privacy);
1817
1529
  // If there's an explicit region attribute set on the element, use it to mark a region on the page
1818
1530
  if (data.attributes && "data-clarity-region" /* RegionData */ in data.attributes) {
1819
1531
  observe$b(node, data.attributes["data-clarity-region" /* RegionData */]);
@@ -1833,7 +1545,7 @@ function add(node, parent, data, source) {
1833
1545
  };
1834
1546
  updateSelector(values[id]);
1835
1547
  size(values[id], parentValue);
1836
- track$4(id, source);
1548
+ track$5(id, source);
1837
1549
  }
1838
1550
  function update(node, parent, data, source) {
1839
1551
  var id = getId(node);
@@ -1883,7 +1595,7 @@ function update(node, parent, data, source) {
1883
1595
  }
1884
1596
  // Update selector
1885
1597
  updateSelector(value);
1886
- track$4(id, source, changed, parentChanged);
1598
+ track$5(id, source, changed, parentChanged);
1887
1599
  }
1888
1600
  }
1889
1601
  function sameorigin(node) {
@@ -1908,21 +1620,35 @@ function iframe(node) {
1908
1620
  var doc = node.nodeType === Node.DOCUMENT_NODE ? node : null;
1909
1621
  return doc && iframeMap.has(doc) ? iframeMap.get(doc) : null;
1910
1622
  }
1911
- function getPrivacy(node, data, parentTag, privacy) {
1623
+ function getPrivacy(node, data, parent, privacy) {
1912
1624
  var attributes = data.attributes;
1913
1625
  var tag = data.tag.toUpperCase();
1914
1626
  // If this node was explicitly configured to contain sensitive content, use that information and return the value
1915
1627
  if (privacyMap.has(node)) {
1916
1628
  return privacyMap.get(node);
1917
1629
  }
1630
+ // If it's a text node belonging to a STYLE or TITLE tag;
1631
+ // Or, the text node belongs to one of SCRUB_EXCEPTIONS
1632
+ // then reset the privacy setting to ensure we capture the content
1633
+ if (tag === "*T" /* TextTag */ && parent && parent.data) {
1634
+ var path = parent.selector ? parent.selector[0 /* Stable */] : "" /* Empty */;
1635
+ privacy = parent.data.tag === "STYLE" /* StyleTag */ || parent.data.tag === "TITLE" /* TitleTag */ ? 0 /* None */ : privacy;
1636
+ for (var _i = 0, override_1 = override; _i < override_1.length; _i++) {
1637
+ var entry = override_1[_i];
1638
+ if (path.indexOf(entry) >= 0) {
1639
+ privacy = 0 /* None */;
1640
+ break;
1641
+ }
1642
+ }
1643
+ }
1918
1644
  // Do not proceed if attributes are missing for the node
1919
1645
  if (attributes === null || attributes === undefined) {
1920
1646
  return privacy;
1921
1647
  }
1922
1648
  // Look up for sensitive fields
1923
1649
  if ("class" /* Class */ in attributes && privacy === 1 /* Sensitive */) {
1924
- for (var _i = 0, DISALLOWED_MATCH_1 = DISALLOWED_MATCH; _i < DISALLOWED_MATCH_1.length; _i++) {
1925
- var match = DISALLOWED_MATCH_1[_i];
1650
+ for (var _a = 0, DISALLOWED_MATCH_1 = DISALLOWED_MATCH; _a < DISALLOWED_MATCH_1.length; _a++) {
1651
+ var match = DISALLOWED_MATCH_1[_a];
1926
1652
  if (attributes["class" /* Class */].indexOf(match) >= 0) {
1927
1653
  privacy = 2 /* Text */;
1928
1654
  break;
@@ -1934,12 +1660,12 @@ function getPrivacy(node, data, parentTag, privacy) {
1934
1660
  if (privacy === 0 /* None */) {
1935
1661
  var field = "" /* Empty */;
1936
1662
  // Be aggressive in looking up any attribute (id, class, name, etc.) for disallowed names
1937
- for (var _a = 0, _b = Object.keys(attributes); _a < _b.length; _a++) {
1938
- var attribute = _b[_a];
1663
+ for (var _b = 0, _c = Object.keys(attributes); _b < _c.length; _b++) {
1664
+ var attribute = _c[_b];
1939
1665
  field += attributes[attribute].toLowerCase();
1940
1666
  }
1941
- for (var _c = 0, DISALLOWED_NAMES_1 = DISALLOWED_NAMES; _c < DISALLOWED_NAMES_1.length; _c++) {
1942
- var name_1 = DISALLOWED_NAMES_1[_c];
1667
+ for (var _d = 0, DISALLOWED_NAMES_1 = DISALLOWED_NAMES; _d < DISALLOWED_NAMES_1.length; _d++) {
1668
+ var name_1 = DISALLOWED_NAMES_1[_d];
1943
1669
  if (field.indexOf(name_1) >= 0) {
1944
1670
  privacy = 2 /* Text */;
1945
1671
  break;
@@ -1962,11 +1688,6 @@ function getPrivacy(node, data, parentTag, privacy) {
1962
1688
  if ("data-clarity-unmask" /* UnmaskData */ in attributes) {
1963
1689
  privacy = 0 /* None */;
1964
1690
  }
1965
- // If it's a text node belonging to a STYLE or TITLE tag; then reset the privacy setting to ensure we capture the content
1966
- var cTag = tag === "*T" /* TextTag */ ? parentTag : tag;
1967
- if (cTag === "STYLE" /* StyleTag */ || cTag === "TITLE" /* TitleTag */) {
1968
- privacy = 0 /* None */;
1969
- }
1970
1691
  return privacy;
1971
1692
  }
1972
1693
  function diff(a, b, field) {
@@ -2045,7 +1766,7 @@ function remove(id, source) {
2045
1766
  var value = values[id];
2046
1767
  value.metadata.active = false;
2047
1768
  value.parent = null;
2048
- track$4(id, source);
1769
+ track$5(id, source);
2049
1770
  }
2050
1771
  }
2051
1772
  function size(value, parent) {
@@ -2072,7 +1793,7 @@ function getPreviousId(node) {
2072
1793
  }
2073
1794
  return id;
2074
1795
  }
2075
- function track$4(id, source, changed, parentChanged) {
1796
+ function track$5(id, source, changed, parentChanged) {
2076
1797
  if (changed === void 0) { changed = true; }
2077
1798
  if (parentChanged === void 0) { parentChanged = false; }
2078
1799
  // Keep track of the order in which mutations happened, they may not be sequential
@@ -2090,8 +1811,8 @@ function track$4(id, source, changed, parentChanged) {
2090
1811
 
2091
1812
  var dom = /*#__PURE__*/Object.freeze({
2092
1813
  __proto__: null,
2093
- start: start$o,
2094
- stop: stop$n,
1814
+ start: start$r,
1815
+ stop: stop$q,
2095
1816
  parse: parse,
2096
1817
  getId: getId,
2097
1818
  add: add,
@@ -2112,8 +1833,8 @@ var regions = {};
2112
1833
  var queue$2 = [];
2113
1834
  var watch = false;
2114
1835
  var observer$1 = null;
2115
- function start$n() {
2116
- reset$e();
1836
+ function start$q() {
1837
+ reset$f();
2117
1838
  observer$1 = null;
2118
1839
  regionMap = new WeakMap();
2119
1840
  regions = {};
@@ -2141,7 +1862,7 @@ function exists(node) {
2141
1862
  // and still attempt to call exists on a late coming DOM mutation (or addition), effectively causing a script error
2142
1863
  return regionMap && regionMap.has(node);
2143
1864
  }
2144
- function track$3(id, event) {
1865
+ function track$4(id, event) {
2145
1866
  var node = getNode(id);
2146
1867
  var data = id in regions ? regions[id] : { id: id, visibility: 0 /* Rendered */, interaction: 16 /* None */, name: regionMap.get(node) };
2147
1868
  // Determine the interaction state based on incoming event
@@ -2157,7 +1878,7 @@ function track$3(id, event) {
2157
1878
  // Process updates to this region, if applicable
2158
1879
  process$6(node, data, interaction, data.visibility);
2159
1880
  }
2160
- function compute$4() {
1881
+ function compute$5() {
2161
1882
  // Process any regions where we couldn't resolve an "id" for at the time of last intersection observer event
2162
1883
  // This could happen in cases where elements are not yet processed by Clarity's virtual DOM but browser reports a change, regardless.
2163
1884
  // For those cases we add them to the queue and re-process them below
@@ -2238,11 +1959,11 @@ function process$6(n, d, s, v) {
2238
1959
  function clone(r) {
2239
1960
  return { time: time(), data: { id: r.id, interaction: r.interaction, visibility: r.visibility, name: r.name } };
2240
1961
  }
2241
- function reset$e() {
1962
+ function reset$f() {
2242
1963
  state$7 = [];
2243
1964
  }
2244
- function stop$m() {
2245
- reset$e();
1965
+ function stop$p() {
1966
+ reset$f();
2246
1967
  regionMap = null;
2247
1968
  regions = {};
2248
1969
  queue$2 = [];
@@ -2271,8 +1992,8 @@ function offset (element) {
2271
1992
 
2272
1993
  var UserInputTags = ["input", "textarea", "radio", "button", "canvas"];
2273
1994
  var state$6 = [];
2274
- function start$m() {
2275
- reset$d();
1995
+ function start$p() {
1996
+ reset$e();
2276
1997
  }
2277
1998
  function observe$a(root) {
2278
1999
  bind(root, "click", handler$1.bind(this, 9 /* Click */, root), true);
@@ -2379,16 +2100,16 @@ function context(a) {
2379
2100
  }
2380
2101
  return 0 /* Self */;
2381
2102
  }
2382
- function reset$d() {
2103
+ function reset$e() {
2383
2104
  state$6 = [];
2384
2105
  }
2385
- function stop$l() {
2386
- reset$d();
2106
+ function stop$o() {
2107
+ reset$e();
2387
2108
  }
2388
2109
 
2389
2110
  var state$5 = [];
2390
- function start$l() {
2391
- reset$c();
2111
+ function start$o() {
2112
+ reset$d();
2392
2113
  }
2393
2114
  function observe$9(root) {
2394
2115
  bind(root, "cut", recompute$7.bind(this, 0 /* Cut */), true);
@@ -2399,17 +2120,17 @@ function recompute$7(action, evt) {
2399
2120
  state$5.push({ time: time(), event: 38 /* Clipboard */, data: { target: target(evt), action: action } });
2400
2121
  schedule$1(encode$2.bind(this, 38 /* Clipboard */));
2401
2122
  }
2402
- function reset$c() {
2123
+ function reset$d() {
2403
2124
  state$5 = [];
2404
2125
  }
2405
- function stop$k() {
2406
- reset$c();
2126
+ function stop$n() {
2127
+ reset$d();
2407
2128
  }
2408
2129
 
2409
2130
  var timeout$5 = null;
2410
2131
  var state$4 = [];
2411
- function start$k() {
2412
- reset$b();
2132
+ function start$n() {
2133
+ reset$c();
2413
2134
  }
2414
2135
  function observe$8(root) {
2415
2136
  bind(root, "input", recompute$6, true);
@@ -2444,18 +2165,18 @@ function recompute$6(evt) {
2444
2165
  function process$5(event) {
2445
2166
  schedule$1(encode$2.bind(this, event));
2446
2167
  }
2447
- function reset$b() {
2168
+ function reset$c() {
2448
2169
  state$4 = [];
2449
2170
  }
2450
- function stop$j() {
2171
+ function stop$m() {
2451
2172
  clearTimeout(timeout$5);
2452
- reset$b();
2173
+ reset$c();
2453
2174
  }
2454
2175
 
2455
2176
  var state$3 = [];
2456
2177
  var timeout$4 = null;
2457
- function start$j() {
2458
- reset$a();
2178
+ function start$m() {
2179
+ reset$b();
2459
2180
  }
2460
2181
  function observe$7(root) {
2461
2182
  bind(root, "mousedown", mouse.bind(this, 13 /* MouseDown */, root), true);
@@ -2526,7 +2247,7 @@ function handler(current) {
2526
2247
  function process$4(event) {
2527
2248
  schedule$1(encode$2.bind(this, event));
2528
2249
  }
2529
- function reset$a() {
2250
+ function reset$b() {
2530
2251
  state$3 = [];
2531
2252
  }
2532
2253
  function similar$1(last, current) {
@@ -2537,7 +2258,7 @@ function similar$1(last, current) {
2537
2258
  var match = current.data.target === last.data.target;
2538
2259
  return current.event === last.event && match && distance < 20 /* Distance */ && gap < 25 /* Interval */;
2539
2260
  }
2540
- function stop$i() {
2261
+ function stop$l() {
2541
2262
  clearTimeout(timeout$4);
2542
2263
  // Send out any pending pointer events in the pipeline
2543
2264
  if (state$3.length > 0) {
@@ -2545,8 +2266,8 @@ function stop$i() {
2545
2266
  }
2546
2267
  }
2547
2268
 
2548
- var data$5;
2549
- function start$i() {
2269
+ var data$8;
2270
+ function start$l() {
2550
2271
  bind(window, "resize", recompute$5);
2551
2272
  recompute$5();
2552
2273
  }
@@ -2554,22 +2275,22 @@ function recompute$5() {
2554
2275
  var de = document.documentElement;
2555
2276
  // window.innerWidth includes width of the scrollbar and is not a true representation of the viewport width.
2556
2277
  // Therefore, when possible, use documentElement's clientWidth property.
2557
- data$5 = {
2278
+ data$8 = {
2558
2279
  width: de && "clientWidth" in de ? Math.min(de.clientWidth, window.innerWidth) : window.innerWidth,
2559
2280
  height: de && "clientHeight" in de ? Math.min(de.clientHeight, window.innerHeight) : window.innerHeight,
2560
2281
  };
2561
2282
  encode$2(11 /* Resize */);
2562
2283
  }
2563
- function reset$9() {
2564
- data$5 = null;
2284
+ function reset$a() {
2285
+ data$8 = null;
2565
2286
  }
2566
- function stop$h() {
2567
- reset$9();
2287
+ function stop$k() {
2288
+ reset$a();
2568
2289
  }
2569
2290
 
2570
2291
  var state$2 = [];
2571
2292
  var timeout$3 = null;
2572
- function start$h() {
2293
+ function start$k() {
2573
2294
  state$2 = [];
2574
2295
  recompute$4();
2575
2296
  }
@@ -2608,7 +2329,7 @@ function recompute$4(event) {
2608
2329
  clearTimeout(timeout$3);
2609
2330
  timeout$3 = setTimeout(process$3, 500 /* LookAhead */, 10 /* Scroll */);
2610
2331
  }
2611
- function reset$8() {
2332
+ function reset$9() {
2612
2333
  state$2 = [];
2613
2334
  }
2614
2335
  function process$3(event) {
@@ -2619,16 +2340,16 @@ function similar(last, current) {
2619
2340
  var dy = last.data.y - current.data.y;
2620
2341
  return (dx * dx + dy * dy < 20 /* Distance */ * 20 /* Distance */) && (current.time - last.time < 25 /* Interval */);
2621
2342
  }
2622
- function stop$g() {
2343
+ function stop$j() {
2623
2344
  clearTimeout(timeout$3);
2624
2345
  state$2 = [];
2625
2346
  }
2626
2347
 
2627
- var data$4 = null;
2348
+ var data$7 = null;
2628
2349
  var previous = null;
2629
2350
  var timeout$2 = null;
2630
- function start$g() {
2631
- reset$7();
2351
+ function start$j() {
2352
+ reset$8();
2632
2353
  }
2633
2354
  function observe$5(root) {
2634
2355
  bind(root, "selectstart", recompute$3.bind(this, root), true);
@@ -2649,12 +2370,12 @@ function recompute$3(root) {
2649
2370
  (current.anchorNode === current.focusNode && current.anchorOffset === current.focusOffset)) {
2650
2371
  return;
2651
2372
  }
2652
- var startNode = data$4.start ? data$4.start : null;
2653
- if (previous !== null && data$4.start !== null && startNode !== current.anchorNode) {
2373
+ var startNode = data$7.start ? data$7.start : null;
2374
+ if (previous !== null && data$7.start !== null && startNode !== current.anchorNode) {
2654
2375
  clearTimeout(timeout$2);
2655
2376
  process$2(21 /* Selection */);
2656
2377
  }
2657
- data$4 = {
2378
+ data$7 = {
2658
2379
  start: current.anchorNode,
2659
2380
  startOffset: current.anchorOffset,
2660
2381
  end: current.focusNode,
@@ -2667,18 +2388,18 @@ function recompute$3(root) {
2667
2388
  function process$2(event) {
2668
2389
  schedule$1(encode$2.bind(this, event));
2669
2390
  }
2670
- function reset$7() {
2391
+ function reset$8() {
2671
2392
  previous = null;
2672
- data$4 = { start: 0, startOffset: 0, end: 0, endOffset: 0 };
2393
+ data$7 = { start: 0, startOffset: 0, end: 0, endOffset: 0 };
2673
2394
  }
2674
- function stop$f() {
2675
- reset$7();
2395
+ function stop$i() {
2396
+ reset$8();
2676
2397
  clearTimeout(timeout$2);
2677
2398
  }
2678
2399
 
2679
2400
  var state$1 = [];
2680
- function start$f() {
2681
- reset$6();
2401
+ function start$i() {
2402
+ reset$7();
2682
2403
  }
2683
2404
  function observe$4(root) {
2684
2405
  bind(root, "submit", recompute$2, true);
@@ -2687,70 +2408,70 @@ function recompute$2(evt) {
2687
2408
  state$1.push({ time: time(), event: 39 /* Submit */, data: { target: target(evt) } });
2688
2409
  schedule$1(encode$2.bind(this, 39 /* Submit */));
2689
2410
  }
2690
- function reset$6() {
2411
+ function reset$7() {
2691
2412
  state$1 = [];
2692
2413
  }
2693
- function stop$e() {
2694
- reset$6();
2414
+ function stop$h() {
2415
+ reset$7();
2695
2416
  }
2696
2417
 
2697
- var data$3;
2698
- function start$e() {
2418
+ var data$6;
2419
+ function start$h() {
2699
2420
  bind(window, "pagehide", recompute$1);
2700
2421
  }
2701
2422
  function recompute$1(evt) {
2702
- data$3 = { name: evt.type };
2423
+ data$6 = { name: evt.type };
2703
2424
  encode$2(26 /* Unload */);
2704
2425
  stop();
2705
2426
  }
2706
- function reset$5() {
2707
- data$3 = null;
2427
+ function reset$6() {
2428
+ data$6 = null;
2708
2429
  }
2709
- function stop$d() {
2710
- reset$5();
2430
+ function stop$g() {
2431
+ reset$6();
2711
2432
  }
2712
2433
 
2713
- var data$2;
2714
- function start$d() {
2434
+ var data$5;
2435
+ function start$g() {
2715
2436
  bind(document, "visibilitychange", recompute);
2716
2437
  recompute();
2717
2438
  }
2718
2439
  function recompute() {
2719
- data$2 = { visible: "visibilityState" in document ? document.visibilityState : "default" };
2440
+ data$5 = { visible: "visibilityState" in document ? document.visibilityState : "default" };
2720
2441
  encode$2(28 /* Visibility */);
2721
2442
  }
2722
- function reset$4() {
2723
- data$2 = null;
2443
+ function reset$5() {
2444
+ data$5 = null;
2724
2445
  }
2725
- function stop$c() {
2726
- reset$4();
2446
+ function stop$f() {
2447
+ reset$5();
2727
2448
  }
2728
2449
 
2729
- function start$c() {
2730
- start$a();
2450
+ function start$f() {
2451
+ start$d();
2452
+ start$p();
2453
+ start$o();
2731
2454
  start$m();
2455
+ start$n();
2732
2456
  start$l();
2733
- start$j();
2457
+ start$g();
2734
2458
  start$k();
2459
+ start$j();
2735
2460
  start$i();
2736
- start$d();
2737
2461
  start$h();
2738
- start$g();
2739
- start$f();
2740
- start$e();
2741
2462
  }
2742
- function stop$b() {
2743
- stop$9();
2463
+ function stop$e() {
2464
+ stop$c();
2465
+ stop$o();
2466
+ stop$n();
2744
2467
  stop$l();
2468
+ stop$m();
2745
2469
  stop$k();
2746
- stop$i();
2470
+ stop$f();
2747
2471
  stop$j();
2472
+ stop$i();
2748
2473
  stop$h();
2749
- stop$c();
2750
2474
  stop$g();
2751
- stop$f();
2752
- stop$e();
2753
- stop$d();
2754
2475
  }
2755
2476
  function observe$3(root) {
2756
2477
  observe$6(root);
@@ -2768,8 +2489,8 @@ function observe$3(root) {
2768
2489
 
2769
2490
  var interaction = /*#__PURE__*/Object.freeze({
2770
2491
  __proto__: null,
2771
- start: start$c,
2772
- stop: stop$b,
2492
+ start: start$f,
2493
+ stop: stop$e,
2773
2494
  observe: observe$3
2774
2495
  });
2775
2496
 
@@ -2786,39 +2507,39 @@ function ld(json) {
2786
2507
  switch (value) {
2787
2508
  case "article" /* Article */:
2788
2509
  case "recipe" /* Recipe */:
2789
- log$1(5 /* SchemaType */, json[key]);
2790
- log$1(8 /* AuthorName */, json["creator" /* Creator */]);
2791
- log$1(18 /* Headline */, json["headline" /* Headline */]);
2510
+ log(5 /* SchemaType */, json[key]);
2511
+ log(8 /* AuthorName */, json["creator" /* Creator */]);
2512
+ log(18 /* Headline */, json["headline" /* Headline */]);
2792
2513
  break;
2793
2514
  case "product" /* Product */:
2794
- log$1(5 /* SchemaType */, json[key]);
2795
- log$1(10 /* ProductName */, json["name" /* Name */]);
2796
- log$1(12 /* ProductSku */, json["sku" /* Sku */]);
2515
+ log(5 /* SchemaType */, json[key]);
2516
+ log(10 /* ProductName */, json["name" /* Name */]);
2517
+ log(12 /* ProductSku */, json["sku" /* Sku */]);
2797
2518
  if (json["brand" /* Brand */]) {
2798
- log$1(6 /* ProductBrand */, json["brand" /* Brand */]["name" /* Name */]);
2519
+ log(6 /* ProductBrand */, json["brand" /* Brand */]["name" /* Name */]);
2799
2520
  }
2800
2521
  break;
2801
2522
  case "aggregaterating" /* AggregateRating */:
2802
2523
  if (json["ratingValue" /* RatingValue */]) {
2803
- max(11 /* RatingValue */, num(json["ratingValue" /* RatingValue */], 100 /* RatingScale */));
2804
- max(18 /* BestRating */, num(json["bestRating" /* BestRating */]));
2805
- max(19 /* WorstRating */, num(json["worstRating" /* WorstRating */]));
2524
+ max(11 /* RatingValue */, num$1(json["ratingValue" /* RatingValue */], 100 /* RatingScale */));
2525
+ max(18 /* BestRating */, num$1(json["bestRating" /* BestRating */]));
2526
+ max(19 /* WorstRating */, num$1(json["worstRating" /* WorstRating */]));
2806
2527
  }
2807
- max(12 /* RatingCount */, num(json["ratingCount" /* RatingCount */]));
2808
- max(17 /* ReviewCount */, num(json["reviewCount" /* ReviewCount */]));
2528
+ max(12 /* RatingCount */, num$1(json["ratingCount" /* RatingCount */]));
2529
+ max(17 /* ReviewCount */, num$1(json["reviewCount" /* ReviewCount */]));
2809
2530
  break;
2810
2531
  case "person" /* Author */:
2811
- log$1(8 /* AuthorName */, json["name" /* Name */]);
2532
+ log(8 /* AuthorName */, json["name" /* Name */]);
2812
2533
  break;
2813
2534
  case "offer" /* Offer */:
2814
- log$1(7 /* ProductAvailability */, json["availability" /* Availability */]);
2815
- log$1(14 /* ProductCondition */, json["itemCondition" /* ItemCondition */]);
2816
- log$1(13 /* ProductCurrency */, json["priceCurrency" /* PriceCurrency */]);
2817
- log$1(12 /* ProductSku */, json["sku" /* Sku */]);
2818
- max(13 /* ProductPrice */, num(json["price" /* Price */]));
2535
+ log(7 /* ProductAvailability */, json["availability" /* Availability */]);
2536
+ log(14 /* ProductCondition */, json["itemCondition" /* ItemCondition */]);
2537
+ log(13 /* ProductCurrency */, json["priceCurrency" /* PriceCurrency */]);
2538
+ log(12 /* ProductSku */, json["sku" /* Sku */]);
2539
+ max(13 /* ProductPrice */, num$1(json["price" /* Price */]));
2819
2540
  break;
2820
2541
  case "brand" /* Brand */:
2821
- log$1(6 /* ProductBrand */, json["name" /* Name */]);
2542
+ log(6 /* ProductBrand */, json["name" /* Name */]);
2822
2543
  break;
2823
2544
  }
2824
2545
  }
@@ -2828,7 +2549,7 @@ function ld(json) {
2828
2549
  }
2829
2550
  }
2830
2551
  }
2831
- function num(input, scale) {
2552
+ function num$1(input, scale) {
2832
2553
  if (scale === void 0) { scale = 1; }
2833
2554
  if (input !== null) {
2834
2555
  switch (typeof input) {
@@ -2877,6 +2598,7 @@ function processNode (node, source) {
2877
2598
  case Node.DOCUMENT_FRAGMENT_NODE:
2878
2599
  var shadowRoot = node;
2879
2600
  if (shadowRoot.host) {
2601
+ parse(shadowRoot);
2880
2602
  var type = typeof (shadowRoot.constructor);
2881
2603
  if (type === "function" /* Function */ && shadowRoot.constructor.toString().indexOf("[native code]" /* NativeCode */) >= 0) {
2882
2604
  observe$2(shadowRoot);
@@ -2950,13 +2672,13 @@ function processNode (node, source) {
2950
2672
  var content = attributes["content" /* Content */];
2951
2673
  switch (attributes[key]) {
2952
2674
  case "og:title" /* ogTitle */:
2953
- log$1(20 /* MetaTitle */, content);
2675
+ log(20 /* MetaTitle */, content);
2954
2676
  break;
2955
2677
  case "og:type" /* ogType */:
2956
- log$1(19 /* MetaType */, content);
2678
+ log(19 /* MetaType */, content);
2957
2679
  break;
2958
2680
  case "generator" /* Generator */:
2959
- log$1(21 /* Generator */, content);
2681
+ log(21 /* Generator */, content);
2960
2682
  break;
2961
2683
  }
2962
2684
  }
@@ -3021,7 +2743,7 @@ function getCssRules(sheet) {
3021
2743
  cssRules = sheet ? sheet.cssRules : [];
3022
2744
  }
3023
2745
  catch (e) {
3024
- log(1 /* CssRules */, 1 /* Warning */, e ? e.name : null);
2746
+ log$1(1 /* CssRules */, 1 /* Warning */, e ? e.name : null);
3025
2747
  if (e && e.name !== "SecurityError") {
3026
2748
  throw e;
3027
2749
  }
@@ -3096,13 +2818,13 @@ var attachShadow = null;
3096
2818
  var queue$1 = [];
3097
2819
  var timeout$1 = null;
3098
2820
  var activePeriod = null;
3099
- var history$1 = {};
3100
- function start$b() {
2821
+ var history$2 = {};
2822
+ function start$e() {
3101
2823
  observers = [];
3102
2824
  queue$1 = [];
3103
2825
  timeout$1 = null;
3104
2826
  activePeriod = 0;
3105
- history$1 = {};
2827
+ history$2 = {};
3106
2828
  if (insertRule === null) {
3107
2829
  insertRule = CSSStyleSheet.prototype.insertRule;
3108
2830
  }
@@ -3110,7 +2832,7 @@ function start$b() {
3110
2832
  deleteRule = CSSStyleSheet.prototype.deleteRule;
3111
2833
  }
3112
2834
  if (attachShadow === null) {
3113
- attachShadow = HTMLElement.prototype.attachShadow;
2835
+ attachShadow = Element.prototype.attachShadow;
3114
2836
  }
3115
2837
  // Some popular open source libraries, like styled-components, optimize performance
3116
2838
  // by injecting CSS using insertRule API vs. appending text node. A side effect of
@@ -3128,7 +2850,7 @@ function start$b() {
3128
2850
  // In case we are unable to add a hook and browser throws an exception,
3129
2851
  // reset attachShadow variable and resume processing like before
3130
2852
  try {
3131
- HTMLElement.prototype.attachShadow = function () {
2853
+ Element.prototype.attachShadow = function () {
3132
2854
  return schedule(attachShadow.apply(this, arguments));
3133
2855
  };
3134
2856
  }
@@ -3153,7 +2875,7 @@ function observe$1(node) {
3153
2875
  }
3154
2876
  }
3155
2877
  catch (e) {
3156
- log(2 /* MutationObserver */, 0 /* Info */, e ? e.name : null);
2878
+ log$1(2 /* MutationObserver */, 0 /* Info */, e ? e.name : null);
3157
2879
  }
3158
2880
  }
3159
2881
  function monitor(frame) {
@@ -3164,7 +2886,7 @@ function monitor(frame) {
3164
2886
  bind(frame, "load" /* LoadEvent */, generate.bind(this, frame, "childList" /* ChildList */), true);
3165
2887
  }
3166
2888
  }
3167
- function stop$a() {
2889
+ function stop$d() {
3168
2890
  for (var _i = 0, observers_1 = observers; _i < observers_1.length; _i++) {
3169
2891
  var observer = observers_1[_i];
3170
2892
  if (observer) {
@@ -3184,10 +2906,10 @@ function stop$a() {
3184
2906
  }
3185
2907
  // Restoring original attachShadow
3186
2908
  if (attachShadow != null) {
3187
- HTMLElement.prototype.attachShadow = attachShadow;
2909
+ Element.prototype.attachShadow = attachShadow;
3188
2910
  attachShadow = null;
3189
2911
  }
3190
- history$1 = {};
2912
+ history$2 = {};
3191
2913
  mutations = [];
3192
2914
  queue$1 = [];
3193
2915
  activePeriod = 0;
@@ -3199,11 +2921,11 @@ function active$2() {
3199
2921
  function handle$1(m) {
3200
2922
  // Queue up mutation records for asynchronous processing
3201
2923
  var now = time();
3202
- track$5(6 /* Mutation */, now);
2924
+ track$6(6 /* Mutation */, now);
3203
2925
  mutations.push({ time: now, mutations: m });
3204
2926
  schedule$1(process$1, 1 /* High */).then(function () {
3205
- measure(compute$6)();
3206
- measure(compute$4)();
2927
+ measure(compute$7)();
2928
+ measure(compute$5)();
3207
2929
  });
3208
2930
  }
3209
2931
  function process$1() {
@@ -3213,7 +2935,7 @@ function process$1() {
3213
2935
  switch (_b.label) {
3214
2936
  case 0:
3215
2937
  timer = { id: id(), cost: 3 /* LayoutCost */ };
3216
- start$t(timer);
2938
+ start$w(timer);
3217
2939
  _b.label = 1;
3218
2940
  case 1:
3219
2941
  if (!(mutations.length > 0)) return [3 /*break*/, 8];
@@ -3234,10 +2956,13 @@ function process$1() {
3234
2956
  return [3 /*break*/, 6];
3235
2957
  }
3236
2958
  target = mutation.target;
3237
- type = track$2(mutation, timer);
2959
+ type = track$3(mutation, timer);
3238
2960
  if (type && target && target.ownerDocument) {
3239
2961
  parse(target.ownerDocument);
3240
2962
  }
2963
+ if (type && target && target.nodeType == Node.DOCUMENT_FRAGMENT_NODE && target.host) {
2964
+ parse(target);
2965
+ }
3241
2966
  switch (type) {
3242
2967
  case "attributes" /* Attributes */:
3243
2968
  processNode(target, 3 /* Attributes */);
@@ -3265,13 +2990,13 @@ function process$1() {
3265
2990
  _b.sent();
3266
2991
  return [3 /*break*/, 1];
3267
2992
  case 8:
3268
- stop$q(timer);
2993
+ stop$t(timer);
3269
2994
  return [2 /*return*/];
3270
2995
  }
3271
2996
  });
3272
2997
  });
3273
2998
  }
3274
- function track$2(m, timer) {
2999
+ function track$3(m, timer) {
3275
3000
  var value = m.target ? get(m.target.parentNode) : null;
3276
3001
  // Check if the parent is already discovered and that the parent is not the document root
3277
3002
  if (value && value.data.tag !== "HTML" /* HTML */) {
@@ -3284,8 +3009,8 @@ function track$2(m, timer) {
3284
3009
  // In those cases, IDs will change however the selector (which is relative to DOM xPath) remains the same
3285
3010
  var key = [parent_1, element, m.attributeName, names(m.addedNodes), names(m.removedNodes)].join();
3286
3011
  // Initialize an entry if it doesn't already exist
3287
- history$1[key] = key in history$1 ? history$1[key] : [0];
3288
- var h = history$1[key];
3012
+ history$2[key] = key in history$2 ? history$2[key] : [0];
3013
+ var h = history$2[key];
3289
3014
  // Lookup any pending nodes queued up for removal, and process them now if we suspended a mutation before
3290
3015
  if (inactive === false && h[0] >= 10 /* MutationSuspendThreshold */) {
3291
3016
  processNodeList(h[1], 2 /* ChildListRemove */, timer);
@@ -3358,10 +3083,10 @@ function schedule(node) {
3358
3083
  if (timeout$1) {
3359
3084
  clearTimeout(timeout$1);
3360
3085
  }
3361
- timeout$1 = setTimeout(trigger, 33 /* LookAhead */);
3086
+ timeout$1 = setTimeout(trigger$1, 33 /* LookAhead */);
3362
3087
  return node;
3363
3088
  }
3364
- function trigger() {
3089
+ function trigger$1() {
3365
3090
  for (var _i = 0, queue_1 = queue$1; _i < queue_1.length; _i++) {
3366
3091
  var node = queue_1[_i];
3367
3092
  var shadowRoot = node && node.nodeType === Node.DOCUMENT_FRAGMENT_NODE;
@@ -3405,7 +3130,7 @@ function link(node) {
3405
3130
  }
3406
3131
  return null;
3407
3132
  }
3408
- function metadata(node, event) {
3133
+ function metadata$2(node, event) {
3409
3134
  // If the node is null, we return a reserved value for id: 0. Valid assignment of id begins from 1+.
3410
3135
  var output = { id: 0, hash: null, privacy: 2 /* Text */, node: node };
3411
3136
  if (node) {
@@ -3415,7 +3140,7 @@ function metadata(node, event) {
3415
3140
  output.hash = value.hash;
3416
3141
  output.privacy = value.metadata.privacy;
3417
3142
  if (value.region) {
3418
- track$3(value.region, event);
3143
+ track$4(value.region, event);
3419
3144
  }
3420
3145
  }
3421
3146
  }
@@ -3440,7 +3165,7 @@ function encode$2 (type) {
3440
3165
  case 20 /* TouchCancel */:
3441
3166
  for (_i = 0, _a = state$3; _i < _a.length; _i++) {
3442
3167
  entry = _a[_i];
3443
- pTarget = metadata(entry.data.target, entry.event);
3168
+ pTarget = metadata$2(entry.data.target, entry.event);
3444
3169
  if (pTarget.id > 0) {
3445
3170
  tokens = [entry.time, entry.event];
3446
3171
  tokens.push(pTarget.id);
@@ -3450,12 +3175,12 @@ function encode$2 (type) {
3450
3175
  track$7(entry.event, entry.data.x, entry.data.y);
3451
3176
  }
3452
3177
  }
3453
- reset$a();
3178
+ reset$b();
3454
3179
  break;
3455
3180
  case 9 /* Click */:
3456
3181
  for (_b = 0, _c = state$6; _b < _c.length; _b++) {
3457
3182
  entry = _c[_b];
3458
- cTarget = metadata(entry.data.target, entry.event);
3183
+ cTarget = metadata$2(entry.data.target, entry.event);
3459
3184
  tokens = [entry.time, entry.event];
3460
3185
  cHash = cTarget.hash.join("." /* Dot */);
3461
3186
  tokens.push(cTarget.id);
@@ -3470,65 +3195,65 @@ function encode$2 (type) {
3470
3195
  tokens.push(entry.data.link);
3471
3196
  tokens.push(cHash);
3472
3197
  queue(tokens);
3473
- track$1(entry.time, entry.event, cHash, entry.data.x, entry.data.y, entry.data.reaction, entry.data.context);
3198
+ track$2(entry.time, entry.event, cHash, entry.data.x, entry.data.y, entry.data.reaction, entry.data.context);
3474
3199
  }
3475
- reset$d();
3200
+ reset$e();
3476
3201
  break;
3477
3202
  case 38 /* Clipboard */:
3478
3203
  for (_d = 0, _e = state$5; _d < _e.length; _d++) {
3479
3204
  entry = _e[_d];
3480
3205
  tokens = [entry.time, entry.event];
3481
- target = metadata(entry.data.target, entry.event);
3206
+ target = metadata$2(entry.data.target, entry.event);
3482
3207
  if (target.id > 0) {
3483
3208
  tokens.push(target.id);
3484
3209
  tokens.push(entry.data.action);
3485
3210
  queue(tokens);
3486
3211
  }
3487
3212
  }
3488
- reset$c();
3213
+ reset$d();
3489
3214
  break;
3490
3215
  case 11 /* Resize */:
3491
- r = data$5;
3216
+ r = data$8;
3492
3217
  tokens.push(r.width);
3493
3218
  tokens.push(r.height);
3494
3219
  track$7(type, r.width, r.height);
3495
- reset$9();
3220
+ reset$a();
3496
3221
  queue(tokens);
3497
3222
  break;
3498
3223
  case 26 /* Unload */:
3499
- u = data$3;
3224
+ u = data$6;
3500
3225
  tokens.push(u.name);
3501
- reset$5();
3226
+ reset$6();
3502
3227
  queue(tokens);
3503
3228
  break;
3504
3229
  case 27 /* Input */:
3505
3230
  for (_f = 0, _g = state$4; _f < _g.length; _f++) {
3506
3231
  entry = _g[_f];
3507
- iTarget = metadata(entry.data.target, entry.event);
3232
+ iTarget = metadata$2(entry.data.target, entry.event);
3508
3233
  tokens = [entry.time, entry.event];
3509
3234
  tokens.push(iTarget.id);
3510
3235
  tokens.push(entry.data.value);
3511
3236
  queue(tokens);
3512
3237
  }
3513
- reset$b();
3238
+ reset$c();
3514
3239
  break;
3515
3240
  case 21 /* Selection */:
3516
- s = data$4;
3241
+ s = data$7;
3517
3242
  if (s) {
3518
- startTarget = metadata(s.start, type);
3519
- endTarget = metadata(s.end, type);
3243
+ startTarget = metadata$2(s.start, type);
3244
+ endTarget = metadata$2(s.end, type);
3520
3245
  tokens.push(startTarget.id);
3521
3246
  tokens.push(s.startOffset);
3522
3247
  tokens.push(endTarget.id);
3523
3248
  tokens.push(s.endOffset);
3524
- reset$7();
3249
+ reset$8();
3525
3250
  queue(tokens);
3526
3251
  }
3527
3252
  break;
3528
3253
  case 10 /* Scroll */:
3529
3254
  for (_h = 0, _j = state$2; _h < _j.length; _h++) {
3530
3255
  entry = _j[_h];
3531
- sTarget = metadata(entry.data.target, entry.event);
3256
+ sTarget = metadata$2(entry.data.target, entry.event);
3532
3257
  if (sTarget.id > 0) {
3533
3258
  tokens = [entry.time, entry.event];
3534
3259
  tokens.push(sTarget.id);
@@ -3538,19 +3263,19 @@ function encode$2 (type) {
3538
3263
  track$7(entry.event, entry.data.x, entry.data.y);
3539
3264
  }
3540
3265
  }
3541
- reset$8();
3266
+ reset$9();
3542
3267
  break;
3543
3268
  case 39 /* Submit */:
3544
3269
  for (_k = 0, _l = state$1; _k < _l.length; _k++) {
3545
3270
  entry = _l[_k];
3546
3271
  tokens = [entry.time, entry.event];
3547
- target = metadata(entry.data.target, entry.event);
3272
+ target = metadata$2(entry.data.target, entry.event);
3548
3273
  if (target.id > 0) {
3549
3274
  tokens.push(target.id);
3550
3275
  queue(tokens);
3551
3276
  }
3552
3277
  }
3553
- reset$6();
3278
+ reset$7();
3554
3279
  break;
3555
3280
  case 22 /* Timeline */:
3556
3281
  for (_m = 0, _o = updates$1; _m < _o.length; _m++) {
@@ -3564,14 +3289,14 @@ function encode$2 (type) {
3564
3289
  tokens.push(entry.data.context);
3565
3290
  queue(tokens, false);
3566
3291
  }
3567
- reset$3();
3292
+ reset$4();
3568
3293
  break;
3569
3294
  case 28 /* Visibility */:
3570
- v = data$2;
3295
+ v = data$5;
3571
3296
  tokens.push(v.visible);
3572
3297
  queue(tokens);
3573
3298
  visibility(t, v.visible);
3574
- reset$4();
3299
+ reset$5();
3575
3300
  break;
3576
3301
  }
3577
3302
  return [2 /*return*/];
@@ -3581,14 +3306,14 @@ function encode$2 (type) {
3581
3306
 
3582
3307
  var state = [];
3583
3308
  var updates$1 = [];
3584
- function start$a() {
3309
+ function start$d() {
3585
3310
  state = [];
3586
- reset$3();
3311
+ reset$4();
3587
3312
  }
3588
- function reset$3() {
3313
+ function reset$4() {
3589
3314
  updates$1 = [];
3590
3315
  }
3591
- function track$1(time, event, hash, x, y, reaction, context) {
3316
+ function track$2(time, event, hash, x, y, reaction, context) {
3592
3317
  if (reaction === void 0) { reaction = 1 /* True */; }
3593
3318
  if (context === void 0) { context = 0 /* Self */; }
3594
3319
  state.push({
@@ -3608,10 +3333,10 @@ function track$1(time, event, hash, x, y, reaction, context) {
3608
3333
  // We would still need to capture the last scroll position as part of the baseline event, even when timeline will be empty.
3609
3334
  track$7(event, x, y);
3610
3335
  }
3611
- function compute$3() {
3336
+ function compute$4() {
3612
3337
  var temp = [];
3613
3338
  updates$1 = [];
3614
- var max = data$f.start + data$f.duration;
3339
+ var max = data$1.start + data$1.duration;
3615
3340
  var min = Math.max(max - 2000 /* TimelineSpan */, 0);
3616
3341
  for (var _i = 0, state_1 = state; _i < state_1.length; _i++) {
3617
3342
  var s = state_1[_i];
@@ -3625,9 +3350,9 @@ function compute$3() {
3625
3350
  state = temp; // Drop events less than the min time
3626
3351
  encode$2(22 /* Timeline */);
3627
3352
  }
3628
- function stop$9() {
3353
+ function stop$c() {
3629
3354
  state = [];
3630
- reset$3();
3355
+ reset$4();
3631
3356
  }
3632
3357
 
3633
3358
  var discoverBytes = 0;
@@ -3638,8 +3363,8 @@ var timeout = null;
3638
3363
  var transit;
3639
3364
  var active$1;
3640
3365
  var queuedTime = 0;
3641
- var track;
3642
- function start$9() {
3366
+ var track$1;
3367
+ function start$c() {
3643
3368
  active$1 = true;
3644
3369
  discoverBytes = 0;
3645
3370
  playbackBytes = 0;
@@ -3647,7 +3372,7 @@ function start$9() {
3647
3372
  playback = [];
3648
3373
  analysis = [];
3649
3374
  transit = {};
3650
- track = null;
3375
+ track$1 = null;
3651
3376
  }
3652
3377
  function queue(tokens, transmit) {
3653
3378
  if (transmit === void 0) { transmit = true; }
@@ -3682,15 +3407,15 @@ function queue(tokens, transmit) {
3682
3407
  // We enrich the data going out with the existing upload. In these cases, call to upload comes with 'transmit' set to false.
3683
3408
  if (transmit && timeout === null) {
3684
3409
  if (type !== 25 /* Ping */) {
3685
- reset$k();
3410
+ reset$m();
3686
3411
  }
3687
3412
  timeout = setTimeout(upload, gap);
3688
3413
  queuedTime = now;
3689
- check$3(playbackBytes);
3414
+ check$2(playbackBytes);
3690
3415
  }
3691
3416
  }
3692
3417
  }
3693
- function stop$8() {
3418
+ function stop$b() {
3694
3419
  clearTimeout(timeout);
3695
3420
  upload(true);
3696
3421
  discoverBytes = 0;
@@ -3699,7 +3424,7 @@ function stop$8() {
3699
3424
  playback = [];
3700
3425
  analysis = [];
3701
3426
  transit = {};
3702
- track = null;
3427
+ track$1 = null;
3703
3428
  active$1 = false;
3704
3429
  }
3705
3430
  function upload(final) {
@@ -3710,15 +3435,15 @@ function upload(final) {
3710
3435
  switch (_b.label) {
3711
3436
  case 0:
3712
3437
  timeout = null;
3713
- sendPlaybackBytes = config$1.lean === false && playbackBytes > 0 && (playbackBytes < 1048576 /* MaxFirstPayloadBytes */ || data$f.sequence > 0);
3438
+ sendPlaybackBytes = config$1.lean === false && playbackBytes > 0 && (playbackBytes < 1048576 /* MaxFirstPayloadBytes */ || data$1.sequence > 0);
3714
3439
  if (sendPlaybackBytes) {
3715
3440
  max(1 /* Playback */, 1 /* True */);
3716
3441
  }
3717
3442
  // CAUTION: Ensure "transmit" is set to false in the queue function for following events
3718
3443
  // Otherwise you run a risk of infinite loop.
3444
+ compute$5();
3719
3445
  compute$4();
3720
- compute$3();
3721
- compute$7();
3446
+ compute$8();
3722
3447
  last = final === true;
3723
3448
  e = JSON.stringify(envelope(last));
3724
3449
  a = "[" + analysis.join() + "]";
@@ -3735,7 +3460,7 @@ function upload(final) {
3735
3460
  case 3:
3736
3461
  zipped = _a;
3737
3462
  sum(2 /* TotalBytes */, zipped ? zipped.length : payload.length);
3738
- send(payload, zipped, data$f.sequence, last);
3463
+ send(payload, zipped, data$1.sequence, last);
3739
3464
  // Clear out events now that payload has been dispatched
3740
3465
  analysis = [];
3741
3466
  if (sendPlaybackBytes) {
@@ -3781,265 +3506,607 @@ function send(payload, zipped, sequence, beacon) {
3781
3506
  else {
3782
3507
  transit[sequence] = { data: payload, attempts: 1 };
3783
3508
  }
3784
- var xhr_1 = new XMLHttpRequest();
3785
- xhr_1.open("POST", url);
3786
- if (sequence !== null) {
3787
- xhr_1.onreadystatechange = function () { measure(check$2)(xhr_1, sequence); };
3509
+ var xhr_1 = new XMLHttpRequest();
3510
+ xhr_1.open("POST", url);
3511
+ if (sequence !== null) {
3512
+ xhr_1.onreadystatechange = function () { measure(check$3)(xhr_1, sequence); };
3513
+ }
3514
+ xhr_1.withCredentials = true;
3515
+ if (zipped) {
3516
+ // If we do have valid compressed array, send it with appropriate HTTP headers so server can decode it appropriately
3517
+ xhr_1.setRequestHeader("Accept" /* Accept */, "application/x-clarity-gzip" /* ClarityGzip */);
3518
+ xhr_1.send(zipped);
3519
+ }
3520
+ else {
3521
+ // In all other cases, continue sending string back to the server
3522
+ xhr_1.send(payload);
3523
+ }
3524
+ }
3525
+ }
3526
+ else if (config$1.upload) {
3527
+ var callback = config$1.upload;
3528
+ callback(payload);
3529
+ done(sequence);
3530
+ }
3531
+ }
3532
+ function check$3(xhr, sequence) {
3533
+ var transitData = transit[sequence];
3534
+ if (xhr && xhr.readyState === 4 /* Done */ && transitData) {
3535
+ // Attempt send payload again (as configured in settings) if we do not receive a success (2XX) response code back from the server
3536
+ if ((xhr.status < 200 || xhr.status > 208) && transitData.attempts <= 1 /* RetryLimit */) {
3537
+ // We re-attempt in all cases except when server explicitly rejects our request with 4XX error
3538
+ if (xhr.status >= 400 && xhr.status < 500) {
3539
+ // In case of a 4XX response from the server, we bail out instead of trying again
3540
+ trigger(6 /* Server */);
3541
+ }
3542
+ else {
3543
+ // Browser will send status = 0 when it refuses to put network request over the wire
3544
+ // This could happen for several reasons, couple of known ones are:
3545
+ // 1: Browsers block upload because of content security policy violation
3546
+ // 2: Safari will terminate pending XHR requests with status code 0 if the user navigates away from the page
3547
+ // In any case, we switch the upload URL to fallback configuration (if available) before re-trying one more time
3548
+ if (xhr.status === 0) {
3549
+ config$1.upload = config$1.fallback ? config$1.fallback : config$1.upload;
3550
+ }
3551
+ // In all other cases, re-attempt sending the same data
3552
+ // For retry we always fallback to string payload, even though we may have attempted
3553
+ // sending zipped payload earlier
3554
+ send(transitData.data, null, sequence);
3555
+ }
3556
+ }
3557
+ else {
3558
+ track$1 = { sequence: sequence, attempts: transitData.attempts, status: xhr.status };
3559
+ // Send back an event only if we were not successful in our first attempt
3560
+ if (transitData.attempts > 1) {
3561
+ encode$1(2 /* Upload */);
3562
+ }
3563
+ // Handle response if it was a 200 response with a valid body
3564
+ if (xhr.status === 200 && xhr.responseText) {
3565
+ response(xhr.responseText);
3566
+ }
3567
+ // If we exhausted our retries then trigger Clarity's shutdown for this page since the data will be incomplete
3568
+ if (xhr.status === 0) {
3569
+ // And, right before we terminate the session, we will attempt one last time to see if we can use
3570
+ // different transport option (sendBeacon vs. XHR) to get this data to the server for analysis purposes
3571
+ send(transitData.data, null, sequence, true);
3572
+ trigger(3 /* Retry */);
3573
+ }
3574
+ // Signal that this request completed successfully
3575
+ if (xhr.status >= 200 && xhr.status <= 208) {
3576
+ done(sequence);
3577
+ }
3578
+ // Stop tracking this payload now that it's all done
3579
+ delete transit[sequence];
3580
+ }
3581
+ }
3582
+ }
3583
+ function done(sequence) {
3584
+ // If we everything went successfully, and it is the first sequence, save this session for future reference
3585
+ if (sequence === 1) {
3586
+ save();
3587
+ }
3588
+ }
3589
+ function delay() {
3590
+ // Progressively increase delay as we continue to send more payloads from the client to the server
3591
+ // If we are not uploading data to a server, and instead invoking UploadCallback, in that case keep returning configured value
3592
+ var gap = config$1.lean === false && discoverBytes > 0 ? 100 /* MinUploadDelay */ : data$1.sequence * config$1.delay;
3593
+ return typeof config$1.upload === "string" /* String */ ? Math.max(Math.min(gap, 30000 /* MaxUploadDelay */), 100 /* MinUploadDelay */) : config$1.delay;
3594
+ }
3595
+ function response(payload) {
3596
+ var key = payload && payload.length > 0 ? payload.split(" ")[0] : "" /* Empty */;
3597
+ switch (key) {
3598
+ case "END" /* End */:
3599
+ // Clear out session storage and end the session so we can start fresh the next time
3600
+ trigger(6 /* Server */);
3601
+ break;
3602
+ case "UPGRADE" /* Upgrade */:
3603
+ // Upgrade current session to send back playback information
3604
+ upgrade("Auto" /* Auto */);
3605
+ break;
3606
+ }
3607
+ }
3608
+
3609
+ function encode$1 (event) {
3610
+ var t = time();
3611
+ var tokens = [t, event];
3612
+ switch (event) {
3613
+ case 4 /* Baseline */:
3614
+ var b = state$9;
3615
+ if (b) {
3616
+ tokens = [b.time, b.event];
3617
+ tokens.push(b.data.visible);
3618
+ tokens.push(b.data.docWidth);
3619
+ tokens.push(b.data.docHeight);
3620
+ tokens.push(b.data.screenWidth);
3621
+ tokens.push(b.data.screenHeight);
3622
+ tokens.push(b.data.scrollX);
3623
+ tokens.push(b.data.scrollY);
3624
+ tokens.push(b.data.pointerX);
3625
+ tokens.push(b.data.pointerY);
3626
+ tokens.push(b.data.activityTime);
3627
+ queue(tokens, false);
3628
+ }
3629
+ reset$o();
3630
+ break;
3631
+ case 25 /* Ping */:
3632
+ tokens.push(data$g.gap);
3633
+ queue(tokens);
3634
+ break;
3635
+ case 35 /* Limit */:
3636
+ tokens.push(data$4.check);
3637
+ queue(tokens, false);
3638
+ break;
3639
+ case 3 /* Upgrade */:
3640
+ tokens.push(data$e.key);
3641
+ queue(tokens);
3642
+ break;
3643
+ case 2 /* Upload */:
3644
+ tokens.push(track$1.sequence);
3645
+ tokens.push(track$1.attempts);
3646
+ tokens.push(track$1.status);
3647
+ queue(tokens, false);
3648
+ break;
3649
+ case 24 /* Custom */:
3650
+ tokens.push(data$i.key);
3651
+ tokens.push(data$i.value);
3652
+ queue(tokens);
3653
+ break;
3654
+ case 34 /* Variable */:
3655
+ var variableKeys = Object.keys(data$d);
3656
+ if (variableKeys.length > 0) {
3657
+ for (var _i = 0, variableKeys_1 = variableKeys; _i < variableKeys_1.length; _i++) {
3658
+ var v = variableKeys_1[_i];
3659
+ tokens.push(v);
3660
+ tokens.push(data$d[v]);
3661
+ }
3662
+ reset$k();
3663
+ queue(tokens, false);
3664
+ }
3665
+ break;
3666
+ case 0 /* Metric */:
3667
+ var metricKeys = Object.keys(updates$3);
3668
+ if (metricKeys.length > 0) {
3669
+ for (var _a = 0, metricKeys_1 = metricKeys; _a < metricKeys_1.length; _a++) {
3670
+ var m = metricKeys_1[_a];
3671
+ var key = parseInt(m, 10);
3672
+ tokens.push(key);
3673
+ // For computation, we need microseconds precision that performance.now() API offers
3674
+ // However, for data over the wire, we round it off to milliseconds precision.
3675
+ tokens.push(Math.round(updates$3[m]));
3676
+ }
3677
+ reset$n();
3678
+ queue(tokens, false);
3788
3679
  }
3789
- xhr_1.withCredentials = true;
3790
- if (zipped) {
3791
- // If we do have valid compressed array, send it with appropriate HTTP headers so server can decode it appropriately
3792
- xhr_1.setRequestHeader("Accept" /* Accept */, "application/x-clarity-gzip" /* ClarityGzip */);
3793
- xhr_1.send(zipped);
3680
+ break;
3681
+ case 1 /* Dimension */:
3682
+ var dimensionKeys = Object.keys(updates);
3683
+ if (dimensionKeys.length > 0) {
3684
+ for (var _b = 0, dimensionKeys_1 = dimensionKeys; _b < dimensionKeys_1.length; _b++) {
3685
+ var d = dimensionKeys_1[_b];
3686
+ var key = parseInt(d, 10);
3687
+ tokens.push(key);
3688
+ tokens.push(updates[d]);
3689
+ }
3690
+ reset$3();
3691
+ queue(tokens, false);
3794
3692
  }
3795
- else {
3796
- // In all other cases, continue sending string back to the server
3797
- xhr_1.send(payload);
3693
+ break;
3694
+ case 36 /* Summary */:
3695
+ var eventKeys = Object.keys(data$f);
3696
+ if (eventKeys.length > 0) {
3697
+ for (var _c = 0, eventKeys_1 = eventKeys; _c < eventKeys_1.length; _c++) {
3698
+ var e = eventKeys_1[_c];
3699
+ var key = parseInt(e, 10);
3700
+ tokens.push(key);
3701
+ tokens.push([].concat.apply([], data$f[e]));
3702
+ }
3703
+ reset$l();
3704
+ queue(tokens, false);
3798
3705
  }
3706
+ break;
3707
+ }
3708
+ }
3709
+
3710
+ var data$4;
3711
+ function start$b() {
3712
+ data$4 = { check: 0 /* None */ };
3713
+ }
3714
+ function check$2(bytes) {
3715
+ if (data$4.check === 0 /* None */) {
3716
+ var reason = data$4.check;
3717
+ reason = data$1.sequence >= 128 /* PayloadLimit */ ? 1 /* Payload */ : reason;
3718
+ reason = time() > 7200000 /* ShutdownLimit */ ? 2 /* Shutdown */ : reason;
3719
+ reason = bytes > 10485760 /* PlaybackBytesLimit */ ? 2 /* Shutdown */ : reason;
3720
+ if (reason !== data$4.check) {
3721
+ trigger(reason);
3799
3722
  }
3800
3723
  }
3801
- else if (config$1.upload) {
3802
- var callback = config$1.upload;
3803
- callback(payload);
3804
- done(sequence);
3724
+ }
3725
+ function trigger(reason) {
3726
+ data$4.check = reason;
3727
+ clear();
3728
+ stop();
3729
+ }
3730
+ function compute$3() {
3731
+ if (data$4.check !== 0 /* None */) {
3732
+ encode$1(35 /* Limit */);
3805
3733
  }
3806
3734
  }
3807
- function check$2(xhr, sequence) {
3808
- var transitData = transit[sequence];
3809
- if (xhr && xhr.readyState === 4 /* Done */ && transitData) {
3810
- // Attempt send payload again (as configured in settings) if we do not receive a success (2XX) response code back from the server
3811
- if ((xhr.status < 200 || xhr.status > 208) && transitData.attempts <= 1 /* RetryLimit */) {
3812
- // We re-attempt in all cases except when server explicitly rejects our request with 4XX error
3813
- if (xhr.status >= 400 && xhr.status < 500) {
3814
- // In case of a 4XX response from the server, we bail out instead of trying again
3815
- trigger$1(6 /* Server */);
3816
- }
3817
- else {
3818
- // Browser will send status = 0 when it refuses to put network request over the wire
3819
- // This could happen for several reasons, couple of known ones are:
3820
- // 1: Browsers block upload because of content security policy violation
3821
- // 2: Safari will terminate pending XHR requests with status code 0 if the user navigates away from the page
3822
- // In any case, we switch the upload URL to fallback configuration (if available) before re-trying one more time
3823
- if (xhr.status === 0) {
3824
- config$1.upload = config$1.fallback ? config$1.fallback : config$1.upload;
3825
- }
3826
- // In all other cases, re-attempt sending the same data
3827
- // For retry we always fallback to string payload, even though we may have attempted
3828
- // sending zipped payload earlier
3829
- send(transitData.data, null, sequence);
3830
- }
3735
+ function stop$a() {
3736
+ data$4 = null;
3737
+ }
3738
+
3739
+ var data$3 = null;
3740
+ var updates = null;
3741
+ function start$a() {
3742
+ data$3 = {};
3743
+ updates = {};
3744
+ }
3745
+ function stop$9() {
3746
+ data$3 = {};
3747
+ updates = {};
3748
+ }
3749
+ function log(dimension, value) {
3750
+ // Check valid value before moving ahead
3751
+ if (value) {
3752
+ // Ensure received value is casted into a string if it wasn't a string to begin with
3753
+ value = "" + value;
3754
+ if (!(dimension in data$3)) {
3755
+ data$3[dimension] = [];
3831
3756
  }
3832
- else {
3833
- track = { sequence: sequence, attempts: transitData.attempts, status: xhr.status };
3834
- // Send back an event only if we were not successful in our first attempt
3835
- if (transitData.attempts > 1) {
3836
- encode$1(2 /* Upload */);
3837
- }
3838
- // Handle response if it was a 200 response with a valid body
3839
- if (xhr.status === 200 && xhr.responseText) {
3840
- response(xhr.responseText);
3841
- }
3842
- // If we exhausted our retries then trigger Clarity's shutdown for this page since the data will be incomplete
3843
- if (xhr.status === 0) {
3844
- // And, right before we terminate the session, we will attempt one last time to see if we can use
3845
- // different transport option (sendBeacon vs. XHR) to get this data to the server for analysis purposes
3846
- send(transitData.data, null, sequence, true);
3847
- trigger$1(3 /* Retry */);
3757
+ if (data$3[dimension].indexOf(value) < 0) {
3758
+ data$3[dimension].push(value);
3759
+ // If this is a new value, track it as part of updates object
3760
+ // This allows us to only send back new values in subsequent payloads
3761
+ if (!(dimension in updates)) {
3762
+ updates[dimension] = [];
3848
3763
  }
3849
- // Signal that this request completed successfully
3850
- if (xhr.status >= 200 && xhr.status <= 208) {
3851
- done(sequence);
3764
+ updates[dimension].push(value);
3765
+ // Limit check to ensure we have a cap on number of dimensions we can collect
3766
+ if (data$3[dimension].length > 128 /* CollectionLimit */) {
3767
+ trigger(5 /* Collection */);
3852
3768
  }
3853
- // Stop tracking this payload now that it's all done
3854
- delete transit[sequence];
3855
3769
  }
3856
3770
  }
3857
3771
  }
3858
- function done(sequence) {
3859
- // If we everything went successfully, and it is the first sequence, save this session for future reference
3860
- if (sequence === 1) {
3861
- save();
3862
- }
3863
- }
3864
- function delay() {
3865
- // Progressively increase delay as we continue to send more payloads from the client to the server
3866
- // If we are not uploading data to a server, and instead invoking UploadCallback, in that case keep returning configured value
3867
- var gap = config$1.lean === false && discoverBytes > 0 ? 100 /* MinUploadDelay */ : data$f.sequence * config$1.delay;
3868
- return typeof config$1.upload === "string" /* String */ ? Math.max(Math.min(gap, 30000 /* MaxUploadDelay */), 100 /* MinUploadDelay */) : config$1.delay;
3772
+ function compute$2() {
3773
+ encode$1(1 /* Dimension */);
3774
+ }
3775
+ function reset$3() {
3776
+ updates = {};
3777
+ }
3778
+
3779
+ var data$2 = null;
3780
+ var callback = null;
3781
+ var rootDomain = null;
3782
+ function start$9() {
3783
+ callback = null;
3784
+ rootDomain = null;
3785
+ var ua = navigator && "userAgent" in navigator ? navigator.userAgent : "" /* Empty */;
3786
+ var title = document && document.title ? document.title : "" /* Empty */;
3787
+ // Populate ids for this page
3788
+ var s = session();
3789
+ var u = user();
3790
+ data$2 = {
3791
+ projectId: config$1.projectId || hash(location.host),
3792
+ userId: u.id,
3793
+ sessionId: s.session,
3794
+ pageNum: s.count
3795
+ };
3796
+ // Override configuration based on what's in the session storage, unless it is blank (e.g. using upload callback, like in devtools)
3797
+ config$1.lean = config$1.track && s.upgrade !== null ? s.upgrade === 0 /* False */ : config$1.lean;
3798
+ config$1.upload = config$1.track && typeof config$1.upload === "string" /* String */ && s.upload && s.upload.length > "https://" /* HTTPS */.length ? s.upload : config$1.upload;
3799
+ // Log dimensions
3800
+ log(0 /* UserAgent */, ua);
3801
+ log(3 /* PageTitle */, title);
3802
+ log(1 /* Url */, location.href);
3803
+ log(2 /* Referrer */, document.referrer);
3804
+ log(15 /* TabId */, tab());
3805
+ log(16 /* PageLanguage */, document.documentElement.lang);
3806
+ log(17 /* DocumentDirection */, document.dir);
3807
+ if (navigator) {
3808
+ log(9 /* Language */, navigator.userLanguage || navigator.language);
3809
+ max(26 /* Automation */, navigator.webdriver ? 1 /* True */ : 0 /* False */);
3810
+ userAgentData();
3811
+ }
3812
+ // Metrics
3813
+ max(0 /* ClientTimestamp */, s.ts);
3814
+ max(1 /* Playback */, 0 /* False */);
3815
+ if (screen) {
3816
+ max(14 /* ScreenWidth */, Math.round(screen.width));
3817
+ max(15 /* ScreenHeight */, Math.round(screen.height));
3818
+ max(16 /* ColorDepth */, Math.round(screen.colorDepth));
3819
+ }
3820
+ // Read cookies specified in configuration
3821
+ for (var _i = 0, _a = config$1.cookies; _i < _a.length; _i++) {
3822
+ var key = _a[_i];
3823
+ var value = getCookie(key);
3824
+ if (value) {
3825
+ set(key, value);
3826
+ }
3827
+ }
3828
+ // Track ids using a cookie if configuration allows it
3829
+ track(u);
3830
+ }
3831
+ function userAgentData() {
3832
+ if (navigator["userAgentData"] && navigator["userAgentData"].getHighEntropyValues) {
3833
+ navigator["userAgentData"].getHighEntropyValues(["model",
3834
+ "platform",
3835
+ "platformVersion",
3836
+ "uaFullVersion"])
3837
+ .then(function (ua) {
3838
+ var _a;
3839
+ log(22 /* Platform */, ua.platform);
3840
+ log(23 /* PlatformVersion */, ua.platformVersion);
3841
+ (_a = ua.brands) === null || _a === void 0 ? void 0 : _a.forEach(function (brand) {
3842
+ log(24 /* Brand */, brand.name + "~" /* Tilde */ + brand.version);
3843
+ });
3844
+ log(25 /* Model */, ua.model);
3845
+ max(27 /* Mobile */, ua.mobile ? 1 /* True */ : 0 /* False */);
3846
+ });
3847
+ }
3848
+ }
3849
+ function stop$8() {
3850
+ callback = null;
3851
+ rootDomain = null;
3852
+ data$2 = null;
3853
+ }
3854
+ function metadata(cb, wait) {
3855
+ if (wait === void 0) { wait = true; }
3856
+ if (data$2 && wait === false) {
3857
+ // Immediately invoke the callback if the caller explicitly doesn't want to wait for the upgrade confirmation
3858
+ cb(data$2, !config$1.lean);
3859
+ }
3860
+ else {
3861
+ // Save the callback for future reference; so we can inform the caller when page gets upgraded and we have a valid playback flag
3862
+ callback = cb;
3863
+ }
3864
+ }
3865
+ function id() {
3866
+ return data$2 ? [data$2.userId, data$2.sessionId, data$2.pageNum].join("." /* Dot */) : "" /* Empty */;
3867
+ }
3868
+ function consent() {
3869
+ if (active()) {
3870
+ config$1.track = true;
3871
+ track(user(), 1 /* True */);
3872
+ }
3873
+ }
3874
+ function clear() {
3875
+ // Clear any stored information in the cookie that tracks session information so we can restart fresh the next time
3876
+ setCookie("_clsk" /* SessionKey */, "" /* Empty */, 0);
3877
+ }
3878
+ function tab() {
3879
+ var id = shortid();
3880
+ if (config$1.track && supported(window, "sessionStorage" /* SessionStorage */)) {
3881
+ var value = sessionStorage.getItem("_cltk" /* TabKey */);
3882
+ id = value ? value : id;
3883
+ sessionStorage.setItem("_cltk" /* TabKey */, id);
3884
+ }
3885
+ return id;
3886
+ }
3887
+ function save() {
3888
+ var ts = Math.round(Date.now());
3889
+ var upgrade = config$1.lean ? 0 /* False */ : 1 /* True */;
3890
+ var upload = config$1.upload && typeof config$1.upload === "string" /* String */ ? config$1.upload.replace("https://" /* HTTPS */, "" /* Empty */) : "" /* Empty */;
3891
+ if (upgrade && callback) {
3892
+ callback(data$2, !config$1.lean);
3893
+ }
3894
+ setCookie("_clsk" /* SessionKey */, [data$2.sessionId, ts, data$2.pageNum, upgrade, upload].join("|" /* Pipe */), 1 /* SessionExpire */);
3895
+ }
3896
+ function supported(target, api) {
3897
+ try {
3898
+ return !!target[api];
3899
+ }
3900
+ catch (_a) {
3901
+ return false;
3902
+ }
3903
+ }
3904
+ function track(u, consent) {
3905
+ if (consent === void 0) { consent = null; }
3906
+ // If consent is not explicitly specified, infer it from the user object
3907
+ consent = consent === null ? u.consent : consent;
3908
+ // Convert time precision into days to reduce number of bytes we have to write in a cookie
3909
+ // E.g. Math.ceil(1628735962643 / (24*60*60*1000)) => 18852 (days) => ejo in base36 (13 bytes => 3 bytes)
3910
+ var end = Math.ceil((Date.now() + (365 /* Expire */ * 86400000 /* Day */)) / 86400000 /* Day */);
3911
+ // To avoid cookie churn, write user id cookie only once every day
3912
+ if (u.expiry === null || Math.abs(end - u.expiry) >= 1 /* CookieInterval */ || u.consent !== consent) {
3913
+ setCookie("_clck" /* CookieKey */, [data$2.userId, 1 /* CookieVersion */, end.toString(36), consent].join("|" /* Pipe */), 365 /* Expire */);
3914
+ }
3915
+ }
3916
+ function shortid() {
3917
+ var id = Math.floor(Math.random() * Math.pow(2, 32));
3918
+ if (window && window.crypto && window.crypto.getRandomValues && Uint32Array) {
3919
+ id = window.crypto.getRandomValues(new Uint32Array(1))[0];
3920
+ }
3921
+ return id.toString(36);
3922
+ }
3923
+ function session() {
3924
+ var output = { session: shortid(), ts: Math.round(Date.now()), count: 1, upgrade: null, upload: "" /* Empty */ };
3925
+ var value = getCookie("_clsk" /* SessionKey */);
3926
+ if (value) {
3927
+ var parts = value.split("|" /* Pipe */);
3928
+ // Making it backward & forward compatible by using greater than comparison (v0.6.21)
3929
+ // In future version, we can reduce the parts length to be 5 where the last part contains the full upload URL
3930
+ if (parts.length >= 5 && output.ts - num(parts[1]) < 1800000 /* SessionTimeout */) {
3931
+ output.session = parts[0];
3932
+ output.count = num(parts[2]) + 1;
3933
+ output.upgrade = num(parts[3]);
3934
+ output.upload = parts.length >= 6 ? "" + "https://" /* HTTPS */ + parts[5] + "/" + parts[4] : "" + "https://" /* HTTPS */ + parts[4];
3935
+ }
3936
+ }
3937
+ return output;
3938
+ }
3939
+ function num(string, base) {
3940
+ if (base === void 0) { base = 10; }
3941
+ return parseInt(string, base);
3869
3942
  }
3870
- function response(payload) {
3871
- var key = payload && payload.length > 0 ? payload.split(" ")[0] : "" /* Empty */;
3872
- switch (key) {
3873
- case "END" /* End */:
3874
- // Clear out session storage and end the session so we can start fresh the next time
3875
- trigger$1(6 /* Server */);
3876
- break;
3877
- case "UPGRADE" /* Upgrade */:
3878
- // Upgrade current session to send back playback information
3879
- upgrade("Auto" /* Auto */);
3880
- break;
3943
+ function user() {
3944
+ var output = { id: shortid(), expiry: null, consent: 0 /* False */ };
3945
+ var cookie = getCookie("_clck" /* CookieKey */);
3946
+ if (cookie && cookie.length > 0) {
3947
+ // Splitting and looking up first part for forward compatibility, in case we wish to store additional information in a cookie
3948
+ var parts = cookie.split("|" /* Pipe */);
3949
+ // For backward compatibility introduced in v0.6.18; following code can be removed with future iterations
3950
+ // Count number of times Clarity's user cookie crumb appears in document.cookie (could be on different sub-domains e.g. www.domain.com and .domain.com)
3951
+ var count = 0;
3952
+ for (var _i = 0, _a = document.cookie.split(";" /* Semicolon */); _i < _a.length; _i++) {
3953
+ var c = _a[_i];
3954
+ count += c.split("=" /* Equals */)[0].trim() === "_clck" /* CookieKey */ ? 1 : 0;
3955
+ }
3956
+ // Check if we either got version-less cookie value or saw multiple copies of the user cookie crumbs
3957
+ // In both these cases, we go ahead and delete the existing cookie set on current domain
3958
+ if (parts.length === 1 || count > 1) {
3959
+ var deleted = "" + ";" /* Semicolon */ + "expires=" /* Expires */ + (new Date(0)).toUTCString() + ";path=/" /* Path */;
3960
+ // First, delete current user cookie which might be set on current sub-domain vs. root domain
3961
+ document.cookie = "_clck" /* CookieKey */ + "=" + deleted;
3962
+ // Second, same thing for current session cookie so it can be re-written later with the root domain
3963
+ document.cookie = "_clsk" /* SessionKey */ + "=" + deleted;
3964
+ }
3965
+ // End code for backward compatibility
3966
+ // Read version information and timestamp from cookie, if available
3967
+ if (parts.length > 2) {
3968
+ output.expiry = num(parts[2], 36);
3969
+ }
3970
+ // Check if we have explicit consent to track this user
3971
+ if (parts.length > 3 && num(parts[3]) === 1) {
3972
+ output.consent = 1 /* True */;
3973
+ }
3974
+ // Set track configuration to true for this user if we have explicit consent, regardless of project setting
3975
+ config$1.track = config$1.track || output.consent === 1 /* True */;
3976
+ // Get user id from cookie only if we tracking is enabled, otherwise fallback to a random id
3977
+ output.id = config$1.track ? parts[0] : output.id;
3881
3978
  }
3882
- }
3883
-
3884
- function encode$1 (event) {
3885
- var t = time();
3886
- var tokens = [t, event];
3887
- switch (event) {
3888
- case 4 /* Baseline */:
3889
- var b = state$9;
3890
- if (b) {
3891
- tokens = [b.time, b.event];
3892
- tokens.push(b.data.visible);
3893
- tokens.push(b.data.docWidth);
3894
- tokens.push(b.data.docHeight);
3895
- tokens.push(b.data.screenWidth);
3896
- tokens.push(b.data.screenHeight);
3897
- tokens.push(b.data.scrollX);
3898
- tokens.push(b.data.scrollY);
3899
- tokens.push(b.data.pointerX);
3900
- tokens.push(b.data.pointerY);
3901
- tokens.push(b.data.activityTime);
3902
- queue(tokens, false);
3903
- }
3904
- reset$o();
3905
- break;
3906
- case 25 /* Ping */:
3907
- tokens.push(data$c.gap);
3908
- queue(tokens);
3909
- break;
3910
- case 35 /* Limit */:
3911
- tokens.push(data$e.check);
3912
- queue(tokens, false);
3913
- break;
3914
- case 3 /* Upgrade */:
3915
- tokens.push(data$a.key);
3916
- queue(tokens);
3917
- break;
3918
- case 2 /* Upload */:
3919
- tokens.push(track.sequence);
3920
- tokens.push(track.attempts);
3921
- tokens.push(track.status);
3922
- queue(tokens, false);
3923
- break;
3924
- case 24 /* Custom */:
3925
- tokens.push(data$i.key);
3926
- tokens.push(data$i.value);
3927
- queue(tokens);
3928
- break;
3929
- case 34 /* Variable */:
3930
- var variableKeys = Object.keys(data$h);
3931
- if (variableKeys.length > 0) {
3932
- for (var _i = 0, variableKeys_1 = variableKeys; _i < variableKeys_1.length; _i++) {
3933
- var v = variableKeys_1[_i];
3934
- tokens.push(v);
3935
- tokens.push(data$h[v]);
3936
- }
3937
- reset$n();
3938
- queue(tokens, false);
3939
- }
3940
- break;
3941
- case 0 /* Metric */:
3942
- var metricKeys = Object.keys(updates);
3943
- if (metricKeys.length > 0) {
3944
- for (var _a = 0, metricKeys_1 = metricKeys; _a < metricKeys_1.length; _a++) {
3945
- var m = metricKeys_1[_a];
3946
- var key = parseInt(m, 10);
3947
- tokens.push(key);
3948
- // For computation, we need microseconds precision that performance.now() API offers
3949
- // However, for data over the wire, we round it off to milliseconds precision.
3950
- tokens.push(Math.round(updates[m]));
3951
- }
3952
- reset$2();
3953
- queue(tokens, false);
3954
- }
3955
- break;
3956
- case 1 /* Dimension */:
3957
- var dimensionKeys = Object.keys(updates$3);
3958
- if (dimensionKeys.length > 0) {
3959
- for (var _b = 0, dimensionKeys_1 = dimensionKeys; _b < dimensionKeys_1.length; _b++) {
3960
- var d = dimensionKeys_1[_b];
3961
- var key = parseInt(d, 10);
3962
- tokens.push(key);
3963
- tokens.push(updates$3[d]);
3979
+ return output;
3980
+ }
3981
+ function getCookie(key) {
3982
+ if (supported(document, "cookie" /* Cookie */)) {
3983
+ var cookies = document.cookie.split(";" /* Semicolon */);
3984
+ if (cookies) {
3985
+ for (var i = 0; i < cookies.length; i++) {
3986
+ var pair = cookies[i].split("=" /* Equals */);
3987
+ if (pair.length > 1 && pair[0] && pair[0].trim() === key) {
3988
+ return pair[1];
3964
3989
  }
3965
- reset$l();
3966
- queue(tokens, false);
3967
3990
  }
3968
- break;
3969
- case 36 /* Summary */:
3970
- var eventKeys = Object.keys(data$b);
3971
- if (eventKeys.length > 0) {
3972
- for (var _c = 0, eventKeys_1 = eventKeys; _c < eventKeys_1.length; _c++) {
3973
- var e = eventKeys_1[_c];
3974
- var key = parseInt(e, 10);
3975
- tokens.push(key);
3976
- tokens.push([].concat.apply([], data$b[e]));
3991
+ }
3992
+ }
3993
+ return null;
3994
+ }
3995
+ function setCookie(key, value, time) {
3996
+ if (config$1.track && ((navigator && navigator.cookieEnabled) || supported(document, "cookie" /* Cookie */))) {
3997
+ var expiry = new Date();
3998
+ expiry.setDate(expiry.getDate() + time);
3999
+ var expires = expiry ? "expires=" /* Expires */ + expiry.toUTCString() : "" /* Empty */;
4000
+ var cookie = key + "=" + value + ";" /* Semicolon */ + expires + ";path=/" /* Path */;
4001
+ try {
4002
+ // Attempt to get the root domain only once and fall back to writing cookie on the current domain.
4003
+ if (rootDomain === null) {
4004
+ var hostname = location.hostname ? location.hostname.split("." /* Dot */) : [];
4005
+ // Walk backwards on a domain and attempt to set a cookie, until successful
4006
+ for (var i = hostname.length - 1; i >= 0; i--) {
4007
+ rootDomain = "." + hostname[i] + (rootDomain ? rootDomain : "" /* Empty */);
4008
+ // We do not wish to attempt writing a cookie on the absolute last part of the domain, e.g. .com or .net.
4009
+ // So we start attempting after second-last part, e.g. .domain.com (PASS) or .co.uk (FAIL)
4010
+ if (i < hostname.length - 1) {
4011
+ // Write the cookie on the current computed top level domain
4012
+ document.cookie = "" + cookie + ";" /* Semicolon */ + "domain=" /* Domain */ + rootDomain;
4013
+ // Once written, check if the cookie exists and its value matches exactly with what we intended to set
4014
+ // Checking for exact value match helps us eliminate a corner case where the cookie may already be present with a different value
4015
+ // If the check is successful, no more action is required and we can return from the function since rootDomain cookie is already set
4016
+ // If the check fails, continue with the for loop until we can successfully set and verify the cookie
4017
+ if (getCookie(key) === value) {
4018
+ return;
4019
+ }
4020
+ }
3977
4021
  }
3978
- reset$j();
3979
- queue(tokens, false);
4022
+ // Finally, if we were not successful and gone through all the options, play it safe and reset rootDomain to be empty
4023
+ // This forces our code to fall back to always writing cookie to the current domain
4024
+ rootDomain = "" /* Empty */;
3980
4025
  }
3981
- break;
4026
+ }
4027
+ catch (_a) {
4028
+ rootDomain = "" /* Empty */;
4029
+ }
4030
+ document.cookie = rootDomain ? "" + cookie + ";" /* Semicolon */ + "domain=" /* Domain */ + rootDomain : cookie;
3982
4031
  }
3983
4032
  }
3984
4033
 
3985
4034
  var data$1 = null;
3986
- var updates = null;
3987
4035
  function start$8() {
3988
- data$1 = {};
3989
- updates = {};
3990
- count$1(5 /* InvokeCount */);
4036
+ var m = data$2;
4037
+ data$1 = {
4038
+ version: version$1,
4039
+ sequence: 0,
4040
+ start: 0,
4041
+ duration: 0,
4042
+ projectId: m.projectId,
4043
+ userId: m.userId,
4044
+ sessionId: m.sessionId,
4045
+ pageNum: m.pageNum,
4046
+ upload: 0 /* Async */,
4047
+ end: 0 /* False */
4048
+ };
3991
4049
  }
3992
4050
  function stop$7() {
3993
- data$1 = {};
3994
- updates = {};
3995
- }
3996
- function count$1(metric, increment) {
3997
- if (increment === void 0) { increment = 1; }
3998
- if (!(metric in data$1)) {
3999
- data$1[metric] = 0;
4000
- }
4001
- if (!(metric in updates)) {
4002
- updates[metric] = 0;
4003
- }
4004
- data$1[metric] += increment;
4005
- updates[metric] += increment;
4051
+ data$1 = null;
4006
4052
  }
4007
- function sum(metric, value) {
4008
- if (value !== null) {
4009
- if (!(metric in data$1)) {
4010
- data$1[metric] = 0;
4011
- }
4012
- if (!(metric in updates)) {
4013
- updates[metric] = 0;
4014
- }
4015
- data$1[metric] += value;
4016
- updates[metric] += value;
4017
- }
4053
+ function envelope(last) {
4054
+ data$1.start = data$1.start + data$1.duration;
4055
+ data$1.duration = time() - data$1.start;
4056
+ data$1.sequence++;
4057
+ data$1.upload = last && "sendBeacon" in navigator ? 1 /* Beacon */ : 0 /* Async */;
4058
+ data$1.end = last ? 1 /* True */ : 0 /* False */;
4059
+ return [
4060
+ data$1.version,
4061
+ data$1.sequence,
4062
+ data$1.start,
4063
+ data$1.duration,
4064
+ data$1.projectId,
4065
+ data$1.userId,
4066
+ data$1.sessionId,
4067
+ data$1.pageNum,
4068
+ data$1.upload,
4069
+ data$1.end
4070
+ ];
4071
+ }
4072
+
4073
+ var history$1;
4074
+ function reset$2() {
4075
+ history$1 = [];
4018
4076
  }
4019
- function max(metric, value) {
4020
- // Ensure that we do not process null or NaN values
4021
- if (value !== null && isNaN(value) === false) {
4022
- if (!(metric in data$1)) {
4023
- data$1[metric] = 0;
4024
- }
4025
- if (value > data$1[metric] || data$1[metric] === 0) {
4026
- updates[metric] = value;
4027
- data$1[metric] = value;
4077
+ function report(e) {
4078
+ // Do not report the same message twice for the same page
4079
+ if (history$1 && history$1.indexOf(e.message) === -1) {
4080
+ var url = config$1.report;
4081
+ if (url && url.length > 0) {
4082
+ var payload = { v: data$1.version, p: data$1.projectId, u: data$1.userId, s: data$1.sessionId, n: data$1.pageNum };
4083
+ if (e.message) {
4084
+ payload.m = e.message;
4085
+ }
4086
+ if (e.stack) {
4087
+ payload.e = e.stack;
4088
+ }
4089
+ // Using POST request instead of a GET request (img-src) to not violate existing CSP rules
4090
+ // Since, Clarity already uses XHR to upload data, we stick with similar POST mechanism for reporting too
4091
+ var xhr = new XMLHttpRequest();
4092
+ xhr.open("POST", url);
4093
+ xhr.send(JSON.stringify(payload));
4094
+ history$1.push(e.message);
4028
4095
  }
4029
4096
  }
4030
- }
4031
- function compute$2() {
4032
- encode$1(0 /* Metric */);
4033
- }
4034
- function reset$2() {
4035
- updates = {};
4097
+ return e;
4036
4098
  }
4037
4099
 
4038
4100
  // tslint:disable-next-line: ban-types
4039
4101
  function measure (method) {
4040
4102
  return function () {
4041
4103
  var start = performance.now();
4042
- method.apply(this, arguments);
4104
+ try {
4105
+ method.apply(this, arguments);
4106
+ }
4107
+ catch (ex) {
4108
+ throw report(ex);
4109
+ }
4043
4110
  var duration = performance.now() - start;
4044
4111
  sum(4 /* TotalCost */, duration);
4045
4112
  if (duration > 30 /* LongTask */) {
@@ -4105,7 +4172,7 @@ function start$7() {
4105
4172
  }
4106
4173
  function check$1() {
4107
4174
  if (count++ > 20 /* CallStackDepth */) {
4108
- log(4 /* CallStackDepth */, 0 /* Info */);
4175
+ log$1(4 /* CallStackDepth */, 0 /* Info */);
4109
4176
  return false;
4110
4177
  }
4111
4178
  return true;
@@ -4140,16 +4207,16 @@ var status = false;
4140
4207
  function start$6() {
4141
4208
  status = true;
4142
4209
  start$E();
4143
- reset$i();
4210
+ reset$j();
4144
4211
  reset$1();
4145
- reset$m();
4212
+ reset$2();
4146
4213
  start$7();
4147
4214
  }
4148
4215
  function stop$5() {
4149
4216
  stop$6();
4150
- reset$m();
4217
+ reset$2();
4151
4218
  reset$1();
4152
- reset$i();
4219
+ reset$j();
4153
4220
  stop$B();
4154
4221
  status = false;
4155
4222
  }
@@ -4204,11 +4271,11 @@ function restart() {
4204
4271
  }
4205
4272
 
4206
4273
  function start$5() {
4207
- start$q();
4208
- start$p();
4274
+ start$t();
4275
+ start$s();
4209
4276
  }
4210
4277
  function stop$4() {
4211
- stop$o();
4278
+ stop$r();
4212
4279
  }
4213
4280
 
4214
4281
  var diagnostic = /*#__PURE__*/Object.freeze({
@@ -4219,8 +4286,8 @@ var diagnostic = /*#__PURE__*/Object.freeze({
4219
4286
 
4220
4287
  function start$4() {
4221
4288
  schedule$1(discover, 1 /* High */).then(function () {
4222
- measure(compute$6)();
4223
- measure(compute$4)();
4289
+ measure(compute$7)();
4290
+ measure(compute$5)();
4224
4291
  });
4225
4292
  }
4226
4293
  function discover() {
@@ -4231,14 +4298,14 @@ function discover() {
4231
4298
  case 0:
4232
4299
  ts = time();
4233
4300
  timer = { id: id(), cost: 3 /* LayoutCost */ };
4234
- start$t(timer);
4301
+ start$w(timer);
4235
4302
  return [4 /*yield*/, traverse(document, timer, 0 /* Discover */)];
4236
4303
  case 1:
4237
4304
  _a.sent();
4238
4305
  return [4 /*yield*/, encode$4(5 /* Discover */, timer, ts)];
4239
4306
  case 2:
4240
4307
  _a.sent();
4241
- stop$q(timer);
4308
+ stop$t(timer);
4242
4309
  return [2 /*return*/];
4243
4310
  }
4244
4311
  });
@@ -4248,18 +4315,18 @@ function discover() {
4248
4315
  function start$3() {
4249
4316
  // The order below is important
4250
4317
  // and is determined by interdependencies of modules
4251
- start$s();
4252
- start$n();
4253
- start$o();
4254
- start$b();
4255
- start$4();
4318
+ start$v();
4319
+ start$q();
4256
4320
  start$r();
4321
+ start$e();
4322
+ start$4();
4323
+ start$u();
4257
4324
  }
4258
4325
  function stop$3() {
4259
- stop$m();
4260
- stop$n();
4261
- stop$a();
4262
4326
  stop$p();
4327
+ stop$q();
4328
+ stop$d();
4329
+ stop$s();
4263
4330
  end();
4264
4331
  }
4265
4332
 
@@ -4344,7 +4411,7 @@ function start$2() {
4344
4411
  }
4345
4412
  }
4346
4413
  else {
4347
- log(3 /* PerformanceObserver */, 0 /* Info */);
4414
+ log$1(3 /* PerformanceObserver */, 0 /* Info */);
4348
4415
  }
4349
4416
  }
4350
4417
  function observe() {
@@ -4372,7 +4439,7 @@ function observe() {
4372
4439
  }
4373
4440
  }
4374
4441
  catch (_a) {
4375
- log(3 /* PerformanceObserver */, 1 /* Warning */);
4442
+ log$1(3 /* PerformanceObserver */, 1 /* Warning */);
4376
4443
  }
4377
4444
  }
4378
4445
  function handle(entries) {
@@ -4387,7 +4454,7 @@ function process(entries) {
4387
4454
  compute(entry);
4388
4455
  break;
4389
4456
  case "resource" /* Resource */:
4390
- log$1(4 /* NetworkHosts */, host(entry.name));
4457
+ log(4 /* NetworkHosts */, host(entry.name));
4391
4458
  break;
4392
4459
  case "longtask" /* LongTask */:
4393
4460
  count$1(7 /* LongTaskCount */);
@@ -4445,7 +4512,7 @@ function start(config$1) {
4445
4512
  if (check()) {
4446
4513
  config(config$1);
4447
4514
  start$6();
4448
- start$u();
4515
+ start$x();
4449
4516
  modules.forEach(function (x) { return measure(x.start)(); });
4450
4517
  }
4451
4518
  }
@@ -4471,7 +4538,7 @@ function stop() {
4471
4538
  if (active()) {
4472
4539
  // Stop modules in the reverse order of their initialization
4473
4540
  modules.slice().reverse().forEach(function (x) { return measure(x.stop)(); });
4474
- stop$r();
4541
+ stop$u();
4475
4542
  stop$5();
4476
4543
  }
4477
4544
  }
@@ -4488,7 +4555,7 @@ var clarity = /*#__PURE__*/Object.freeze({
4488
4555
  identify: identify,
4489
4556
  set: set,
4490
4557
  upgrade: upgrade,
4491
- metadata: metadata$1
4558
+ metadata: metadata
4492
4559
  });
4493
4560
 
4494
4561
  var helper = { hash: hash, selector: selector, get: get, getNode: getNode, lookup: lookup };