@openreplay/tracker 15.0.3 → 15.0.5-beta.1

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
@@ -774,13 +774,10 @@ class ConditionsManager {
774
774
  this.conditions = [];
775
775
  this.hasStarted = false;
776
776
  this.createConditionFromFilter = (filter) => {
777
- if (filter.value.length) {
778
- const resultCondition = mapCondition(filter);
779
- if (resultCondition.type) {
780
- return resultCondition;
781
- }
777
+ const resultCondition = mapCondition(filter);
778
+ if (resultCondition.type) {
779
+ return resultCondition;
782
780
  }
783
- return undefined;
784
781
  };
785
782
  this.durationInt = null;
786
783
  }
@@ -1063,8 +1060,9 @@ const mapCondition = (condition) => {
1063
1060
  con = {
1064
1061
  type: 'session_duration',
1065
1062
  // @ts-ignore
1066
- value: condition.value[0],
1063
+ value: condition.value,
1067
1064
  key: '',
1065
+ operator: 'is',
1068
1066
  };
1069
1067
  break;
1070
1068
  case 'fetchUrl':
@@ -2330,7 +2328,7 @@ const containerStyle = {
2330
2328
  alignItems: 'center',
2331
2329
  padding: '1.5rem',
2332
2330
  borderRadius: '2px',
2333
- border: '1px solid #D9D9D9',
2331
+ border: '1px solid rgb(255 255 255 / var(--tw-bg-opacity, 1))',
2334
2332
  background: '#FFF',
2335
2333
  width: '22rem',
2336
2334
  };
@@ -2342,7 +2340,7 @@ const containerWidgetStyle = {
2342
2340
  padding: 'unset',
2343
2341
  fontFamily: `-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"`,
2344
2342
  'border-radius': '2px',
2345
- border: '1px solid #D9D9D9',
2343
+ border: '1px solid rgb(255 255 255 / var(--tw-bg-opacity, 1))',
2346
2344
  background: 'rgba(255, 255, 255, 0.75)',
2347
2345
  width: '22rem',
2348
2346
  };
@@ -2424,7 +2422,7 @@ const descriptionWidgetStyle = {
2424
2422
  boxSizing: 'border-box',
2425
2423
  display: 'block',
2426
2424
  width: '100%',
2427
- borderBottom: '1px solid #D9D9D9',
2425
+ borderBottom: '1px solid rgb(255 255 255 / var(--tw-bg-opacity, 1))',
2428
2426
  background: '#FFF',
2429
2427
  padding: '0.65rem',
2430
2428
  alignSelf: 'stretch',
@@ -3297,7 +3295,10 @@ function isNode(sth) {
3297
3295
  return !!sth && sth.nodeType != null;
3298
3296
  }
3299
3297
  function isSVGElement(node) {
3300
- return node.namespaceURI === 'http://www.w3.org/2000/svg';
3298
+ return (node.namespaceURI === 'http://www.w3.org/2000/svg' || node.localName === 'svg');
3299
+ }
3300
+ function isUseElement(node) {
3301
+ return node.localName === 'use';
3301
3302
  }
3302
3303
  function isElementNode(node) {
3303
3304
  return node.nodeType === Node.ELEMENT_NODE;
@@ -3727,6 +3728,48 @@ class Nodes {
3727
3728
  }
3728
3729
  }
3729
3730
 
3731
+ const iconCache = {};
3732
+ const domParser = new DOMParser();
3733
+ async function parseUseEl(useElement, mode) {
3734
+ try {
3735
+ const href = useElement.getAttribute('xlink:href') || useElement.getAttribute('href');
3736
+ if (!href) {
3737
+ console.debug('Openreplay: xlink:href or href not found on <use>.');
3738
+ return;
3739
+ }
3740
+ const [url, symbolId] = href.split('#');
3741
+ if (!url || !symbolId) {
3742
+ console.debug('Openreplay: Invalid xlink:href or href found on <use>.');
3743
+ return;
3744
+ }
3745
+ if (iconCache[symbolId]) {
3746
+ return iconCache[symbolId];
3747
+ }
3748
+ const response = await fetch(url);
3749
+ const svgText = await response.text();
3750
+ const svgDoc = domParser.parseFromString(svgText, 'image/svg+xml');
3751
+ const symbol = svgDoc.getElementById(symbolId);
3752
+ if (!symbol) {
3753
+ console.debug('Openreplay: Symbol not found in SVG.');
3754
+ return;
3755
+ }
3756
+ if (mode === 'inline') ;
3757
+ if (mode === 'svgtext') {
3758
+ const inlineSvg = `
3759
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="${symbol.getAttribute('viewBox') || '0 0 24 24'}">
3760
+ ${symbol.innerHTML}
3761
+ </svg>
3762
+ `.trim();
3763
+ iconCache[symbolId] = inlineSvg;
3764
+ return inlineSvg;
3765
+ }
3766
+ if (mode === 'dataurl') ;
3767
+ console.debug(`Openreplay: Unknown mode: ${mode}. Use "inline" or "dataurl".`);
3768
+ }
3769
+ catch (error) {
3770
+ console.error('Openreplay: Error processing <use> element:', error);
3771
+ }
3772
+ }
3730
3773
  function isIgnored(node) {
3731
3774
  if (isCommentNode(node)) {
3732
3775
  return true;
@@ -3865,7 +3908,19 @@ class Observer {
3865
3908
  if (value === null) {
3866
3909
  this.app.send(RemoveNodeAttribute(id, name));
3867
3910
  }
3868
- else if (name === 'href') {
3911
+ if (isUseElement(node) && name === 'href') {
3912
+ parseUseEl(node, 'svgtext')
3913
+ .then((svgData) => {
3914
+ if (svgData) {
3915
+ this.app.send(SetNodeAttribute(id, name, `_$OPENREPLAY_SPRITE$_${svgData}`));
3916
+ }
3917
+ })
3918
+ .catch((e) => {
3919
+ console.error('Openreplay: Error parsing <use> element:', e);
3920
+ });
3921
+ return;
3922
+ }
3923
+ if (name === 'href') {
3869
3924
  if (value.length > 1e5) {
3870
3925
  value = '';
3871
3926
  }
@@ -4648,7 +4703,7 @@ class App {
4648
4703
  this.stopCallbacks = [];
4649
4704
  this.commitCallbacks = [];
4650
4705
  this.activityState = ActivityState.NotActive;
4651
- this.version = '15.0.3'; // TODO: version compatability check inside each plugin.
4706
+ this.version = '15.0.5-beta.1'; // TODO: version compatability check inside each plugin.
4652
4707
  this.socketMode = false;
4653
4708
  this.compressionThreshold = 24 * 1000;
4654
4709
  this.bc = null;
@@ -4920,17 +4975,16 @@ class App {
4920
4975
  };
4921
4976
  this.flushBuffer = async (buffer) => {
4922
4977
  return new Promise((res) => {
4923
- let ended = false;
4924
- const messagesBatch = [buffer.shift()];
4925
- while (!ended) {
4926
- const nextMsg = buffer[0];
4927
- if (!nextMsg || nextMsg[0] === 0 /* MType.Timestamp */) {
4928
- ended = true;
4929
- }
4930
- else {
4931
- messagesBatch.push(buffer.shift());
4932
- }
4978
+ if (buffer.length === 0) {
4979
+ res(null);
4980
+ return;
4981
+ }
4982
+ // Since the first element is always a Timestamp, include it by default.
4983
+ let endIndex = 1;
4984
+ while (endIndex < buffer.length && buffer[endIndex][0] !== 0 /* MType.Timestamp */) {
4985
+ endIndex++;
4933
4986
  }
4987
+ const messagesBatch = buffer.splice(0, endIndex);
4934
4988
  this.postToWorker(messagesBatch);
4935
4989
  res(null);
4936
4990
  });
@@ -4994,6 +5048,9 @@ class App {
4994
5048
  const host = location.hostname.split('.').slice(-2).join('_');
4995
5049
  this.bc = new BroadcastChannel(`rick_${host}`);
4996
5050
  }
5051
+ else if (this.options.forceSingleTab) {
5052
+ this.allowAppStart();
5053
+ }
4997
5054
  this.revID = this.options.revID;
4998
5055
  this.localStorage = this.options.localStorage ?? window.localStorage;
4999
5056
  this.sessionStorage = this.options.sessionStorage ?? window.sessionStorage;
@@ -5311,7 +5368,6 @@ class App {
5311
5368
  postToWorker(messages) {
5312
5369
  this.worker?.postMessage(messages);
5313
5370
  this.commitCallbacks.forEach((cb) => cb(messages));
5314
- messages.length = 0;
5315
5371
  }
5316
5372
  timestamp() {
5317
5373
  return now() + this.delay;
@@ -6678,122 +6734,170 @@ function Input (app, opts) {
6678
6734
  // License: MIT
6679
6735
  // Author: Anton Medvedev <anton@medv.io>
6680
6736
  // Source: https://github.com/antonmedv/finder
6681
- let config;
6682
- let rootDocument;
6683
- let start;
6737
+ const acceptedAttrNames = new Set(['role', 'name', 'aria-label', 'rel', 'href']);
6738
+ /** Check if attribute name and value are word-like. */
6739
+ function attr(name, value) {
6740
+ let nameIsOk = acceptedAttrNames.has(name);
6741
+ nameIsOk ||= name.startsWith('data-') && wordLike(name);
6742
+ let valueIsOk = wordLike(value) && value.length < 100;
6743
+ valueIsOk ||= value.startsWith('#') && wordLike(value.slice(1));
6744
+ return nameIsOk && valueIsOk;
6745
+ }
6746
+ /** Check if id name is word-like. */
6747
+ function idName(name) {
6748
+ return wordLike(name);
6749
+ }
6750
+ /** Check if class name is word-like. */
6751
+ function className(name) {
6752
+ return wordLike(name);
6753
+ }
6754
+ /** Check if tag name is word-like. */
6755
+ function tagName(name) {
6756
+ return true;
6757
+ }
6758
+ /** Finds unique CSS selectors for the given element. */
6684
6759
  function finder(input, options) {
6685
- start = new Date();
6686
6760
  if (input.nodeType !== Node.ELEMENT_NODE) {
6687
6761
  throw new Error(`Can't generate CSS selector for non-element node type.`);
6688
6762
  }
6689
- if ('html' === input.tagName.toLowerCase()) {
6763
+ if (input.tagName.toLowerCase() === 'html') {
6690
6764
  return 'html';
6691
6765
  }
6692
6766
  const defaults = {
6693
6767
  root: document.body,
6694
- idName: (name) => true,
6695
- className: (name) => true,
6696
- tagName: (name) => true,
6697
- attr: (name, value) => false,
6698
- seedMinLength: 1,
6768
+ idName: idName,
6769
+ className: className,
6770
+ tagName: tagName,
6771
+ attr: attr,
6772
+ timeoutMs: 1000,
6773
+ seedMinLength: 3,
6699
6774
  optimizedMinLength: 2,
6700
- threshold: 1000,
6701
- maxNumberOfTries: 10000,
6702
- timeoutMs: undefined,
6775
+ maxNumberOfPathChecks: Infinity,
6703
6776
  };
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];
6777
+ const startTime = new Date();
6778
+ const config = { ...defaults, ...options };
6779
+ const rootDocument = findRootDocument(config.root, defaults);
6780
+ let foundPath;
6781
+ let count = 0;
6782
+ for (const candidate of search(input, config, rootDocument)) {
6783
+ const elapsedTimeMs = new Date().getTime() - startTime.getTime();
6784
+ if (elapsedTimeMs > config.timeoutMs ||
6785
+ count >= config.maxNumberOfPathChecks) {
6786
+ const fPath = fallback(input, rootDocument);
6787
+ if (!fPath) {
6788
+ throw new Error(`Timeout: Can't find a unique selector after ${config.timeoutMs}ms`);
6789
+ }
6790
+ return selector(fPath);
6791
+ }
6792
+ count++;
6793
+ if (unique(candidate, rootDocument)) {
6794
+ foundPath = candidate;
6795
+ break;
6711
6796
  }
6712
- return selector(path);
6713
6797
  }
6714
- else {
6798
+ if (!foundPath) {
6715
6799
  throw new Error(`Selector was not found.`);
6716
6800
  }
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;
6801
+ const optimized = [
6802
+ ...optimize(foundPath, input, config, rootDocument, startTime),
6803
+ ];
6804
+ optimized.sort(byPenalty);
6805
+ if (optimized.length > 0) {
6806
+ return selector(optimized[0]);
6724
6807
  }
6725
- return rootNode;
6808
+ return selector(foundPath);
6726
6809
  }
6727
- function bottomUpSearch(input, limit, fallback) {
6728
- let path = null;
6729
- let stack = [];
6810
+ function* search(input, config, rootDocument) {
6811
+ const stack = [];
6812
+ let paths = [];
6730
6813
  let current = input;
6731
6814
  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) {
6815
+ while (current && current !== rootDocument) {
6816
+ const level = tie(current, config);
6817
+ for (const node of level) {
6766
6818
  node.level = i;
6767
6819
  }
6768
6820
  stack.push(level);
6769
- if (stack.length >= config.seedMinLength) {
6770
- path = findUniquePath(stack, fallback);
6771
- if (path) {
6772
- break;
6773
- }
6774
- }
6775
6821
  current = current.parentElement;
6776
6822
  i++;
6823
+ paths.push(...combinations(stack));
6824
+ if (i >= config.seedMinLength) {
6825
+ paths.sort(byPenalty);
6826
+ for (const candidate of paths) {
6827
+ yield candidate;
6828
+ }
6829
+ paths = [];
6830
+ }
6777
6831
  }
6778
- if (!path) {
6779
- path = findUniquePath(stack, fallback);
6832
+ paths.sort(byPenalty);
6833
+ for (const candidate of paths) {
6834
+ yield candidate;
6780
6835
  }
6781
- if (!path && fallback) {
6782
- return fallback();
6836
+ }
6837
+ function wordLike(name) {
6838
+ if (/^[a-z\-]{3,}$/i.test(name)) {
6839
+ const words = name.split(/-|[A-Z]/);
6840
+ for (const word of words) {
6841
+ if (word.length <= 2) {
6842
+ return false;
6843
+ }
6844
+ if (/[^aeiou]{4,}/i.test(word)) {
6845
+ return false;
6846
+ }
6847
+ }
6848
+ return true;
6783
6849
  }
6784
- return path;
6850
+ return false;
6785
6851
  }
6786
- function findUniquePath(stack, fallback) {
6787
- const paths = sort(combinations(stack));
6788
- if (paths.length > config.threshold) {
6789
- return fallback ? fallback() : null;
6852
+ function tie(element, config) {
6853
+ const level = [];
6854
+ const elementId = element.getAttribute('id');
6855
+ if (elementId && config.idName(elementId)) {
6856
+ level.push({
6857
+ name: '#' + CSS.escape(elementId),
6858
+ penalty: 0,
6859
+ });
6790
6860
  }
6791
- for (let candidate of paths) {
6792
- if (unique(candidate)) {
6793
- return candidate;
6861
+ for (let i = 0; i < element.classList.length; i++) {
6862
+ const name = element.classList[i];
6863
+ if (config.className(name)) {
6864
+ level.push({
6865
+ name: '.' + CSS.escape(name),
6866
+ penalty: 1,
6867
+ });
6794
6868
  }
6795
6869
  }
6796
- return null;
6870
+ for (let i = 0; i < element.attributes.length; i++) {
6871
+ const attr = element.attributes[i];
6872
+ if (config.attr(attr.name, attr.value)) {
6873
+ level.push({
6874
+ name: `[${CSS.escape(attr.name)}="${CSS.escape(attr.value)}"]`,
6875
+ penalty: 2,
6876
+ });
6877
+ }
6878
+ }
6879
+ const tagName = element.tagName.toLowerCase();
6880
+ if (config.tagName(tagName)) {
6881
+ level.push({
6882
+ name: tagName,
6883
+ penalty: 5,
6884
+ });
6885
+ const index = indexOf(element, tagName);
6886
+ if (index !== undefined) {
6887
+ level.push({
6888
+ name: nthOfType(tagName, index),
6889
+ penalty: 10,
6890
+ });
6891
+ }
6892
+ }
6893
+ const nth = indexOf(element);
6894
+ if (nth !== undefined) {
6895
+ level.push({
6896
+ name: nthChild(tagName, nth),
6897
+ penalty: 50,
6898
+ });
6899
+ }
6900
+ return level;
6797
6901
  }
6798
6902
  function selector(path) {
6799
6903
  let node = path[0];
@@ -6813,69 +6917,23 @@ function selector(path) {
6813
6917
  function penalty(path) {
6814
6918
  return path.map((node) => node.penalty).reduce((acc, i) => acc + i, 0);
6815
6919
  }
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;
6920
+ function byPenalty(a, b) {
6921
+ return penalty(a) - penalty(b);
6860
6922
  }
6861
- function any() {
6862
- return {
6863
- name: '*',
6864
- penalty: 3,
6865
- };
6866
- }
6867
- function index(input) {
6923
+ function indexOf(input, tagName) {
6868
6924
  const parent = input.parentNode;
6869
6925
  if (!parent) {
6870
- return null;
6926
+ return undefined;
6871
6927
  }
6872
6928
  let child = parent.firstChild;
6873
6929
  if (!child) {
6874
- return null;
6930
+ return undefined;
6875
6931
  }
6876
6932
  let i = 0;
6877
6933
  while (child) {
6878
- if (child.nodeType === Node.ELEMENT_NODE) {
6934
+ if (child.nodeType === Node.ELEMENT_NODE &&
6935
+ (tagName === undefined ||
6936
+ child.tagName.toLowerCase() === tagName)) {
6879
6937
  i++;
6880
6938
  }
6881
6939
  if (child === input) {
@@ -6885,24 +6943,39 @@ function index(input) {
6885
6943
  }
6886
6944
  return i;
6887
6945
  }
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('#');
6946
+ function fallback(input, rootDocument) {
6947
+ let i = 0;
6948
+ let current = input;
6949
+ const path = [];
6950
+ while (current && current !== rootDocument) {
6951
+ const tagName = current.tagName.toLowerCase();
6952
+ const index = indexOf(current, tagName);
6953
+ if (index === undefined) {
6954
+ return;
6955
+ }
6956
+ path.push({
6957
+ name: nthOfType(tagName, index),
6958
+ penalty: NaN,
6959
+ level: i,
6960
+ });
6961
+ current = current.parentElement;
6962
+ i++;
6963
+ }
6964
+ if (unique(path, rootDocument)) {
6965
+ return path;
6966
+ }
6896
6967
  }
6897
- function maybe(...level) {
6898
- const list = level.filter(notEmpty);
6899
- if (list.length > 0) {
6900
- return list;
6968
+ function nthChild(tagName, index) {
6969
+ if (tagName === 'html') {
6970
+ return 'html';
6901
6971
  }
6902
- return null;
6972
+ return `${tagName}:nth-child(${index})`;
6903
6973
  }
6904
- function notEmpty(value) {
6905
- return value !== null && value !== undefined;
6974
+ function nthOfType(tagName, index) {
6975
+ if (tagName === 'html') {
6976
+ return 'html';
6977
+ }
6978
+ return `${tagName}:nth-of-type(${index})`;
6906
6979
  }
6907
6980
  function* combinations(stack, path = []) {
6908
6981
  if (stack.length > 0) {
@@ -6914,44 +6987,50 @@ function* combinations(stack, path = []) {
6914
6987
  yield path;
6915
6988
  }
6916
6989
  }
6917
- function sort(paths) {
6918
- return [...paths].sort((a, b) => penalty(a) - penalty(b));
6990
+ function findRootDocument(rootNode, defaults) {
6991
+ if (rootNode.nodeType === Node.DOCUMENT_NODE) {
6992
+ return rootNode;
6993
+ }
6994
+ if (rootNode === defaults.root) {
6995
+ return rootNode.ownerDocument;
6996
+ }
6997
+ return rootNode;
6998
+ }
6999
+ function unique(path, rootDocument) {
7000
+ const css = selector(path);
7001
+ switch (rootDocument.querySelectorAll(css).length) {
7002
+ case 0:
7003
+ throw new Error(`Can't select any node with this selector: ${css}`);
7004
+ case 1:
7005
+ return true;
7006
+ default:
7007
+ return false;
7008
+ }
6919
7009
  }
6920
- function* optimize(path, input, scope = {
6921
- counter: 0,
6922
- visited: new Map(),
6923
- }) {
7010
+ function* optimize(path, input, config, rootDocument, startTime) {
6924
7011
  if (path.length > 2 && path.length > config.optimizedMinLength) {
6925
7012
  for (let i = 1; i < path.length - 1; i++) {
6926
- if (scope.counter > config.maxNumberOfTries) {
6927
- return; // Okay At least I tried!
7013
+ const elapsedTimeMs = new Date().getTime() - startTime.getTime();
7014
+ if (elapsedTimeMs > config.timeoutMs) {
7015
+ return;
6928
7016
  }
6929
- scope.counter += 1;
6930
7017
  const newPath = [...path];
6931
7018
  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)) {
7019
+ if (unique(newPath, rootDocument) &&
7020
+ rootDocument.querySelector(selector(newPath)) === input) {
6937
7021
  yield newPath;
6938
- scope.visited.set(newPathKey, true);
6939
- yield* optimize(newPath, input, scope);
7022
+ yield* optimize(newPath, input, config, rootDocument, startTime);
6940
7023
  }
6941
7024
  }
6942
7025
  }
6943
7026
  }
6944
- function same(path, input) {
6945
- return rootDocument.querySelector(selector(path)) === input;
6946
- }
6947
7027
 
6948
7028
  function _getSelector(target, document, options) {
6949
7029
  const selector = finder(target, {
6950
7030
  root: document.body,
6951
7031
  seedMinLength: 3,
6952
7032
  optimizedMinLength: options?.minSelectorDepth || 2,
6953
- threshold: options?.nthThreshold || 1000,
6954
- maxNumberOfTries: options?.maxOptimiseTries || 10000,
7033
+ maxNumberOfPathChecks: options?.maxOptimiseTries || 10000,
6955
7034
  });
6956
7035
  return selector;
6957
7036
  }
@@ -7218,6 +7297,11 @@ function Timing (app, opts) {
7218
7297
  if (shouldSkip) {
7219
7298
  return;
7220
7299
  }
7300
+ const failed = entry.responseEnd === 0
7301
+ || (entry.transferSize === 0 && entry.decodedBodySize === 0);
7302
+ if (failed) {
7303
+ app.send(ResourceTiming(entry.startTime + getTimeOrigin(), 0, 0, 0, 0, 0, entry.name, entry.initiatorType, 0, true));
7304
+ }
7221
7305
  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
7306
  // @ts-ignore
7223
7307
  (entry.responseStatus && entry.responseStatus === 304) || entry.transferSize === 0));
@@ -8749,6 +8833,9 @@ function strMethod(method) {
8749
8833
  return typeof method === 'string' ? method.toUpperCase() : 'GET';
8750
8834
  }
8751
8835
  function Network (app, opts = {}) {
8836
+ if (opts.disabled) {
8837
+ return;
8838
+ }
8752
8839
  const options = Object.assign({
8753
8840
  failuresOnly: false,
8754
8841
  ignoreHeaders: ['cookie', 'set-cookie', 'authorization'],
@@ -9068,11 +9155,8 @@ class API {
9068
9155
  };
9069
9156
  this.signalStartIssue = (reason, missingApi) => {
9070
9157
  const doNotTrack = this.checkDoNotTrack();
9071
- const req = new XMLHttpRequest();
9072
- const orig = this.options.ingestPoint || DEFAULT_INGEST_POINT;
9073
- req.open('POST', orig + '/v1/web/not-started');
9074
- req.send(JSON.stringify({
9075
- trackerVersion: '15.0.3',
9158
+ console.log("Tracker couldn't start due to:", JSON.stringify({
9159
+ trackerVersion: '15.0.5-beta.1',
9076
9160
  projectKey: this.options.projectKey,
9077
9161
  doNotTrack,
9078
9162
  reason: missingApi.length ? `missing api: ${missingApi.join(',')}` : reason,
@@ -9180,7 +9264,10 @@ class API {
9180
9264
  Timing(app, options);
9181
9265
  Focus(app);
9182
9266
  Fonts(app);
9183
- Network(app, options.network);
9267
+ const skipNetwork = options.network?.disabled;
9268
+ if (!skipNetwork) {
9269
+ Network(app, options.network);
9270
+ }
9184
9271
  selection(app);
9185
9272
  window.__OPENREPLAY__ = this;
9186
9273
  if (options.flags && options.flags.onFlagsLoad) {