@openreplay/tracker 15.0.2 → 15.0.5-beta.0

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/dist/cjs/index.js CHANGED
@@ -2330,7 +2330,7 @@ const containerStyle = {
2330
2330
  alignItems: 'center',
2331
2331
  padding: '1.5rem',
2332
2332
  borderRadius: '2px',
2333
- border: '1px solid #D9D9D9',
2333
+ border: '1px solid rgb(255 255 255 / var(--tw-bg-opacity, 1))',
2334
2334
  background: '#FFF',
2335
2335
  width: '22rem',
2336
2336
  };
@@ -2342,7 +2342,7 @@ const containerWidgetStyle = {
2342
2342
  padding: 'unset',
2343
2343
  fontFamily: `-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"`,
2344
2344
  'border-radius': '2px',
2345
- border: '1px solid #D9D9D9',
2345
+ border: '1px solid rgb(255 255 255 / var(--tw-bg-opacity, 1))',
2346
2346
  background: 'rgba(255, 255, 255, 0.75)',
2347
2347
  width: '22rem',
2348
2348
  };
@@ -2424,7 +2424,7 @@ const descriptionWidgetStyle = {
2424
2424
  boxSizing: 'border-box',
2425
2425
  display: 'block',
2426
2426
  width: '100%',
2427
- borderBottom: '1px solid #D9D9D9',
2427
+ borderBottom: '1px solid rgb(255 255 255 / var(--tw-bg-opacity, 1))',
2428
2428
  background: '#FFF',
2429
2429
  padding: '0.65rem',
2430
2430
  alignSelf: 'stretch',
@@ -3297,7 +3297,10 @@ function isNode(sth) {
3297
3297
  return !!sth && sth.nodeType != null;
3298
3298
  }
3299
3299
  function isSVGElement(node) {
3300
- return node.namespaceURI === 'http://www.w3.org/2000/svg';
3300
+ return (node.namespaceURI === 'http://www.w3.org/2000/svg' || node.localName === 'svg');
3301
+ }
3302
+ function isUseElement(node) {
3303
+ return node.localName === 'use';
3301
3304
  }
3302
3305
  function isElementNode(node) {
3303
3306
  return node.nodeType === Node.ELEMENT_NODE;
@@ -3727,6 +3730,48 @@ class Nodes {
3727
3730
  }
3728
3731
  }
3729
3732
 
3733
+ const iconCache = {};
3734
+ const domParser = new DOMParser();
3735
+ async function parseUseEl(useElement, mode) {
3736
+ try {
3737
+ const href = useElement.getAttribute('xlink:href') || useElement.getAttribute('href');
3738
+ if (!href) {
3739
+ console.debug('Openreplay: xlink:href or href not found on <use>.');
3740
+ return;
3741
+ }
3742
+ const [url, symbolId] = href.split('#');
3743
+ if (!url || !symbolId) {
3744
+ console.debug('Openreplay: Invalid xlink:href or href found on <use>.');
3745
+ return;
3746
+ }
3747
+ if (iconCache[symbolId]) {
3748
+ return iconCache[symbolId];
3749
+ }
3750
+ const response = await fetch(url);
3751
+ const svgText = await response.text();
3752
+ const svgDoc = domParser.parseFromString(svgText, 'image/svg+xml');
3753
+ const symbol = svgDoc.getElementById(symbolId);
3754
+ if (!symbol) {
3755
+ console.debug('Openreplay: Symbol not found in SVG.');
3756
+ return;
3757
+ }
3758
+ if (mode === 'inline') ;
3759
+ if (mode === 'svgtext') {
3760
+ const inlineSvg = `
3761
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="${symbol.getAttribute('viewBox') || '0 0 24 24'}">
3762
+ ${symbol.innerHTML}
3763
+ </svg>
3764
+ `.trim();
3765
+ iconCache[symbolId] = inlineSvg;
3766
+ return inlineSvg;
3767
+ }
3768
+ if (mode === 'dataurl') ;
3769
+ console.debug(`Openreplay: Unknown mode: ${mode}. Use "inline" or "dataurl".`);
3770
+ }
3771
+ catch (error) {
3772
+ console.error('Openreplay: Error processing <use> element:', error);
3773
+ }
3774
+ }
3730
3775
  function isIgnored(node) {
3731
3776
  if (isCommentNode(node)) {
3732
3777
  return true;
@@ -3865,7 +3910,19 @@ class Observer {
3865
3910
  if (value === null) {
3866
3911
  this.app.send(RemoveNodeAttribute(id, name));
3867
3912
  }
3868
- else if (name === 'href') {
3913
+ if (isUseElement(node) && name === 'href') {
3914
+ parseUseEl(node, 'svgtext')
3915
+ .then((svgData) => {
3916
+ if (svgData) {
3917
+ this.app.send(SetNodeAttribute(id, name, `_$OPENREPLAY_SPRITE$_${svgData}`));
3918
+ }
3919
+ })
3920
+ .catch((e) => {
3921
+ console.error('Openreplay: Error parsing <use> element:', e);
3922
+ });
3923
+ return;
3924
+ }
3925
+ if (name === 'href') {
3869
3926
  if (value.length > 1e5) {
3870
3927
  value = '';
3871
3928
  }
@@ -4648,7 +4705,7 @@ class App {
4648
4705
  this.stopCallbacks = [];
4649
4706
  this.commitCallbacks = [];
4650
4707
  this.activityState = ActivityState.NotActive;
4651
- this.version = '15.0.2'; // TODO: version compatability check inside each plugin.
4708
+ this.version = '15.0.5-beta.0'; // TODO: version compatability check inside each plugin.
4652
4709
  this.socketMode = false;
4653
4710
  this.compressionThreshold = 24 * 1000;
4654
4711
  this.bc = null;
@@ -4994,6 +5051,9 @@ class App {
4994
5051
  const host = location.hostname.split('.').slice(-2).join('_');
4995
5052
  this.bc = new BroadcastChannel(`rick_${host}`);
4996
5053
  }
5054
+ else if (this.options.forceSingleTab) {
5055
+ this.allowAppStart();
5056
+ }
4997
5057
  this.revID = this.options.revID;
4998
5058
  this.localStorage = this.options.localStorage ?? window.localStorage;
4999
5059
  this.sessionStorage = this.options.sessionStorage ?? window.sessionStorage;
@@ -6678,122 +6738,170 @@ function Input (app, opts) {
6678
6738
  // License: MIT
6679
6739
  // Author: Anton Medvedev <anton@medv.io>
6680
6740
  // Source: https://github.com/antonmedv/finder
6681
- let config;
6682
- let rootDocument;
6683
- let start;
6741
+ const acceptedAttrNames = new Set(['role', 'name', 'aria-label', 'rel', 'href']);
6742
+ /** Check if attribute name and value are word-like. */
6743
+ function attr(name, value) {
6744
+ let nameIsOk = acceptedAttrNames.has(name);
6745
+ nameIsOk ||= name.startsWith('data-') && wordLike(name);
6746
+ let valueIsOk = wordLike(value) && value.length < 100;
6747
+ valueIsOk ||= value.startsWith('#') && wordLike(value.slice(1));
6748
+ return nameIsOk && valueIsOk;
6749
+ }
6750
+ /** Check if id name is word-like. */
6751
+ function idName(name) {
6752
+ return wordLike(name);
6753
+ }
6754
+ /** Check if class name is word-like. */
6755
+ function className(name) {
6756
+ return wordLike(name);
6757
+ }
6758
+ /** Check if tag name is word-like. */
6759
+ function tagName(name) {
6760
+ return true;
6761
+ }
6762
+ /** Finds unique CSS selectors for the given element. */
6684
6763
  function finder(input, options) {
6685
- start = new Date();
6686
6764
  if (input.nodeType !== Node.ELEMENT_NODE) {
6687
6765
  throw new Error(`Can't generate CSS selector for non-element node type.`);
6688
6766
  }
6689
- if ('html' === input.tagName.toLowerCase()) {
6767
+ if (input.tagName.toLowerCase() === 'html') {
6690
6768
  return 'html';
6691
6769
  }
6692
6770
  const defaults = {
6693
6771
  root: document.body,
6694
- idName: (name) => true,
6695
- className: (name) => true,
6696
- tagName: (name) => true,
6697
- attr: (name, value) => false,
6698
- seedMinLength: 1,
6772
+ idName: idName,
6773
+ className: className,
6774
+ tagName: tagName,
6775
+ attr: attr,
6776
+ timeoutMs: 1000,
6777
+ seedMinLength: 3,
6699
6778
  optimizedMinLength: 2,
6700
- threshold: 1000,
6701
- maxNumberOfTries: 10000,
6702
- timeoutMs: undefined,
6779
+ maxNumberOfPathChecks: Infinity,
6703
6780
  };
6704
- config = { ...defaults, ...options };
6705
- rootDocument = findRootDocument(config.root, defaults);
6706
- let path = bottomUpSearch(input, 'all', () => bottomUpSearch(input, 'two', () => bottomUpSearch(input, 'one', () => bottomUpSearch(input, 'none'))));
6707
- if (path) {
6708
- const optimized = sort(optimize(path, input));
6709
- if (optimized.length > 0) {
6710
- path = optimized[0];
6781
+ const startTime = new Date();
6782
+ const config = { ...defaults, ...options };
6783
+ const rootDocument = findRootDocument(config.root, defaults);
6784
+ let foundPath;
6785
+ let count = 0;
6786
+ for (const candidate of search(input, config, rootDocument)) {
6787
+ const elapsedTimeMs = new Date().getTime() - startTime.getTime();
6788
+ if (elapsedTimeMs > config.timeoutMs ||
6789
+ count >= config.maxNumberOfPathChecks) {
6790
+ const fPath = fallback(input, rootDocument);
6791
+ if (!fPath) {
6792
+ throw new Error(`Timeout: Can't find a unique selector after ${config.timeoutMs}ms`);
6793
+ }
6794
+ return selector(fPath);
6795
+ }
6796
+ count++;
6797
+ if (unique(candidate, rootDocument)) {
6798
+ foundPath = candidate;
6799
+ break;
6711
6800
  }
6712
- return selector(path);
6713
6801
  }
6714
- else {
6802
+ if (!foundPath) {
6715
6803
  throw new Error(`Selector was not found.`);
6716
6804
  }
6717
- }
6718
- function findRootDocument(rootNode, defaults) {
6719
- if (rootNode.nodeType === Node.DOCUMENT_NODE) {
6720
- return rootNode;
6721
- }
6722
- if (rootNode === defaults.root) {
6723
- return rootNode.ownerDocument;
6805
+ const optimized = [
6806
+ ...optimize(foundPath, input, config, rootDocument, startTime),
6807
+ ];
6808
+ optimized.sort(byPenalty);
6809
+ if (optimized.length > 0) {
6810
+ return selector(optimized[0]);
6724
6811
  }
6725
- return rootNode;
6812
+ return selector(foundPath);
6726
6813
  }
6727
- function bottomUpSearch(input, limit, fallback) {
6728
- let path = null;
6729
- let stack = [];
6814
+ function* search(input, config, rootDocument) {
6815
+ const stack = [];
6816
+ let paths = [];
6730
6817
  let current = input;
6731
6818
  let i = 0;
6732
- while (current) {
6733
- const elapsedTime = new Date().getTime() - start.getTime();
6734
- if (config.timeoutMs !== undefined && elapsedTime > config.timeoutMs) {
6735
- throw new Error(`Timeout: Can't find a unique selector after ${elapsedTime}ms`);
6736
- }
6737
- let level = maybe(id(current)) ||
6738
- maybe(...attr(current)) ||
6739
- maybe(...classNames(current)) ||
6740
- maybe(tagName(current)) || [any()];
6741
- const nth = index(current);
6742
- if (limit == 'all') {
6743
- if (nth) {
6744
- level = level.concat(level.filter(dispensableNth).map((node) => nthChild(node, nth)));
6745
- }
6746
- }
6747
- else if (limit == 'two') {
6748
- level = level.slice(0, 1);
6749
- if (nth) {
6750
- level = level.concat(level.filter(dispensableNth).map((node) => nthChild(node, nth)));
6751
- }
6752
- }
6753
- else if (limit == 'one') {
6754
- const [node] = (level = level.slice(0, 1));
6755
- if (nth && dispensableNth(node)) {
6756
- level = [nthChild(node, nth)];
6757
- }
6758
- }
6759
- else if (limit == 'none') {
6760
- level = [any()];
6761
- if (nth) {
6762
- level = [nthChild(level[0], nth)];
6763
- }
6764
- }
6765
- for (let node of level) {
6819
+ while (current && current !== rootDocument) {
6820
+ const level = tie(current, config);
6821
+ for (const node of level) {
6766
6822
  node.level = i;
6767
6823
  }
6768
6824
  stack.push(level);
6769
- if (stack.length >= config.seedMinLength) {
6770
- path = findUniquePath(stack, fallback);
6771
- if (path) {
6772
- break;
6773
- }
6774
- }
6775
6825
  current = current.parentElement;
6776
6826
  i++;
6827
+ paths.push(...combinations(stack));
6828
+ if (i >= config.seedMinLength) {
6829
+ paths.sort(byPenalty);
6830
+ for (const candidate of paths) {
6831
+ yield candidate;
6832
+ }
6833
+ paths = [];
6834
+ }
6777
6835
  }
6778
- if (!path) {
6779
- path = findUniquePath(stack, fallback);
6836
+ paths.sort(byPenalty);
6837
+ for (const candidate of paths) {
6838
+ yield candidate;
6780
6839
  }
6781
- if (!path && fallback) {
6782
- return fallback();
6840
+ }
6841
+ function wordLike(name) {
6842
+ if (/^[a-z\-]{3,}$/i.test(name)) {
6843
+ const words = name.split(/-|[A-Z]/);
6844
+ for (const word of words) {
6845
+ if (word.length <= 2) {
6846
+ return false;
6847
+ }
6848
+ if (/[^aeiou]{4,}/i.test(word)) {
6849
+ return false;
6850
+ }
6851
+ }
6852
+ return true;
6783
6853
  }
6784
- return path;
6854
+ return false;
6785
6855
  }
6786
- function findUniquePath(stack, fallback) {
6787
- const paths = sort(combinations(stack));
6788
- if (paths.length > config.threshold) {
6789
- return fallback ? fallback() : null;
6856
+ function tie(element, config) {
6857
+ const level = [];
6858
+ const elementId = element.getAttribute('id');
6859
+ if (elementId && config.idName(elementId)) {
6860
+ level.push({
6861
+ name: '#' + CSS.escape(elementId),
6862
+ penalty: 0,
6863
+ });
6790
6864
  }
6791
- for (let candidate of paths) {
6792
- if (unique(candidate)) {
6793
- return candidate;
6865
+ for (let i = 0; i < element.classList.length; i++) {
6866
+ const name = element.classList[i];
6867
+ if (config.className(name)) {
6868
+ level.push({
6869
+ name: '.' + CSS.escape(name),
6870
+ penalty: 1,
6871
+ });
6794
6872
  }
6795
6873
  }
6796
- return null;
6874
+ for (let i = 0; i < element.attributes.length; i++) {
6875
+ const attr = element.attributes[i];
6876
+ if (config.attr(attr.name, attr.value)) {
6877
+ level.push({
6878
+ name: `[${CSS.escape(attr.name)}="${CSS.escape(attr.value)}"]`,
6879
+ penalty: 2,
6880
+ });
6881
+ }
6882
+ }
6883
+ const tagName = element.tagName.toLowerCase();
6884
+ if (config.tagName(tagName)) {
6885
+ level.push({
6886
+ name: tagName,
6887
+ penalty: 5,
6888
+ });
6889
+ const index = indexOf(element, tagName);
6890
+ if (index !== undefined) {
6891
+ level.push({
6892
+ name: nthOfType(tagName, index),
6893
+ penalty: 10,
6894
+ });
6895
+ }
6896
+ }
6897
+ const nth = indexOf(element);
6898
+ if (nth !== undefined) {
6899
+ level.push({
6900
+ name: nthChild(tagName, nth),
6901
+ penalty: 50,
6902
+ });
6903
+ }
6904
+ return level;
6797
6905
  }
6798
6906
  function selector(path) {
6799
6907
  let node = path[0];
@@ -6813,69 +6921,23 @@ function selector(path) {
6813
6921
  function penalty(path) {
6814
6922
  return path.map((node) => node.penalty).reduce((acc, i) => acc + i, 0);
6815
6923
  }
6816
- function unique(path) {
6817
- const css = selector(path);
6818
- switch (rootDocument.querySelectorAll(css).length) {
6819
- case 0:
6820
- throw new Error(`Can't select any node with this selector: ${css}`);
6821
- case 1:
6822
- return true;
6823
- default:
6824
- return false;
6825
- }
6826
- }
6827
- function id(input) {
6828
- const elementId = input.getAttribute('id');
6829
- if (elementId && config.idName(elementId)) {
6830
- return {
6831
- name: '#' + CSS.escape(elementId),
6832
- penalty: 0,
6833
- };
6834
- }
6835
- return null;
6836
- }
6837
- function attr(input) {
6838
- const attrs = Array.from(input.attributes).filter((attr) => config.attr(attr.name, attr.value));
6839
- return attrs.map((attr) => ({
6840
- name: `[${CSS.escape(attr.name)}="${CSS.escape(attr.value)}"]`,
6841
- penalty: 0.5,
6842
- }));
6843
- }
6844
- function classNames(input) {
6845
- const names = Array.from(input.classList).filter(config.className);
6846
- return names.map((name) => ({
6847
- name: '.' + CSS.escape(name),
6848
- penalty: 1,
6849
- }));
6850
- }
6851
- function tagName(input) {
6852
- const name = input.tagName.toLowerCase();
6853
- if (config.tagName(name)) {
6854
- return {
6855
- name,
6856
- penalty: 2,
6857
- };
6858
- }
6859
- return null;
6860
- }
6861
- function any() {
6862
- return {
6863
- name: '*',
6864
- penalty: 3,
6865
- };
6924
+ function byPenalty(a, b) {
6925
+ return penalty(a) - penalty(b);
6866
6926
  }
6867
- function index(input) {
6927
+ function indexOf(input, tagName) {
6868
6928
  const parent = input.parentNode;
6869
6929
  if (!parent) {
6870
- return null;
6930
+ return undefined;
6871
6931
  }
6872
6932
  let child = parent.firstChild;
6873
6933
  if (!child) {
6874
- return null;
6934
+ return undefined;
6875
6935
  }
6876
6936
  let i = 0;
6877
6937
  while (child) {
6878
- if (child.nodeType === Node.ELEMENT_NODE) {
6938
+ if (child.nodeType === Node.ELEMENT_NODE &&
6939
+ (tagName === undefined ||
6940
+ child.tagName.toLowerCase() === tagName)) {
6879
6941
  i++;
6880
6942
  }
6881
6943
  if (child === input) {
@@ -6885,24 +6947,39 @@ function index(input) {
6885
6947
  }
6886
6948
  return i;
6887
6949
  }
6888
- function nthChild(node, i) {
6889
- return {
6890
- name: node.name + `:nth-child(${i})`,
6891
- penalty: node.penalty + 1,
6892
- };
6893
- }
6894
- function dispensableNth(node) {
6895
- return node.name !== 'html' && !node.name.startsWith('#');
6950
+ function fallback(input, rootDocument) {
6951
+ let i = 0;
6952
+ let current = input;
6953
+ const path = [];
6954
+ while (current && current !== rootDocument) {
6955
+ const tagName = current.tagName.toLowerCase();
6956
+ const index = indexOf(current, tagName);
6957
+ if (index === undefined) {
6958
+ return;
6959
+ }
6960
+ path.push({
6961
+ name: nthOfType(tagName, index),
6962
+ penalty: NaN,
6963
+ level: i,
6964
+ });
6965
+ current = current.parentElement;
6966
+ i++;
6967
+ }
6968
+ if (unique(path, rootDocument)) {
6969
+ return path;
6970
+ }
6896
6971
  }
6897
- function maybe(...level) {
6898
- const list = level.filter(notEmpty);
6899
- if (list.length > 0) {
6900
- return list;
6972
+ function nthChild(tagName, index) {
6973
+ if (tagName === 'html') {
6974
+ return 'html';
6901
6975
  }
6902
- return null;
6976
+ return `${tagName}:nth-child(${index})`;
6903
6977
  }
6904
- function notEmpty(value) {
6905
- return value !== null && value !== undefined;
6978
+ function nthOfType(tagName, index) {
6979
+ if (tagName === 'html') {
6980
+ return 'html';
6981
+ }
6982
+ return `${tagName}:nth-of-type(${index})`;
6906
6983
  }
6907
6984
  function* combinations(stack, path = []) {
6908
6985
  if (stack.length > 0) {
@@ -6914,44 +6991,50 @@ function* combinations(stack, path = []) {
6914
6991
  yield path;
6915
6992
  }
6916
6993
  }
6917
- function sort(paths) {
6918
- return [...paths].sort((a, b) => penalty(a) - penalty(b));
6994
+ function findRootDocument(rootNode, defaults) {
6995
+ if (rootNode.nodeType === Node.DOCUMENT_NODE) {
6996
+ return rootNode;
6997
+ }
6998
+ if (rootNode === defaults.root) {
6999
+ return rootNode.ownerDocument;
7000
+ }
7001
+ return rootNode;
7002
+ }
7003
+ function unique(path, rootDocument) {
7004
+ const css = selector(path);
7005
+ switch (rootDocument.querySelectorAll(css).length) {
7006
+ case 0:
7007
+ throw new Error(`Can't select any node with this selector: ${css}`);
7008
+ case 1:
7009
+ return true;
7010
+ default:
7011
+ return false;
7012
+ }
6919
7013
  }
6920
- function* optimize(path, input, scope = {
6921
- counter: 0,
6922
- visited: new Map(),
6923
- }) {
7014
+ function* optimize(path, input, config, rootDocument, startTime) {
6924
7015
  if (path.length > 2 && path.length > config.optimizedMinLength) {
6925
7016
  for (let i = 1; i < path.length - 1; i++) {
6926
- if (scope.counter > config.maxNumberOfTries) {
6927
- return; // Okay At least I tried!
7017
+ const elapsedTimeMs = new Date().getTime() - startTime.getTime();
7018
+ if (elapsedTimeMs > config.timeoutMs) {
7019
+ return;
6928
7020
  }
6929
- scope.counter += 1;
6930
7021
  const newPath = [...path];
6931
7022
  newPath.splice(i, 1);
6932
- const newPathKey = selector(newPath);
6933
- if (scope.visited.has(newPathKey)) {
6934
- return;
6935
- }
6936
- if (unique(newPath) && same(newPath, input)) {
7023
+ if (unique(newPath, rootDocument) &&
7024
+ rootDocument.querySelector(selector(newPath)) === input) {
6937
7025
  yield newPath;
6938
- scope.visited.set(newPathKey, true);
6939
- yield* optimize(newPath, input, scope);
7026
+ yield* optimize(newPath, input, config, rootDocument, startTime);
6940
7027
  }
6941
7028
  }
6942
7029
  }
6943
7030
  }
6944
- function same(path, input) {
6945
- return rootDocument.querySelector(selector(path)) === input;
6946
- }
6947
7031
 
6948
7032
  function _getSelector(target, document, options) {
6949
7033
  const selector = finder(target, {
6950
7034
  root: document.body,
6951
7035
  seedMinLength: 3,
6952
7036
  optimizedMinLength: options?.minSelectorDepth || 2,
6953
- threshold: options?.nthThreshold || 1000,
6954
- maxNumberOfTries: options?.maxOptimiseTries || 10000,
7037
+ maxNumberOfPathChecks: options?.maxOptimiseTries || 10000,
6955
7038
  });
6956
7039
  return selector;
6957
7040
  }
@@ -7218,6 +7301,11 @@ function Timing (app, opts) {
7218
7301
  if (shouldSkip) {
7219
7302
  return;
7220
7303
  }
7304
+ const failed = entry.responseEnd === 0
7305
+ || (entry.transferSize === 0 && entry.decodedBodySize === 0);
7306
+ if (failed) {
7307
+ app.send(ResourceTiming(entry.startTime + getTimeOrigin(), 0, 0, 0, 0, 0, entry.name, entry.initiatorType, 0, true));
7308
+ }
7221
7309
  app.send(ResourceTiming(entry.startTime + getTimeOrigin(), entry.duration, entry.responseStart && entry.startTime ? entry.responseStart - entry.startTime : 0, entry.transferSize > entry.encodedBodySize ? entry.transferSize - entry.encodedBodySize : 0, entry.encodedBodySize || 0, entry.decodedBodySize || 0, entry.name, entry.initiatorType, entry.transferSize,
7222
7310
  // @ts-ignore
7223
7311
  (entry.responseStatus && entry.responseStatus === 304) || entry.transferSize === 0));
@@ -8809,6 +8897,9 @@ function Network (app, opts = {}) {
8809
8897
  /* ====== modern way ====== */
8810
8898
  if (options.useProxy) {
8811
8899
  return createNetworkProxy(context, options.ignoreHeaders, setSessionTokenHeader, sanitize, (message) => {
8900
+ if (options.failuresOnly && message.status < 400) {
8901
+ return;
8902
+ }
8812
8903
  app.send(NetworkRequest(message.requestType, message.method, message.url, message.request, message.response, message.status, message.startTime + getTimeOrigin(), message.duration, message.responseSize));
8813
8904
  }, (url) => app.isServiceURL(url), { xhr: true, fetch: true, beacon: true }, options.tokenUrlMatcher);
8814
8905
  }
@@ -9065,11 +9156,8 @@ class API {
9065
9156
  };
9066
9157
  this.signalStartIssue = (reason, missingApi) => {
9067
9158
  const doNotTrack = this.checkDoNotTrack();
9068
- const req = new XMLHttpRequest();
9069
- const orig = this.options.ingestPoint || DEFAULT_INGEST_POINT;
9070
- req.open('POST', orig + '/v1/web/not-started');
9071
- req.send(JSON.stringify({
9072
- trackerVersion: '15.0.2',
9159
+ console.log("Tracker couldn't start due to:", JSON.stringify({
9160
+ trackerVersion: '15.0.5-beta.0',
9073
9161
  projectKey: this.options.projectKey,
9074
9162
  doNotTrack,
9075
9163
  reason: missingApi.length ? `missing api: ${missingApi.join(',')}` : reason,