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