clarity-js 0.6.39 → 0.6.41

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/build/clarity.js CHANGED
@@ -92,7 +92,8 @@ var config$1 = {
92
92
  report: null,
93
93
  upload: null,
94
94
  fallback: null,
95
- upgrade: null
95
+ upgrade: null,
96
+ action: null
96
97
  };
97
98
 
98
99
  function api(method) {
@@ -115,7 +116,7 @@ function stop$B() {
115
116
  startTime = 0;
116
117
  }
117
118
 
118
- var version$1 = "0.6.39";
119
+ var version$1 = "0.6.41";
119
120
 
120
121
  // tslint:disable: no-bitwise
121
122
  function hash (input) {
@@ -142,9 +143,9 @@ var buffer = null;
142
143
  var update$2 = false;
143
144
  function start$E() {
144
145
  update$2 = false;
145
- reset$o();
146
+ reset$p();
146
147
  }
147
- function reset$o() {
148
+ function reset$p() {
148
149
  // Baseline state holds the previous values - if it is updated in the current payload,
149
150
  // reset the state to current value after sending the previous state
150
151
  if (update$2) {
@@ -212,14 +213,14 @@ function compute$c() {
212
213
  }
213
214
  }
214
215
  function stop$A() {
215
- reset$o();
216
+ reset$p();
216
217
  }
217
218
 
218
219
  var baseline = /*#__PURE__*/Object.freeze({
219
220
  __proto__: null,
220
221
  get state () { return state$9; },
221
222
  start: start$E,
222
- reset: reset$o,
223
+ reset: reset$p,
223
224
  track: track$7,
224
225
  activity: activity,
225
226
  visibility: visibility,
@@ -289,7 +290,7 @@ function max(metric, value) {
289
290
  function compute$b() {
290
291
  encode$1(0 /* Event.Metric */);
291
292
  }
292
- function reset$n() {
293
+ function reset$o() {
293
294
  updates$3 = {};
294
295
  }
295
296
 
@@ -308,7 +309,7 @@ function start$C() {
308
309
  interval = 60000 /* Setting.PingInterval */;
309
310
  last = 0;
310
311
  }
311
- function reset$m() {
312
+ function reset$n() {
312
313
  if (timeout$6) {
313
314
  clearTimeout(timeout$6);
314
315
  }
@@ -336,7 +337,7 @@ var ping$1 = /*#__PURE__*/Object.freeze({
336
337
  __proto__: null,
337
338
  get data () { return data$h; },
338
339
  start: start$C,
339
- reset: reset$m,
340
+ reset: reset$n,
340
341
  stop: stop$y
341
342
  });
342
343
 
@@ -367,7 +368,7 @@ function track$6(event, time) {
367
368
  function compute$a() {
368
369
  encode$1(36 /* Event.Summary */);
369
370
  }
370
- function reset$l() {
371
+ function reset$m() {
371
372
  data$g = {};
372
373
  }
373
374
 
@@ -378,7 +379,7 @@ var summary = /*#__PURE__*/Object.freeze({
378
379
  stop: stop$x,
379
380
  track: track$6,
380
381
  compute: compute$a,
381
- reset: reset$l
382
+ reset: reset$m
382
383
  });
383
384
 
384
385
  var data$f = null;
@@ -420,7 +421,7 @@ var upgrade$1 = /*#__PURE__*/Object.freeze({
420
421
 
421
422
  var data$e = null;
422
423
  function start$z() {
423
- reset$k();
424
+ reset$l();
424
425
  }
425
426
  function set(variable, value) {
426
427
  var values = typeof value === "string" /* Constant.String */ ? [value] : value;
@@ -451,11 +452,11 @@ function log$2(variable, value) {
451
452
  function compute$9() {
452
453
  encode$1(34 /* Event.Variable */);
453
454
  }
454
- function reset$k() {
455
+ function reset$l() {
455
456
  data$e = {};
456
457
  }
457
458
  function stop$v() {
458
- reset$k();
459
+ reset$l();
459
460
  }
460
461
 
461
462
  var variable = /*#__PURE__*/Object.freeze({
@@ -465,7 +466,7 @@ var variable = /*#__PURE__*/Object.freeze({
465
466
  set: set,
466
467
  identify: identify,
467
468
  compute: compute$9,
468
- reset: reset$k,
469
+ reset: reset$l,
469
470
  stop: stop$v
470
471
  });
471
472
 
@@ -705,7 +706,7 @@ function redact(value) {
705
706
  // Check if unicode regex is supported, otherwise fallback to calling mask function on this token
706
707
  if (unicodeRegex && currencyRegex !== null) {
707
708
  // Do not redact information if the token contains a currency symbol
708
- token = token.match(currencyRegex) ? token : token.replace(letterRegex, "\u2022" /* Data.Constant.Letter */).replace(digitRegex, "\u2022" /* Data.Constant.Digit */);
709
+ token = token.match(currencyRegex) ? token : token.replace(letterRegex, "\u25AA" /* Data.Constant.Letter */).replace(digitRegex, "\u25AB" /* Data.Constant.Digit */);
709
710
  }
710
711
  else {
711
712
  token = mask(token);
@@ -743,12 +744,15 @@ function check$4(id, target, input) {
743
744
  }
744
745
  }
745
746
 
746
- var TAGS = ["DIV", "TR", "P", "LI", "UL", "A", "BUTTON"];
747
- function selector (input, beta) {
748
- if (beta === void 0) { beta = false; }
747
+ var excludeClassNames = "load,active,fixed,visible,focus,show,collaps,animat" /* Constant.ExcludeClassNames */.split("," /* Constant.Comma */);
748
+ var selectorMap = {};
749
+ function reset$k() {
750
+ selectorMap = {};
751
+ }
752
+ function get$1(input, type) {
749
753
  var a = input.attributes;
750
- var prefix = input.prefix ? input.prefix[beta ? 1 /* Selector.Beta */ : 0 /* Selector.Stable */] : null;
751
- var suffix = beta || ((a && !("class" /* Constant.Class */ in a)) || TAGS.indexOf(input.tag) >= 0) ? ":nth-of-type(".concat(input.position, ")") : "" /* Constant.Empty */;
754
+ var prefix = input.prefix ? input.prefix[type] : null;
755
+ var suffix = type === 0 /* Selector.Alpha */ ? "".concat("~" /* Constant.Tilde */).concat(input.position - 1) : ":nth-of-type(".concat(input.position, ")");
752
756
  switch (input.tag) {
753
757
  case "STYLE":
754
758
  case "TITLE":
@@ -763,23 +767,33 @@ function selector (input, beta) {
763
767
  if (prefix === null) {
764
768
  return "" /* Constant.Empty */;
765
769
  }
766
- prefix = "".concat(prefix, ">");
770
+ prefix = "".concat(prefix).concat(">" /* Constant.Separator */);
767
771
  input.tag = input.tag.indexOf("svg:" /* Constant.SvgPrefix */) === 0 ? input.tag.substr("svg:" /* Constant.SvgPrefix */.length) : input.tag;
768
772
  var selector = "".concat(prefix).concat(input.tag).concat(suffix);
769
- var classes = "class" /* Constant.Class */ in a && a["class" /* Constant.Class */].length > 0 ? a["class" /* Constant.Class */].trim().split(/\s+/) : null;
770
- if (beta) {
771
- // In beta mode, update selector to use "id" field when available. There are two exceptions:
772
- // (1) if "id" appears to be an auto generated string token, e.g. guid or a random id containing digits
773
- // (2) if "id" appears inside a shadow DOM, in which case we continue to prefix up to shadow DOM to prevent conflicts
774
- var id = "id" /* Constant.Id */ in a && a["id" /* Constant.Id */].length > 0 ? a["id" /* Constant.Id */] : null;
775
- classes = input.tag !== "BODY" /* Constant.BodyTag */ && classes ? classes.filter(function (c) { return !hasDigits(c); }) : [];
776
- selector = classes.length > 0 ? "".concat(prefix).concat(input.tag, ".").concat(classes.join(".")).concat(suffix) : selector;
777
- selector = id && hasDigits(id) === false ? "".concat(getDomPrefix(prefix), "#").concat(id) : selector;
778
- }
779
- else {
780
- // Otherwise, fallback to stable mode, where we include class names as part of the selector
781
- selector = classes ? "".concat(prefix).concat(input.tag, ".").concat(classes.join(".")).concat(suffix) : selector;
773
+ var id = "id" /* Constant.Id */ in a && a["id" /* Constant.Id */].length > 0 ? a["id" /* Constant.Id */] : null;
774
+ var classes = input.tag !== "BODY" /* Constant.BodyTag */ && "class" /* Constant.Class */ in a && a["class" /* Constant.Class */].length > 0 ? a["class" /* Constant.Class */].trim().split(/\s+/).filter(function (c) { return filter(c); }).join("." /* Constant.Period */) : null;
775
+ if (classes && classes.length > 0) {
776
+ if (type === 0 /* Selector.Alpha */) {
777
+ // In Alpha mode, update selector to use class names, with relative positioning within the parent id container.
778
+ // If the node has valid class name(s) then drop relative positioning within the parent path to keep things simple.
779
+ var key = "".concat(getDomPath(prefix)).concat(input.tag).concat("." /* Constant.Dot */).concat(classes);
780
+ if (!(key in selectorMap)) {
781
+ selectorMap[key] = [];
782
+ }
783
+ if (selectorMap[key].indexOf(input.id) < 0) {
784
+ selectorMap[key].push(input.id);
785
+ }
786
+ selector = "".concat(key).concat("~" /* Constant.Tilde */).concat(selectorMap[key].indexOf(input.id));
787
+ }
788
+ else {
789
+ // In Beta mode, we continue to look at query selectors in context of the full page
790
+ selector = "".concat(prefix).concat(input.tag, ".").concat(classes).concat(suffix);
791
+ }
782
792
  }
793
+ // Update selector to use "id" field when available. There are two exceptions:
794
+ // (1) if "id" appears to be an auto generated string token, e.g. guid or a random id containing digits
795
+ // (2) if "id" appears inside a shadow DOM, in which case we continue to prefix up to shadow DOM to prevent conflicts
796
+ selector = id && filter(id) ? "".concat(getDomPrefix(prefix)).concat("#" /* Constant.Hash */).concat(id) : selector;
783
797
  return selector;
784
798
  }
785
799
  }
@@ -788,22 +802,42 @@ function getDomPrefix(prefix) {
788
802
  var iframeDomStart = prefix.lastIndexOf("".concat("iframe:" /* Constant.IFramePrefix */).concat("HTML" /* Constant.HTML */));
789
803
  var domStart = Math.max(shadowDomStart, iframeDomStart);
790
804
  if (domStart < 0) {
791
- return "";
805
+ return "" /* Constant.Empty */;
806
+ }
807
+ return prefix.substring(0, prefix.indexOf(">" /* Constant.Separator */, domStart) + 1);
808
+ }
809
+ function getDomPath(input) {
810
+ var parts = input.split(">" /* Constant.Separator */);
811
+ for (var i = 0; i < parts.length; i++) {
812
+ var tIndex = parts[i].indexOf("~" /* Constant.Tilde */);
813
+ var dIndex = parts[i].indexOf("." /* Constant.Dot */);
814
+ parts[i] = parts[i].substring(0, dIndex > 0 ? dIndex : (tIndex > 0 ? tIndex : parts[i].length));
792
815
  }
793
- var domEnd = prefix.indexOf(">", domStart) + 1;
794
- return prefix.substr(0, domEnd);
816
+ return parts.join(">" /* Constant.Separator */);
795
817
  }
796
- // Check if the given input string has digits or not
797
- function hasDigits(value) {
818
+ // Check if the given input string has digits or excluded class names
819
+ function filter(value) {
820
+ if (!value) {
821
+ return false;
822
+ } // Do not process empty strings
823
+ if (excludeClassNames.some(function (x) { return value.toLowerCase().indexOf(x) >= 0; })) {
824
+ return false;
825
+ }
798
826
  for (var i = 0; i < value.length; i++) {
799
827
  var c = value.charCodeAt(i);
800
828
  if (c >= 48 /* Character.Zero */ && c <= 57 /* Character.Nine */) {
801
- return true;
829
+ return false;
802
830
  }
803
831
  }
804
- return false;
832
+ return true;
805
833
  }
806
834
 
835
+ var selector = /*#__PURE__*/Object.freeze({
836
+ __proto__: null,
837
+ reset: reset$k,
838
+ get: get$1
839
+ });
840
+
807
841
  // Track the start time to be able to compute duration at the end of the task
808
842
  var idleTimeout = 5000;
809
843
  var tracker = {};
@@ -1123,7 +1157,7 @@ function encode$4 (type, timer, ts) {
1123
1157
  }
1124
1158
  tokens.push(suspend ? "*M" /* Constant.SuspendMutationTag */ : data[key]);
1125
1159
  if (box && box.length === 2) {
1126
- tokens.push("".concat("#" /* Constant.Box */).concat(str$1(box[0]), ".").concat(str$1(box[1])));
1160
+ tokens.push("".concat("#" /* Constant.Hash */).concat(str$1(box[0]), ".").concat(str$1(box[1])));
1127
1161
  }
1128
1162
  break;
1129
1163
  case "attributes":
@@ -2377,6 +2411,7 @@ function reset$7() {
2377
2411
  iframeMap = new WeakMap();
2378
2412
  privacyMap = new WeakMap();
2379
2413
  fraudMap = new WeakMap();
2414
+ reset$k();
2380
2415
  }
2381
2416
  // We parse new root nodes for any regions or masked nodes in the beginning (document) and
2382
2417
  // later whenever there are new additions or modifications to DOM (mutations)
@@ -2553,14 +2588,11 @@ function privacy(node, value, parent) {
2553
2588
  metadata.privacy = 2 /* Privacy.Text */;
2554
2589
  break;
2555
2590
  case tag === "*T" /* Constant.TextTag */:
2556
- // If it's a text node belonging to a STYLE or TITLE tag or one of SCRUB_EXCEPTIONS, then capture content
2591
+ // If it's a text node belonging to a STYLE or TITLE tag or one of scrub exceptions, then capture content
2557
2592
  var pTag = parent && parent.data ? parent.data.tag : "" /* Constant.Empty */;
2558
- var pSelector_1 = parent && parent.selector ? parent.selector[0 /* Selector.Stable */] : "" /* Constant.Empty */;
2559
- metadata.privacy = pTag === "STYLE" /* Constant.StyleTag */ || pTag === "TITLE" /* Constant.TitleTag */ || override.some(function (x) { return pSelector_1.indexOf(x) >= 0; }) ? 0 /* Privacy.None */ : current;
2560
- break;
2561
- case "type" /* Constant.Type */ in attributes:
2562
- // If this node has an explicit type assigned to it, go through masking rules to determine right privacy setting
2563
- metadata.privacy = inspect(attributes["type" /* Constant.Type */], maskInput, metadata);
2593
+ var pSelector_1 = parent && parent.selector ? parent.selector[1 /* Selector.Default */] : "" /* Constant.Empty */;
2594
+ var tags = ["STYLE" /* Constant.StyleTag */, "TITLE" /* Constant.TitleTag */, "svg:style" /* Constant.SvgStyle */];
2595
+ metadata.privacy = tags.includes(pTag) || override.some(function (x) { return pSelector_1.indexOf(x) >= 0; }) ? 0 /* Privacy.None */ : current;
2564
2596
  break;
2565
2597
  case tag === "INPUT" /* Constant.InputTag */ && current === 0 /* Privacy.None */:
2566
2598
  // If even default privacy setting is to not mask, we still scan through input fields for any sensitive information
@@ -2568,11 +2600,13 @@ function privacy(node, value, parent) {
2568
2600
  Object.keys(attributes).forEach(function (x) { return field_1 += attributes[x].toLowerCase(); });
2569
2601
  metadata.privacy = inspect(field_1, maskInput, metadata);
2570
2602
  break;
2571
- case current === 1 /* Privacy.Sensitive */ && tag === "INPUT" /* Constant.InputTag */:
2603
+ case tag === "INPUT" /* Constant.InputTag */ && current === 1 /* Privacy.Sensitive */:
2572
2604
  // Look through class names to aggressively mask content
2573
2605
  metadata.privacy = inspect(attributes["class" /* Constant.Class */], maskText, metadata);
2574
- // If it's a button or an input option, make an exception to disable masking
2575
- metadata.privacy = maskDisable.indexOf(attributes["type" /* Constant.Type */]) >= 0 ? 0 /* Privacy.None */ : current;
2606
+ // If this node has an explicit type assigned to it, go through masking rules to determine right privacy setting
2607
+ metadata.privacy = inspect(attributes["type" /* Constant.Type */], maskInput, metadata);
2608
+ // If it's a button or an input option, make an exception to disable masking in sensitive mode
2609
+ metadata.privacy = maskDisable.indexOf(attributes["type" /* Constant.Type */]) >= 0 ? 0 /* Privacy.None */ : metadata.privacy;
2576
2610
  break;
2577
2611
  case current === 1 /* Privacy.Sensitive */:
2578
2612
  // In a mode where we mask sensitive information by default, look through class names to aggressively mask content
@@ -2619,10 +2653,11 @@ function updateSelector(value) {
2619
2653
  var prefix = parent ? parent.selector : null;
2620
2654
  var d = value.data;
2621
2655
  var p = position(parent, value);
2622
- var s = { tag: d.tag, prefix: prefix, position: p, attributes: d.attributes };
2623
- value.selector = [selector(s), selector(s, true)];
2656
+ var s = { id: value.id, tag: d.tag, prefix: prefix, position: p, attributes: d.attributes };
2657
+ value.selector = [get$1(s, 0 /* Selector.Alpha */), get$1(s, 1 /* Selector.Beta */)];
2624
2658
  value.hash = value.selector.map(function (x) { return x ? hash(x) : null; });
2625
2659
  value.hash.forEach(function (h) { return hashMap[h] = value.id; });
2660
+ // Match fragment configuration against both alpha and beta hash
2626
2661
  if (value.hash.some(function (h) { return fragments.indexOf(h) !== -1; })) {
2627
2662
  value.fragment = value.id;
2628
2663
  }
@@ -3166,7 +3201,7 @@ function queue(tokens, transmit) {
3166
3201
  // We enrich the data going out with the existing upload. In these cases, call to upload comes with 'transmit' set to false.
3167
3202
  if (transmit && timeout === null) {
3168
3203
  if (type !== 25 /* Event.Ping */) {
3169
- reset$m();
3204
+ reset$n();
3170
3205
  }
3171
3206
  timeout = setTimeout(upload, gap);
3172
3207
  queuedTime = now;
@@ -3356,8 +3391,8 @@ function delay() {
3356
3391
  return typeof config$1.upload === "string" /* Constant.String */ ? Math.max(Math.min(gap, 30000 /* Setting.MaxUploadDelay */), 100 /* Setting.MinUploadDelay */) : config$1.delay;
3357
3392
  }
3358
3393
  function response(payload) {
3359
- var key = payload && payload.length > 0 ? payload.split(" ")[0] : "" /* Constant.Empty */;
3360
- switch (key) {
3394
+ var parts = payload && payload.length > 0 ? payload.split(" ") : ["" /* Constant.Empty */];
3395
+ switch (parts[0]) {
3361
3396
  case "END" /* Constant.End */:
3362
3397
  // Clear out session storage and end the session so we can start fresh the next time
3363
3398
  trigger(6 /* Check.Server */);
@@ -3366,6 +3401,12 @@ function response(payload) {
3366
3401
  // Upgrade current session to send back playback information
3367
3402
  upgrade("Auto" /* Constant.Auto */);
3368
3403
  break;
3404
+ case "ACTION" /* Constant.Action */:
3405
+ // Invoke action callback, if configured and has a valid value
3406
+ if (config$1.action && parts.length > 1) {
3407
+ config$1.action(parts[1]);
3408
+ }
3409
+ break;
3369
3410
  }
3370
3411
  }
3371
3412
 
@@ -3621,7 +3662,7 @@ function encode$1 (event) {
3621
3662
  tokens.push(b.data.activityTime);
3622
3663
  queue(tokens, false);
3623
3664
  }
3624
- reset$o();
3665
+ reset$p();
3625
3666
  break;
3626
3667
  case 25 /* Event.Ping */:
3627
3668
  tokens.push(data$h.gap);
@@ -3654,7 +3695,7 @@ function encode$1 (event) {
3654
3695
  tokens.push(v);
3655
3696
  tokens.push(data$e[v]);
3656
3697
  }
3657
- reset$k();
3698
+ reset$l();
3658
3699
  queue(tokens, false);
3659
3700
  }
3660
3701
  break;
@@ -3669,7 +3710,7 @@ function encode$1 (event) {
3669
3710
  // However, for data over the wire, we round it off to milliseconds precision.
3670
3711
  tokens.push(Math.round(updates$3[m]));
3671
3712
  }
3672
- reset$n();
3713
+ reset$o();
3673
3714
  queue(tokens, false);
3674
3715
  }
3675
3716
  break;
@@ -3695,7 +3736,7 @@ function encode$1 (event) {
3695
3736
  tokens.push(key);
3696
3737
  tokens.push([].concat.apply([], data$g[e]));
3697
3738
  }
3698
- reset$l();
3739
+ reset$m();
3699
3740
  queue(tokens, false);
3700
3741
  }
3701
3742
  break;