index.js
   1  import { getCurrentHub, addGlobalEventProcessor, prepareEvent, setContext, captureException } from '@sentry/core';
   2  import { GLOBAL_OBJ, normalize, fill, htmlTreeAsString, logger, uuid4, SENTRY_XHR_DATA_KEY, dropUndefinedKeys, stringMatchesSomePattern, addInstrumentationHandler, browserPerformanceTimeOrigin, createEnvelope, createEventEnvelopeHeaders, getSdkMetadataForEnvelopeHeader, isNodeEnv } from '@sentry/utils';
   3  
   4  // exporting a separate copy of `WINDOW` rather than exporting the one from `@sentry/browser`
   5  // prevents the browser package from being bundled in the CDN bundle, and avoids a
   6  // circular dependency between the browser and replay packages should `@sentry/browser` import
   7  // from `@sentry/replay` in the future
   8  const WINDOW = GLOBAL_OBJ ;
   9  
  10  const REPLAY_SESSION_KEY = 'sentryReplaySession';
  11  const REPLAY_EVENT_NAME = 'replay_event';
  12  const UNABLE_TO_SEND_REPLAY = 'Unable to send Replay';
  13  
  14  // The idle limit for a session after which recording is paused.
  15  const SESSION_IDLE_PAUSE_DURATION = 300000; // 5 minutes in ms
  16  
  17  // The idle limit for a session after which the session expires.
  18  const SESSION_IDLE_EXPIRE_DURATION = 900000; // 15 minutes in ms
  19  
  20  // The maximum length of a session
  21  const MAX_SESSION_LIFE = 3600000; // 60 minutes in ms
  22  
  23  /** Default flush delays */
  24  const DEFAULT_FLUSH_MIN_DELAY = 5000;
  25  // XXX: Temp fix for our debounce logic where `maxWait` would never occur if it
  26  // was the same as `wait`
  27  const DEFAULT_FLUSH_MAX_DELAY = 5500;
  28  
  29  /* How long to wait for error checkouts */
  30  const BUFFER_CHECKOUT_TIME = 60000;
  31  
  32  const RETRY_BASE_INTERVAL = 5000;
  33  const RETRY_MAX_COUNT = 3;
  34  
  35  /* The max (uncompressed) size in bytes of a network body. Any body larger than this will be truncated. */
  36  const NETWORK_BODY_MAX_SIZE = 150000;
  37  
  38  /* The max size of a single console arg that is captured. Any arg larger than this will be truncated. */
  39  const CONSOLE_ARG_MAX_SIZE = 5000;
  40  
  41  /* Min. time to wait before we consider something a slow click. */
  42  const SLOW_CLICK_THRESHOLD = 3000;
  43  /* For scroll actions after a click, we only look for a very short time period to detect programmatic scrolling. */
  44  const SLOW_CLICK_SCROLL_TIMEOUT = 300;
  45  /* Clicks in this time period are considered e.g. double/triple clicks. */
  46  const MULTI_CLICK_TIMEOUT = 1000;
  47  
  48  /** When encountering a total segment size exceeding this size, stop the replay (as we cannot properly ingest it). */
  49  const REPLAY_MAX_EVENT_BUFFER_SIZE = 20000000; // ~20MB
  50  
  51  var NodeType$1;
  52  (function (NodeType) {
  53      NodeType[NodeType["Document"] = 0] = "Document";
  54      NodeType[NodeType["DocumentType"] = 1] = "DocumentType";
  55      NodeType[NodeType["Element"] = 2] = "Element";
  56      NodeType[NodeType["Text"] = 3] = "Text";
  57      NodeType[NodeType["CDATA"] = 4] = "CDATA";
  58      NodeType[NodeType["Comment"] = 5] = "Comment";
  59  })(NodeType$1 || (NodeType$1 = {}));
  60  
  61  function isElement(n) {
  62      return n.nodeType === n.ELEMENT_NODE;
  63  }
  64  function isShadowRoot(n) {
  65      const host = n === null || n === void 0 ? void 0 : n.host;
  66      return Boolean(host && host.shadowRoot && host.shadowRoot === n);
  67  }
  68  function isInputTypeMasked({ maskInputOptions, tagName, type, }) {
  69      if (tagName.toLowerCase() === 'option') {
  70          tagName = 'select';
  71      }
  72      const actualType = typeof type === 'string' ? type.toLowerCase() : undefined;
  73      return (maskInputOptions[tagName.toLowerCase()] ||
  74          (actualType && maskInputOptions[actualType]) ||
  75          actualType === 'password' ||
  76          (tagName === 'input' && !type && maskInputOptions['text']));
  77  }
  78  function hasInputMaskOptions({ tagName, type, maskInputOptions, maskInputSelector, }) {
  79      return (maskInputSelector || isInputTypeMasked({ maskInputOptions, tagName, type }));
  80  }
  81  function maskInputValue({ input, maskInputSelector, unmaskInputSelector, maskInputOptions, tagName, type, value, maskInputFn, }) {
  82      let text = value || '';
  83      if (unmaskInputSelector && input.matches(unmaskInputSelector)) {
  84          return text;
  85      }
  86      if (input.hasAttribute('data-rr-is-password')) {
  87          type = 'password';
  88      }
  89      if (isInputTypeMasked({ maskInputOptions, tagName, type }) ||
  90          (maskInputSelector && input.matches(maskInputSelector))) {
  91          if (maskInputFn) {
  92              text = maskInputFn(text);
  93          }
  94          else {
  95              text = '*'.repeat(text.length);
  96          }
  97      }
  98      return text;
  99  }
 100  const ORIGINAL_ATTRIBUTE_NAME = '__rrweb_original__';
 101  function is2DCanvasBlank(canvas) {
 102      const ctx = canvas.getContext('2d');
 103      if (!ctx)
 104          return true;
 105      const chunkSize = 50;
 106      for (let x = 0; x < canvas.width; x += chunkSize) {
 107          for (let y = 0; y < canvas.height; y += chunkSize) {
 108              const getImageData = ctx.getImageData;
 109              const originalGetImageData = ORIGINAL_ATTRIBUTE_NAME in getImageData
 110                  ? getImageData[ORIGINAL_ATTRIBUTE_NAME]
 111                  : getImageData;
 112              const pixelBuffer = new Uint32Array(originalGetImageData.call(ctx, x, y, Math.min(chunkSize, canvas.width - x), Math.min(chunkSize, canvas.height - y)).data.buffer);
 113              if (pixelBuffer.some((pixel) => pixel !== 0))
 114                  return false;
 115          }
 116      }
 117      return true;
 118  }
 119  function getInputType(element) {
 120      const type = element.type;
 121      return element.hasAttribute('data-rr-is-password')
 122          ? 'password'
 123          : type
 124              ? type.toLowerCase()
 125              : null;
 126  }
 127  function getInputValue(el, tagName, type) {
 128      typeof type === 'string' ? type.toLowerCase() : '';
 129      if (tagName === 'INPUT' && (type === 'radio' || type === 'checkbox')) {
 130          return el.getAttribute('value') || '';
 131      }
 132      return el.value;
 133  }
 134  
 135  let _id = 1;
 136  const tagNameRegex = new RegExp('[^a-z0-9-_:]');
 137  const IGNORED_NODE = -2;
 138  function defaultMaskFn(str) {
 139      return str ? str.replace(/[\S]/g, '*') : '';
 140  }
 141  function genId() {
 142      return _id++;
 143  }
 144  function getValidTagName(element) {
 145      if (element instanceof HTMLFormElement) {
 146          return 'form';
 147      }
 148      const processedTagName = element.tagName.toLowerCase().trim();
 149      if (tagNameRegex.test(processedTagName)) {
 150          return 'div';
 151      }
 152      return processedTagName;
 153  }
 154  function getCssRulesString(s) {
 155      try {
 156          const rules = s.rules || s.cssRules;
 157          return rules ? Array.from(rules).map(getCssRuleString).join('') : null;
 158      }
 159      catch (error) {
 160          return null;
 161      }
 162  }
 163  function getCssRuleString(rule) {
 164      let cssStringified = rule.cssText;
 165      if (isCSSImportRule(rule)) {
 166          try {
 167              cssStringified = getCssRulesString(rule.styleSheet) || cssStringified;
 168          }
 169          catch (_a) {
 170          }
 171      }
 172      return validateStringifiedCssRule(cssStringified);
 173  }
 174  function validateStringifiedCssRule(cssStringified) {
 175      if (cssStringified.indexOf(':') > -1) {
 176          const regex = /(\[(?:[\w-]+)[^\\])(:(?:[\w-]+)\])/gm;
 177          return cssStringified.replace(regex, '$1\\$2');
 178      }
 179      return cssStringified;
 180  }
 181  function isCSSImportRule(rule) {
 182      return 'styleSheet' in rule;
 183  }
 184  function stringifyStyleSheet(sheet) {
 185      return sheet.cssRules
 186          ? Array.from(sheet.cssRules)
 187              .map((rule) => rule.cssText ? validateStringifiedCssRule(rule.cssText) : '')
 188              .join('')
 189          : '';
 190  }
 191  function extractOrigin(url) {
 192      let origin = '';
 193      if (url.indexOf('//') > -1) {
 194          origin = url.split('/').slice(0, 3).join('/');
 195      }
 196      else {
 197          origin = url.split('/')[0];
 198      }
 199      origin = origin.split('?')[0];
 200      return origin;
 201  }
 202  let canvasService;
 203  let canvasCtx;
 204  const URL_IN_CSS_REF = /url\((?:(')([^']*)'|(")(.*?)"|([^)]*))\)/gm;
 205  const RELATIVE_PATH = /^(?!www\.|(?:http|ftp)s?:\/\/|[A-Za-z]:\\|\/\/|#).*/;
 206  const DATA_URI = /^(data:)([^,]*),(.*)/i;
 207  function absoluteToStylesheet(cssText, href) {
 208      return (cssText || '').replace(URL_IN_CSS_REF, (origin, quote1, path1, quote2, path2, path3) => {
 209          const filePath = path1 || path2 || path3;
 210          const maybeQuote = quote1 || quote2 || '';
 211          if (!filePath) {
 212              return origin;
 213          }
 214          if (!RELATIVE_PATH.test(filePath)) {
 215              return `url(${maybeQuote}${filePath}${maybeQuote})`;
 216          }
 217          if (DATA_URI.test(filePath)) {
 218              return `url(${maybeQuote}${filePath}${maybeQuote})`;
 219          }
 220          if (filePath[0] === '/') {
 221              return `url(${maybeQuote}${extractOrigin(href) + filePath}${maybeQuote})`;
 222          }
 223          const stack = href.split('/');
 224          const parts = filePath.split('/');
 225          stack.pop();
 226          for (const part of parts) {
 227              if (part === '.') {
 228                  continue;
 229              }
 230              else if (part === '..') {
 231                  stack.pop();
 232              }
 233              else {
 234                  stack.push(part);
 235              }
 236          }
 237          return `url(${maybeQuote}${stack.join('/')}${maybeQuote})`;
 238      });
 239  }
 240  const SRCSET_NOT_SPACES = /^[^ \t\n\r\u000c]+/;
 241  const SRCSET_COMMAS_OR_SPACES = /^[, \t\n\r\u000c]+/;
 242  function getAbsoluteSrcsetString(doc, attributeValue) {
 243      if (attributeValue.trim() === '') {
 244          return attributeValue;
 245      }
 246      let pos = 0;
 247      function collectCharacters(regEx) {
 248          let chars;
 249          let match = regEx.exec(attributeValue.substring(pos));
 250          if (match) {
 251              chars = match[0];
 252              pos += chars.length;
 253              return chars;
 254          }
 255          return '';
 256      }
 257      let output = [];
 258      while (true) {
 259          collectCharacters(SRCSET_COMMAS_OR_SPACES);
 260          if (pos >= attributeValue.length) {
 261              break;
 262          }
 263          let url = collectCharacters(SRCSET_NOT_SPACES);
 264          if (url.slice(-1) === ',') {
 265              url = absoluteToDoc(doc, url.substring(0, url.length - 1));
 266              output.push(url);
 267          }
 268          else {
 269              let descriptorsStr = '';
 270              url = absoluteToDoc(doc, url);
 271              let inParens = false;
 272              while (true) {
 273                  let c = attributeValue.charAt(pos);
 274                  if (c === '') {
 275                      output.push((url + descriptorsStr).trim());
 276                      break;
 277                  }
 278                  else if (!inParens) {
 279                      if (c === ',') {
 280                          pos += 1;
 281                          output.push((url + descriptorsStr).trim());
 282                          break;
 283                      }
 284                      else if (c === '(') {
 285                          inParens = true;
 286                      }
 287                  }
 288                  else {
 289                      if (c === ')') {
 290                          inParens = false;
 291                      }
 292                  }
 293                  descriptorsStr += c;
 294                  pos += 1;
 295              }
 296          }
 297      }
 298      return output.join(', ');
 299  }
 300  function absoluteToDoc(doc, attributeValue) {
 301      if (!attributeValue || attributeValue.trim() === '') {
 302          return attributeValue;
 303      }
 304      const a = doc.createElement('a');
 305      a.href = attributeValue;
 306      return a.href;
 307  }
 308  function isSVGElement(el) {
 309      return Boolean(el.tagName === 'svg' || el.ownerSVGElement);
 310  }
 311  function getHref() {
 312      const a = document.createElement('a');
 313      a.href = '';
 314      return a.href;
 315  }
 316  function transformAttribute(doc, element, _tagName, _name, value, maskAllText, unmaskTextSelector, maskTextFn) {
 317      if (!value) {
 318          return value;
 319      }
 320      const name = _name.toLowerCase();
 321      const tagName = _tagName.toLowerCase();
 322      if (name === 'src' || name === 'href') {
 323          return absoluteToDoc(doc, value);
 324      }
 325      else if (name === 'xlink:href' && value[0] !== '#') {
 326          return absoluteToDoc(doc, value);
 327      }
 328      else if (name === 'background' &&
 329          (tagName === 'table' || tagName === 'td' || tagName === 'th')) {
 330          return absoluteToDoc(doc, value);
 331      }
 332      else if (name === 'srcset') {
 333          return getAbsoluteSrcsetString(doc, value);
 334      }
 335      else if (name === 'style') {
 336          return absoluteToStylesheet(value, getHref());
 337      }
 338      else if (tagName === 'object' && name === 'data') {
 339          return absoluteToDoc(doc, value);
 340      }
 341      else if (maskAllText &&
 342          _shouldMaskAttribute(element, name, tagName, unmaskTextSelector)) {
 343          return maskTextFn ? maskTextFn(value) : defaultMaskFn(value);
 344      }
 345      return value;
 346  }
 347  function _shouldMaskAttribute(element, attribute, tagName, unmaskTextSelector) {
 348      if (unmaskTextSelector && element.matches(unmaskTextSelector)) {
 349          return false;
 350      }
 351      return (['placeholder', 'title', 'aria-label'].indexOf(attribute) > -1 ||
 352          (tagName === 'input' &&
 353              attribute === 'value' &&
 354              element.hasAttribute('type') &&
 355              ['submit', 'button'].indexOf(element.getAttribute('type').toLowerCase()) > -1));
 356  }
 357  function _isBlockedElement(element, blockClass, blockSelector, unblockSelector) {
 358      if (unblockSelector && element.matches(unblockSelector)) {
 359          return false;
 360      }
 361      if (typeof blockClass === 'string') {
 362          if (element.classList.contains(blockClass)) {
 363              return true;
 364          }
 365      }
 366      else {
 367          for (let eIndex = 0; eIndex < element.classList.length; eIndex++) {
 368              const className = element.classList[eIndex];
 369              if (blockClass.test(className)) {
 370                  return true;
 371              }
 372          }
 373      }
 374      if (blockSelector) {
 375          return element.matches(blockSelector);
 376      }
 377      return false;
 378  }
 379  function needMaskingText(node, maskTextClass, maskTextSelector, unmaskTextSelector, maskAllText) {
 380      if (!node) {
 381          return false;
 382      }
 383      if (node.nodeType !== node.ELEMENT_NODE) {
 384          return needMaskingText(node.parentNode, maskTextClass, maskTextSelector, unmaskTextSelector, maskAllText);
 385      }
 386      if (unmaskTextSelector) {
 387          if (node.matches(unmaskTextSelector) ||
 388              node.closest(unmaskTextSelector)) {
 389              return false;
 390          }
 391      }
 392      if (maskAllText) {
 393          return true;
 394      }
 395      if (typeof maskTextClass === 'string') {
 396          if (node.classList.contains(maskTextClass)) {
 397              return true;
 398          }
 399      }
 400      else {
 401          for (let eIndex = 0; eIndex < node.classList.length; eIndex++) {
 402              const className = node.classList[eIndex];
 403              if (maskTextClass.test(className)) {
 404                  return true;
 405              }
 406          }
 407      }
 408      if (maskTextSelector) {
 409          if (node.matches(maskTextSelector)) {
 410              return true;
 411          }
 412      }
 413      return needMaskingText(node.parentNode, maskTextClass, maskTextSelector, unmaskTextSelector, maskAllText);
 414  }
 415  function onceIframeLoaded(iframeEl, listener, iframeLoadTimeout) {
 416      const win = iframeEl.contentWindow;
 417      if (!win) {
 418          return;
 419      }
 420      let fired = false;
 421      let readyState;
 422      try {
 423          readyState = win.document.readyState;
 424      }
 425      catch (error) {
 426          return;
 427      }
 428      if (readyState !== 'complete') {
 429          const timer = setTimeout(() => {
 430              if (!fired) {
 431                  listener();
 432                  fired = true;
 433              }
 434          }, iframeLoadTimeout);
 435          iframeEl.addEventListener('load', () => {
 436              clearTimeout(timer);
 437              fired = true;
 438              listener();
 439          });
 440          return;
 441      }
 442      const blankUrl = 'about:blank';
 443      if (win.location.href !== blankUrl ||
 444          iframeEl.src === blankUrl ||
 445          iframeEl.src === '') {
 446          setTimeout(listener, 0);
 447          return;
 448      }
 449      iframeEl.addEventListener('load', listener);
 450  }
 451  function serializeNode(n, options) {
 452      var _a;
 453      const { doc, blockClass, blockSelector, unblockSelector, maskTextClass, maskTextSelector, unmaskTextSelector, inlineStylesheet, maskInputSelector, unmaskInputSelector, maskAllText, maskInputOptions = {}, maskTextFn, maskInputFn, dataURLOptions = {}, inlineImages, recordCanvas, keepIframeSrcFn, } = options;
 454      let rootId;
 455      if (doc.__sn) {
 456          const docId = doc.__sn.id;
 457          rootId = docId === 1 ? undefined : docId;
 458      }
 459      switch (n.nodeType) {
 460          case n.DOCUMENT_NODE:
 461              if (n.compatMode !== 'CSS1Compat') {
 462                  return {
 463                      type: NodeType$1.Document,
 464                      childNodes: [],
 465                      compatMode: n.compatMode,
 466                      rootId,
 467                  };
 468              }
 469              else {
 470                  return {
 471                      type: NodeType$1.Document,
 472                      childNodes: [],
 473                      rootId,
 474                  };
 475              }
 476          case n.DOCUMENT_TYPE_NODE:
 477              return {
 478                  type: NodeType$1.DocumentType,
 479                  name: n.name,
 480                  publicId: n.publicId,
 481                  systemId: n.systemId,
 482                  rootId,
 483              };
 484          case n.ELEMENT_NODE:
 485              const needBlock = _isBlockedElement(n, blockClass, blockSelector, unblockSelector);
 486              const tagName = getValidTagName(n);
 487              let attributes = {};
 488              for (const { name, value } of Array.from(n.attributes)) {
 489                  if (!skipAttribute(tagName, name)) {
 490                      attributes[name] = transformAttribute(doc, n, tagName, name, value, maskAllText, unmaskTextSelector, maskTextFn);
 491                  }
 492              }
 493              if (tagName === 'link' && inlineStylesheet) {
 494                  const stylesheet = Array.from(doc.styleSheets).find((s) => {
 495                      return s.href === n.href;
 496                  });
 497                  let cssText = null;
 498                  if (stylesheet) {
 499                      cssText = getCssRulesString(stylesheet);
 500                  }
 501                  if (cssText) {
 502                      delete attributes.rel;
 503                      delete attributes.href;
 504                      attributes._cssText = absoluteToStylesheet(cssText, stylesheet.href);
 505                  }
 506              }
 507              if (tagName === 'style' &&
 508                  n.sheet &&
 509                  !(n.innerText ||
 510                      n.textContent ||
 511                      '').trim().length) {
 512                  const cssText = getCssRulesString(n.sheet);
 513                  if (cssText) {
 514                      attributes._cssText = absoluteToStylesheet(cssText, getHref());
 515                  }
 516              }
 517              if (tagName === 'input' ||
 518                  tagName === 'textarea' ||
 519                  tagName === 'select' ||
 520                  tagName === 'option') {
 521                  const el = n;
 522                  const type = getInputType(el);
 523                  const value = getInputValue(el, tagName.toUpperCase(), type);
 524                  const checked = n.checked;
 525                  if (type !== 'submit' &&
 526                      type !== 'button' &&
 527                      value) {
 528                      attributes.value = maskInputValue({
 529                          input: el,
 530                          type,
 531                          tagName,
 532                          value,
 533                          maskInputSelector,
 534                          unmaskInputSelector,
 535                          maskInputOptions,
 536                          maskInputFn,
 537                      });
 538                  }
 539                  if (checked) {
 540                      attributes.checked = checked;
 541                  }
 542              }
 543              if (tagName === 'option') {
 544                  if (n.selected && !maskInputOptions['select']) {
 545                      attributes.selected = true;
 546                  }
 547                  else {
 548                      delete attributes.selected;
 549                  }
 550              }
 551              if (tagName === 'canvas' && recordCanvas) {
 552                  if (n.__context === '2d') {
 553                      if (!is2DCanvasBlank(n)) {
 554                          attributes.rr_dataURL = n.toDataURL(dataURLOptions.type, dataURLOptions.quality);
 555                      }
 556                  }
 557                  else if (!('__context' in n)) {
 558                      const canvasDataURL = n.toDataURL(dataURLOptions.type, dataURLOptions.quality);
 559                      const blankCanvas = document.createElement('canvas');
 560                      blankCanvas.width = n.width;
 561                      blankCanvas.height = n.height;
 562                      const blankCanvasDataURL = blankCanvas.toDataURL(dataURLOptions.type, dataURLOptions.quality);
 563                      if (canvasDataURL !== blankCanvasDataURL) {
 564                          attributes.rr_dataURL = canvasDataURL;
 565                      }
 566                  }
 567              }
 568              if (tagName === 'img' && inlineImages) {
 569                  if (!canvasService) {
 570                      canvasService = doc.createElement('canvas');
 571                      canvasCtx = canvasService.getContext('2d');
 572                  }
 573                  const image = n;
 574                  const oldValue = image.crossOrigin;
 575                  image.crossOrigin = 'anonymous';
 576                  const recordInlineImage = () => {
 577                      try {
 578                          canvasService.width = image.naturalWidth;
 579                          canvasService.height = image.naturalHeight;
 580                          canvasCtx.drawImage(image, 0, 0);
 581                          attributes.rr_dataURL = canvasService.toDataURL(dataURLOptions.type, dataURLOptions.quality);
 582                      }
 583                      catch (err) {
 584                          console.warn(`Cannot inline img src=${image.currentSrc}! Error: ${err}`);
 585                      }
 586                      oldValue
 587                          ? (attributes.crossOrigin = oldValue)
 588                          : delete attributes.crossOrigin;
 589                  };
 590                  if (image.complete && image.naturalWidth !== 0)
 591                      recordInlineImage();
 592                  else
 593                      image.onload = recordInlineImage;
 594              }
 595              if (tagName === 'audio' || tagName === 'video') {
 596                  attributes.rr_mediaState = n.paused
 597                      ? 'paused'
 598                      : 'played';
 599                  attributes.rr_mediaCurrentTime = n.currentTime;
 600              }
 601              if (n.scrollLeft) {
 602                  attributes.rr_scrollLeft = n.scrollLeft;
 603              }
 604              if (n.scrollTop) {
 605                  attributes.rr_scrollTop = n.scrollTop;
 606              }
 607              if (needBlock) {
 608                  const { width, height } = n.getBoundingClientRect();
 609                  attributes = {
 610                      class: attributes.class,
 611                      rr_width: `${width}px`,
 612                      rr_height: `${height}px`,
 613                  };
 614              }
 615              if (tagName === 'iframe' && !keepIframeSrcFn(attributes.src)) {
 616                  if (!n.contentDocument) {
 617                      attributes.rr_src = attributes.src;
 618                  }
 619                  delete attributes.src;
 620              }
 621              return {
 622                  type: NodeType$1.Element,
 623                  tagName,
 624                  attributes,
 625                  childNodes: [],
 626                  isSVG: isSVGElement(n) || undefined,
 627                  needBlock,
 628                  rootId,
 629              };
 630          case n.TEXT_NODE:
 631              const parentTagName = n.parentNode && n.parentNode.tagName;
 632              let textContent = n.textContent;
 633              const isStyle = parentTagName === 'STYLE' ? true : undefined;
 634              const isScript = parentTagName === 'SCRIPT' ? true : undefined;
 635              if (isStyle && textContent) {
 636                  try {
 637                      if (n.nextSibling || n.previousSibling) {
 638                      }
 639                      else if ((_a = n.parentNode.sheet) === null || _a === void 0 ? void 0 : _a.cssRules) {
 640                          textContent = stringifyStyleSheet(n.parentNode.sheet);
 641                      }
 642                  }
 643                  catch (err) {
 644                      console.warn(`Cannot get CSS styles from text's parentNode. Error: ${err}`, n);
 645                  }
 646                  textContent = absoluteToStylesheet(textContent, getHref());
 647              }
 648              if (isScript) {
 649                  textContent = 'SCRIPT_PLACEHOLDER';
 650              }
 651              if (parentTagName === 'TEXTAREA' && textContent) {
 652                  textContent = '';
 653              }
 654              else if (parentTagName === 'OPTION' && textContent) {
 655                  const option = n.parentNode;
 656                  textContent = maskInputValue({
 657                      input: option,
 658                      type: null,
 659                      tagName: parentTagName,
 660                      value: textContent,
 661                      maskInputSelector,
 662                      unmaskInputSelector,
 663                      maskInputOptions,
 664                      maskInputFn,
 665                  });
 666              }
 667              else if (!isStyle &&
 668                  !isScript &&
 669                  needMaskingText(n, maskTextClass, maskTextSelector, unmaskTextSelector, maskAllText) &&
 670                  textContent) {
 671                  textContent = maskTextFn
 672                      ? maskTextFn(textContent)
 673                      : defaultMaskFn(textContent);
 674              }
 675              return {
 676                  type: NodeType$1.Text,
 677                  textContent: textContent || '',
 678                  isStyle,
 679                  rootId,
 680              };
 681          case n.CDATA_SECTION_NODE:
 682              return {
 683                  type: NodeType$1.CDATA,
 684                  textContent: '',
 685                  rootId,
 686              };
 687          case n.COMMENT_NODE:
 688              return {
 689                  type: NodeType$1.Comment,
 690                  textContent: n.textContent || '',
 691                  rootId,
 692              };
 693          default:
 694              return false;
 695      }
 696  }
 697  function lowerIfExists(maybeAttr) {
 698      if (maybeAttr === undefined || maybeAttr === null) {
 699          return '';
 700      }
 701      else {
 702          return maybeAttr.toLowerCase();
 703      }
 704  }
 705  function slimDOMExcluded(sn, slimDOMOptions) {
 706      if (slimDOMOptions.comment && sn.type === NodeType$1.Comment) {
 707          return true;
 708      }
 709      else if (sn.type === NodeType$1.Element) {
 710          if (slimDOMOptions.script &&
 711              (sn.tagName === 'script' ||
 712                  (sn.tagName === 'link' &&
 713                      (sn.attributes.rel === 'preload' ||
 714                          sn.attributes.rel === 'modulepreload') &&
 715                      sn.attributes.as === 'script') ||
 716                  (sn.tagName === 'link' &&
 717                      sn.attributes.rel === 'prefetch' &&
 718                      typeof sn.attributes.href === 'string' &&
 719                      sn.attributes.href.endsWith('.js')))) {
 720              return true;
 721          }
 722          else if (slimDOMOptions.headFavicon &&
 723              ((sn.tagName === 'link' && sn.attributes.rel === 'shortcut icon') ||
 724                  (sn.tagName === 'meta' &&
 725                      (lowerIfExists(sn.attributes.name).match(/^msapplication-tile(image|color)$/) ||
 726                          lowerIfExists(sn.attributes.name) === 'application-name' ||
 727                          lowerIfExists(sn.attributes.rel) === 'icon' ||
 728                          lowerIfExists(sn.attributes.rel) === 'apple-touch-icon' ||
 729                          lowerIfExists(sn.attributes.rel) === 'shortcut icon')))) {
 730              return true;
 731          }
 732          else if (sn.tagName === 'meta') {
 733              if (slimDOMOptions.headMetaDescKeywords &&
 734                  lowerIfExists(sn.attributes.name).match(/^description|keywords$/)) {
 735                  return true;
 736              }
 737              else if (slimDOMOptions.headMetaSocial &&
 738                  (lowerIfExists(sn.attributes.property).match(/^(og|twitter|fb):/) ||
 739                      lowerIfExists(sn.attributes.name).match(/^(og|twitter):/) ||
 740                      lowerIfExists(sn.attributes.name) === 'pinterest')) {
 741                  return true;
 742              }
 743              else if (slimDOMOptions.headMetaRobots &&
 744                  (lowerIfExists(sn.attributes.name) === 'robots' ||
 745                      lowerIfExists(sn.attributes.name) === 'googlebot' ||
 746                      lowerIfExists(sn.attributes.name) === 'bingbot')) {
 747                  return true;
 748              }
 749              else if (slimDOMOptions.headMetaHttpEquiv &&
 750                  sn.attributes['http-equiv'] !== undefined) {
 751                  return true;
 752              }
 753              else if (slimDOMOptions.headMetaAuthorship &&
 754                  (lowerIfExists(sn.attributes.name) === 'author' ||
 755                      lowerIfExists(sn.attributes.name) === 'generator' ||
 756                      lowerIfExists(sn.attributes.name) === 'framework' ||
 757                      lowerIfExists(sn.attributes.name) === 'publisher' ||
 758                      lowerIfExists(sn.attributes.name) === 'progid' ||
 759                      lowerIfExists(sn.attributes.property).match(/^article:/) ||
 760                      lowerIfExists(sn.attributes.property).match(/^product:/))) {
 761                  return true;
 762              }
 763              else if (slimDOMOptions.headMetaVerification &&
 764                  (lowerIfExists(sn.attributes.name) === 'google-site-verification' ||
 765                      lowerIfExists(sn.attributes.name) === 'yandex-verification' ||
 766                      lowerIfExists(sn.attributes.name) === 'csrf-token' ||
 767                      lowerIfExists(sn.attributes.name) === 'p:domain_verify' ||
 768                      lowerIfExists(sn.attributes.name) === 'verify-v1' ||
 769                      lowerIfExists(sn.attributes.name) === 'verification' ||
 770                      lowerIfExists(sn.attributes.name) === 'shopify-checkout-api-token')) {
 771                  return true;
 772              }
 773          }
 774      }
 775      return false;
 776  }
 777  function serializeNodeWithId(n, options) {
 778      const { doc, map, blockClass, blockSelector, unblockSelector, maskTextClass, maskTextSelector, unmaskTextSelector, skipChild = false, inlineStylesheet = true, maskInputSelector, unmaskInputSelector, maskAllText, maskInputOptions = {}, maskTextFn, maskInputFn, slimDOMOptions, dataURLOptions = {}, inlineImages = false, recordCanvas = false, onSerialize, onIframeLoad, iframeLoadTimeout = 5000, keepIframeSrcFn = () => false, } = options;
 779      let { preserveWhiteSpace = true } = options;
 780      const _serializedNode = serializeNode(n, {
 781          doc,
 782          blockClass,
 783          blockSelector,
 784          unblockSelector,
 785          maskTextClass,
 786          maskTextSelector,
 787          unmaskTextSelector,
 788          inlineStylesheet,
 789          maskInputSelector,
 790          unmaskInputSelector,
 791          maskAllText,
 792          maskInputOptions,
 793          maskTextFn,
 794          maskInputFn,
 795          dataURLOptions,
 796          inlineImages,
 797          recordCanvas,
 798          keepIframeSrcFn,
 799      });
 800      if (!_serializedNode) {
 801          console.warn(n, 'not serialized');
 802          return null;
 803      }
 804      let id;
 805      if ('__sn' in n) {
 806          id = n.__sn.id;
 807      }
 808      else if (slimDOMExcluded(_serializedNode, slimDOMOptions) ||
 809          (!preserveWhiteSpace &&
 810              _serializedNode.type === NodeType$1.Text &&
 811              !_serializedNode.isStyle &&
 812              !_serializedNode.textContent.replace(/^\s+|\s+$/gm, '').length)) {
 813          id = IGNORED_NODE;
 814      }
 815      else {
 816          id = genId();
 817      }
 818      const serializedNode = Object.assign(_serializedNode, { id });
 819      n.__sn = serializedNode;
 820      if (id === IGNORED_NODE) {
 821          return null;
 822      }
 823      map[id] = n;
 824      if (onSerialize) {
 825          onSerialize(n);
 826      }
 827      let recordChild = !skipChild;
 828      if (serializedNode.type === NodeType$1.Element) {
 829          recordChild = recordChild && !serializedNode.needBlock;
 830          delete serializedNode.needBlock;
 831          if (n.shadowRoot)
 832              serializedNode.isShadowHost = true;
 833      }
 834      if ((serializedNode.type === NodeType$1.Document ||
 835          serializedNode.type === NodeType$1.Element) &&
 836          recordChild) {
 837          if (slimDOMOptions.headWhitespace &&
 838              _serializedNode.type === NodeType$1.Element &&
 839              _serializedNode.tagName === 'head') {
 840              preserveWhiteSpace = false;
 841          }
 842          const bypassOptions = {
 843              doc,
 844              map,
 845              blockClass,
 846              blockSelector,
 847              unblockSelector,
 848              maskTextClass,
 849              maskTextSelector,
 850              unmaskTextSelector,
 851              skipChild,
 852              inlineStylesheet,
 853              maskInputSelector,
 854              unmaskInputSelector,
 855              maskAllText,
 856              maskInputOptions,
 857              maskTextFn,
 858              maskInputFn,
 859              slimDOMOptions,
 860              dataURLOptions,
 861              inlineImages,
 862              recordCanvas,
 863              preserveWhiteSpace,
 864              onSerialize,
 865              onIframeLoad,
 866              iframeLoadTimeout,
 867              keepIframeSrcFn,
 868          };
 869          for (const childN of Array.from(n.childNodes)) {
 870              const serializedChildNode = serializeNodeWithId(childN, bypassOptions);
 871              if (serializedChildNode) {
 872                  serializedNode.childNodes.push(serializedChildNode);
 873              }
 874          }
 875          if (isElement(n) && n.shadowRoot) {
 876              for (const childN of Array.from(n.shadowRoot.childNodes)) {
 877                  const serializedChildNode = serializeNodeWithId(childN, bypassOptions);
 878                  if (serializedChildNode) {
 879                      serializedChildNode.isShadow = true;
 880                      serializedNode.childNodes.push(serializedChildNode);
 881                  }
 882              }
 883          }
 884      }
 885      if (n.parentNode && isShadowRoot(n.parentNode)) {
 886          serializedNode.isShadow = true;
 887      }
 888      if (serializedNode.type === NodeType$1.Element &&
 889          serializedNode.tagName === 'iframe') {
 890          onceIframeLoaded(n, () => {
 891              const iframeDoc = n.contentDocument;
 892              if (iframeDoc && onIframeLoad) {
 893                  const serializedIframeNode = serializeNodeWithId(iframeDoc, {
 894                      doc: iframeDoc,
 895                      map,
 896                      blockClass,
 897                      blockSelector,
 898                      unblockSelector,
 899                      maskTextClass,
 900                      maskTextSelector,
 901                      unmaskTextSelector,
 902                      skipChild: false,
 903                      inlineStylesheet,
 904                      maskInputSelector,
 905                      unmaskInputSelector,
 906                      maskAllText,
 907                      maskInputOptions,
 908                      maskTextFn,
 909                      maskInputFn,
 910                      slimDOMOptions,
 911                      dataURLOptions,
 912                      inlineImages,
 913                      recordCanvas,
 914                      preserveWhiteSpace,
 915                      onSerialize,
 916                      onIframeLoad,
 917                      iframeLoadTimeout,
 918                      keepIframeSrcFn,
 919                  });
 920                  if (serializedIframeNode) {
 921                      onIframeLoad(n, serializedIframeNode);
 922                  }
 923              }
 924          }, iframeLoadTimeout);
 925      }
 926      return serializedNode;
 927  }
 928  function snapshot(n, options) {
 929      const { blockClass = 'rr-block', blockSelector = null, unblockSelector = null, maskTextClass = 'rr-mask', maskTextSelector = null, unmaskTextSelector = null, inlineStylesheet = true, inlineImages = false, recordCanvas = false, maskInputSelector = null, unmaskInputSelector = null, maskAllText = false, maskAllInputs = false, maskTextFn, maskInputFn, slimDOM = false, dataURLOptions, preserveWhiteSpace, onSerialize, onIframeLoad, iframeLoadTimeout, keepIframeSrcFn = () => false, } = options || {};
 930      const idNodeMap = {};
 931      const maskInputOptions = maskAllInputs === true
 932          ? {
 933              color: true,
 934              date: true,
 935              'datetime-local': true,
 936              email: true,
 937              month: true,
 938              number: true,
 939              range: true,
 940              search: true,
 941              tel: true,
 942              text: true,
 943              time: true,
 944              url: true,
 945              week: true,
 946              textarea: true,
 947              select: true,
 948          }
 949          : maskAllInputs === false
 950              ? {}
 951              : maskAllInputs;
 952      const slimDOMOptions = slimDOM === true || slimDOM === 'all'
 953          ?
 954              {
 955                  script: true,
 956                  comment: true,
 957                  headFavicon: true,
 958                  headWhitespace: true,
 959                  headMetaDescKeywords: slimDOM === 'all',
 960                  headMetaSocial: true,
 961                  headMetaRobots: true,
 962                  headMetaHttpEquiv: true,
 963                  headMetaAuthorship: true,
 964                  headMetaVerification: true,
 965              }
 966          : slimDOM === false
 967              ? {}
 968              : slimDOM;
 969      return [
 970          serializeNodeWithId(n, {
 971              doc: n,
 972              map: idNodeMap,
 973              blockClass,
 974              blockSelector,
 975              unblockSelector,
 976              maskTextClass,
 977              maskTextSelector,
 978              unmaskTextSelector,
 979              skipChild: false,
 980              inlineStylesheet,
 981              maskInputSelector,
 982              unmaskInputSelector,
 983              maskAllText,
 984              maskInputOptions,
 985              maskTextFn,
 986              maskInputFn,
 987              slimDOMOptions,
 988              dataURLOptions,
 989              inlineImages,
 990              recordCanvas,
 991              preserveWhiteSpace,
 992              onSerialize,
 993              onIframeLoad,
 994              iframeLoadTimeout,
 995              keepIframeSrcFn,
 996          }),
 997          idNodeMap,
 998      ];
 999  }
1000  function skipAttribute(tagName, attributeName, value) {
1001      return ((tagName === 'video' || tagName === 'audio') && attributeName === 'autoplay');
1002  }
1003  
1004  var EventType;
1005  (function (EventType) {
1006      EventType[EventType["DomContentLoaded"] = 0] = "DomContentLoaded";
1007      EventType[EventType["Load"] = 1] = "Load";
1008      EventType[EventType["FullSnapshot"] = 2] = "FullSnapshot";
1009      EventType[EventType["IncrementalSnapshot"] = 3] = "IncrementalSnapshot";
1010      EventType[EventType["Meta"] = 4] = "Meta";
1011      EventType[EventType["Custom"] = 5] = "Custom";
1012      EventType[EventType["Plugin"] = 6] = "Plugin";
1013  })(EventType || (EventType = {}));
1014  var IncrementalSource;
1015  (function (IncrementalSource) {
1016      IncrementalSource[IncrementalSource["Mutation"] = 0] = "Mutation";
1017      IncrementalSource[IncrementalSource["MouseMove"] = 1] = "MouseMove";
1018      IncrementalSource[IncrementalSource["MouseInteraction"] = 2] = "MouseInteraction";
1019      IncrementalSource[IncrementalSource["Scroll"] = 3] = "Scroll";
1020      IncrementalSource[IncrementalSource["ViewportResize"] = 4] = "ViewportResize";
1021      IncrementalSource[IncrementalSource["Input"] = 5] = "Input";
1022      IncrementalSource[IncrementalSource["TouchMove"] = 6] = "TouchMove";
1023      IncrementalSource[IncrementalSource["MediaInteraction"] = 7] = "MediaInteraction";
1024      IncrementalSource[IncrementalSource["StyleSheetRule"] = 8] = "StyleSheetRule";
1025      IncrementalSource[IncrementalSource["CanvasMutation"] = 9] = "CanvasMutation";
1026      IncrementalSource[IncrementalSource["Font"] = 10] = "Font";
1027      IncrementalSource[IncrementalSource["Log"] = 11] = "Log";
1028      IncrementalSource[IncrementalSource["Drag"] = 12] = "Drag";
1029      IncrementalSource[IncrementalSource["StyleDeclaration"] = 13] = "StyleDeclaration";
1030  })(IncrementalSource || (IncrementalSource = {}));
1031  var MouseInteractions;
1032  (function (MouseInteractions) {
1033      MouseInteractions[MouseInteractions["MouseUp"] = 0] = "MouseUp";
1034      MouseInteractions[MouseInteractions["MouseDown"] = 1] = "MouseDown";
1035      MouseInteractions[MouseInteractions["Click"] = 2] = "Click";
1036      MouseInteractions[MouseInteractions["ContextMenu"] = 3] = "ContextMenu";
1037      MouseInteractions[MouseInteractions["DblClick"] = 4] = "DblClick";
1038      MouseInteractions[MouseInteractions["Focus"] = 5] = "Focus";
1039      MouseInteractions[MouseInteractions["Blur"] = 6] = "Blur";
1040      MouseInteractions[MouseInteractions["TouchStart"] = 7] = "TouchStart";
1041      MouseInteractions[MouseInteractions["TouchMove_Departed"] = 8] = "TouchMove_Departed";
1042      MouseInteractions[MouseInteractions["TouchEnd"] = 9] = "TouchEnd";
1043      MouseInteractions[MouseInteractions["TouchCancel"] = 10] = "TouchCancel";
1044  })(MouseInteractions || (MouseInteractions = {}));
1045  var CanvasContext;
1046  (function (CanvasContext) {
1047      CanvasContext[CanvasContext["2D"] = 0] = "2D";
1048      CanvasContext[CanvasContext["WebGL"] = 1] = "WebGL";
1049      CanvasContext[CanvasContext["WebGL2"] = 2] = "WebGL2";
1050  })(CanvasContext || (CanvasContext = {}));
1051  var MediaInteractions;
1052  (function (MediaInteractions) {
1053      MediaInteractions[MediaInteractions["Play"] = 0] = "Play";
1054      MediaInteractions[MediaInteractions["Pause"] = 1] = "Pause";
1055      MediaInteractions[MediaInteractions["Seeked"] = 2] = "Seeked";
1056      MediaInteractions[MediaInteractions["VolumeChange"] = 3] = "VolumeChange";
1057  })(MediaInteractions || (MediaInteractions = {}));
1058  var ReplayerEvents;
1059  (function (ReplayerEvents) {
1060      ReplayerEvents["Start"] = "start";
1061      ReplayerEvents["Pause"] = "pause";
1062      ReplayerEvents["Resume"] = "resume";
1063      ReplayerEvents["Resize"] = "resize";
1064      ReplayerEvents["Finish"] = "finish";
1065      ReplayerEvents["FullsnapshotRebuilded"] = "fullsnapshot-rebuilded";
1066      ReplayerEvents["LoadStylesheetStart"] = "load-stylesheet-start";
1067      ReplayerEvents["LoadStylesheetEnd"] = "load-stylesheet-end";
1068      ReplayerEvents["SkipStart"] = "skip-start";
1069      ReplayerEvents["SkipEnd"] = "skip-end";
1070      ReplayerEvents["MouseInteraction"] = "mouse-interaction";
1071      ReplayerEvents["EventCast"] = "event-cast";
1072      ReplayerEvents["CustomEvent"] = "custom-event";
1073      ReplayerEvents["Flush"] = "flush";
1074      ReplayerEvents["StateChange"] = "state-change";
1075      ReplayerEvents["PlayBack"] = "play-back";
1076  })(ReplayerEvents || (ReplayerEvents = {}));
1077  
1078  function on(type, fn, target = document) {
1079      const options = { capture: true, passive: true };
1080      target.addEventListener(type, fn, options);
1081      return () => target.removeEventListener(type, fn, options);
1082  }
1083  function createMirror() {
1084      return {
1085          map: {},
1086          getId(n) {
1087              if (!n || !n.__sn) {
1088                  return -1;
1089              }
1090              return n.__sn.id;
1091          },
1092          getNode(id) {
1093              return this.map[id] || null;
1094          },
1095          removeNodeFromMap(n) {
1096              const id = n.__sn && n.__sn.id;
1097              delete this.map[id];
1098              if (n.childNodes) {
1099                  n.childNodes.forEach((child) => this.removeNodeFromMap(child));
1100              }
1101          },
1102          has(id) {
1103              return this.map.hasOwnProperty(id);
1104          },
1105          reset() {
1106              this.map = {};
1107          },
1108      };
1109  }
1110  const DEPARTED_MIRROR_ACCESS_WARNING = 'Please stop import mirror directly. Instead of that,' +
1111      '\r\n' +
1112      'now you can use replayer.getMirror() to access the mirror instance of a replayer,' +
1113      '\r\n' +
1114      'or you can use record.mirror to access the mirror instance during recording.';
1115  let _mirror = {
1116      map: {},
1117      getId() {
1118          console.error(DEPARTED_MIRROR_ACCESS_WARNING);
1119          return -1;
1120      },
1121      getNode() {
1122          console.error(DEPARTED_MIRROR_ACCESS_WARNING);
1123          return null;
1124      },
1125      removeNodeFromMap() {
1126          console.error(DEPARTED_MIRROR_ACCESS_WARNING);
1127      },
1128      has() {
1129          console.error(DEPARTED_MIRROR_ACCESS_WARNING);
1130          return false;
1131      },
1132      reset() {
1133          console.error(DEPARTED_MIRROR_ACCESS_WARNING);
1134      },
1135  };
1136  if (typeof window !== 'undefined' && window.Proxy && window.Reflect) {
1137      _mirror = new Proxy(_mirror, {
1138          get(target, prop, receiver) {
1139              if (prop === 'map') {
1140                  console.error(DEPARTED_MIRROR_ACCESS_WARNING);
1141              }
1142              return Reflect.get(target, prop, receiver);
1143          },
1144      });
1145  }
1146  function throttle$1(func, wait, options = {}) {
1147      let timeout = null;
1148      let previous = 0;
1149      return function (arg) {
1150          let now = Date.now();
1151          if (!previous && options.leading === false) {
1152              previous = now;
1153          }
1154          let remaining = wait - (now - previous);
1155          let context = this;
1156          let args = arguments;
1157          if (remaining <= 0 || remaining > wait) {
1158              if (timeout) {
1159                  clearTimeout(timeout);
1160                  timeout = null;
1161              }
1162              previous = now;
1163              func.apply(context, args);
1164          }
1165          else if (!timeout && options.trailing !== false) {
1166              timeout = setTimeout(() => {
1167                  previous = options.leading === false ? 0 : Date.now();
1168                  timeout = null;
1169                  func.apply(context, args);
1170              }, remaining);
1171          }
1172      };
1173  }
1174  function hookSetter(target, key, d, isRevoked, win = window) {
1175      const original = win.Object.getOwnPropertyDescriptor(target, key);
1176      win.Object.defineProperty(target, key, isRevoked
1177          ? d
1178          : {
1179              set(value) {
1180                  setTimeout(() => {
1181                      d.set.call(this, value);
1182                  }, 0);
1183                  if (original && original.set) {
1184                      original.set.call(this, value);
1185                  }
1186              },
1187          });
1188      return () => hookSetter(target, key, original || {}, true);
1189  }
1190  function patch(source, name, replacement) {
1191      try {
1192          if (!(name in source)) {
1193              return () => { };
1194          }
1195          const original = source[name];
1196          const wrapped = replacement(original);
1197          if (typeof wrapped === 'function') {
1198              wrapped.prototype = wrapped.prototype || {};
1199              Object.defineProperties(wrapped, {
1200                  __rrweb_original__: {
1201                      enumerable: false,
1202                      value: original,
1203                  },
1204              });
1205          }
1206          source[name] = wrapped;
1207          return () => {
1208              source[name] = original;
1209          };
1210      }
1211      catch (_a) {
1212          return () => { };
1213      }
1214  }
1215  function getWindowHeight() {
1216      return (window.innerHeight ||
1217          (document.documentElement && document.documentElement.clientHeight) ||
1218          (document.body && document.body.clientHeight));
1219  }
1220  function getWindowWidth() {
1221      return (window.innerWidth ||
1222          (document.documentElement && document.documentElement.clientWidth) ||
1223          (document.body && document.body.clientWidth));
1224  }
1225  function isBlocked(node, blockClass, blockSelector, unblockSelector) {
1226      if (!node) {
1227          return false;
1228      }
1229      if (node.nodeType === node.ELEMENT_NODE) {
1230          let needBlock = false;
1231          const needUnblock = unblockSelector && node.matches(unblockSelector);
1232          if (typeof blockClass === 'string') {
1233              if (node.closest !== undefined) {
1234                  needBlock =
1235                      !needUnblock &&
1236                          node.closest('.' + blockClass) !== null;
1237              }
1238              else {
1239                  needBlock =
1240                      !needUnblock && node.classList.contains(blockClass);
1241              }
1242          }
1243          else {
1244              !needUnblock &&
1245                  node.classList.forEach((className) => {
1246                      if (blockClass.test(className)) {
1247                          needBlock = true;
1248                      }
1249                  });
1250          }
1251          if (!needBlock && blockSelector) {
1252              needBlock = node.matches(blockSelector);
1253          }
1254          return ((!needUnblock && needBlock) ||
1255              isBlocked(node.parentNode, blockClass, blockSelector, unblockSelector));
1256      }
1257      if (node.nodeType === node.TEXT_NODE) {
1258          return isBlocked(node.parentNode, blockClass, blockSelector, unblockSelector);
1259      }
1260      return isBlocked(node.parentNode, blockClass, blockSelector, unblockSelector);
1261  }
1262  function isIgnored(n) {
1263      if ('__sn' in n) {
1264          return n.__sn.id === IGNORED_NODE;
1265      }
1266      return false;
1267  }
1268  function isAncestorRemoved(target, mirror) {
1269      if (isShadowRoot(target)) {
1270          return false;
1271      }
1272      const id = mirror.getId(target);
1273      if (!mirror.has(id)) {
1274          return true;
1275      }
1276      if (target.parentNode &&
1277          target.parentNode.nodeType === target.DOCUMENT_NODE) {
1278          return false;
1279      }
1280      if (!target.parentNode) {
1281          return true;
1282      }
1283      return isAncestorRemoved(target.parentNode, mirror);
1284  }
1285  function isTouchEvent(event) {
1286      return Boolean(event.changedTouches);
1287  }
1288  function polyfill(win = window) {
1289      if ('NodeList' in win && !win.NodeList.prototype.forEach) {
1290          win.NodeList.prototype.forEach = Array.prototype
1291              .forEach;
1292      }
1293      if ('DOMTokenList' in win && !win.DOMTokenList.prototype.forEach) {
1294          win.DOMTokenList.prototype.forEach = Array.prototype
1295              .forEach;
1296      }
1297      if (!Node.prototype.contains) {
1298          Node.prototype.contains = function contains(node) {
1299              if (!(0 in arguments)) {
1300                  throw new TypeError('1 argument is required');
1301              }
1302              do {
1303                  if (this === node) {
1304                      return true;
1305                  }
1306              } while ((node = node && node.parentNode));
1307              return false;
1308          };
1309      }
1310  }
1311  function isIframeINode(node) {
1312      if ('__sn' in node) {
1313          return (node.__sn.type === NodeType$1.Element && node.__sn.tagName === 'iframe');
1314      }
1315      return false;
1316  }
1317  function hasShadowRoot(n) {
1318      return Boolean(n === null || n === void 0 ? void 0 : n.shadowRoot);
1319  }
1320  
1321  function isNodeInLinkedList(n) {
1322      return '__ln' in n;
1323  }
1324  class DoubleLinkedList {
1325      constructor() {
1326          this.length = 0;
1327          this.head = null;
1328      }
1329      get(position) {
1330          if (position >= this.length) {
1331              throw new Error('Position outside of list range');
1332          }
1333          let current = this.head;
1334          for (let index = 0; index < position; index++) {
1335              current = (current === null || current === void 0 ? void 0 : current.next) || null;
1336          }
1337          return current;
1338      }
1339      addNode(n) {
1340          const node = {
1341              value: n,
1342              previous: null,
1343              next: null,
1344          };
1345          n.__ln = node;
1346          if (n.previousSibling && isNodeInLinkedList(n.previousSibling)) {
1347              const current = n.previousSibling.__ln.next;
1348              node.next = current;
1349              node.previous = n.previousSibling.__ln;
1350              n.previousSibling.__ln.next = node;
1351              if (current) {
1352                  current.previous = node;
1353              }
1354          }
1355          else if (n.nextSibling &&
1356              isNodeInLinkedList(n.nextSibling) &&
1357              n.nextSibling.__ln.previous) {
1358              const current = n.nextSibling.__ln.previous;
1359              node.previous = current;
1360              node.next = n.nextSibling.__ln;
1361              n.nextSibling.__ln.previous = node;
1362              if (current) {
1363                  current.next = node;
1364              }
1365          }
1366          else {
1367              if (this.head) {
1368                  this.head.previous = node;
1369              }
1370              node.next = this.head;
1371              this.head = node;
1372          }
1373          this.length++;
1374      }
1375      removeNode(n) {
1376          const current = n.__ln;
1377          if (!this.head) {
1378              return;
1379          }
1380          if (!current.previous) {
1381              this.head = current.next;
1382              if (this.head) {
1383                  this.head.previous = null;
1384              }
1385          }
1386          else {
1387              current.previous.next = current.next;
1388              if (current.next) {
1389                  current.next.previous = current.previous;
1390              }
1391          }
1392          if (n.__ln) {
1393              delete n.__ln;
1394          }
1395          this.length--;
1396      }
1397  }
1398  const moveKey = (id, parentId) => `${id}@${parentId}`;
1399  function isINode(n) {
1400      return '__sn' in n;
1401  }
1402  class MutationBuffer {
1403      constructor() {
1404          this.frozen = false;
1405          this.locked = false;
1406          this.texts = [];
1407          this.attributes = [];
1408          this.removes = [];
1409          this.mapRemoves = [];
1410          this.movedMap = {};
1411          this.addedSet = new Set();
1412          this.movedSet = new Set();
1413          this.droppedSet = new Set();
1414          this.processMutations = (mutations) => {
1415              mutations.forEach(this.processMutation);
1416              this.emit();
1417          };
1418          this.emit = () => {
1419              if (this.frozen || this.locked) {
1420                  return;
1421              }
1422              const adds = [];
1423              const addList = new DoubleLinkedList();
1424              const getNextId = (n) => {
1425                  let ns = n;
1426                  let nextId = IGNORED_NODE;
1427                  while (nextId === IGNORED_NODE) {
1428                      ns = ns && ns.nextSibling;
1429                      nextId = ns && this.mirror.getId(ns);
1430                  }
1431                  return nextId;
1432              };
1433              const pushAdd = (n) => {
1434                  var _a, _b, _c, _d, _e;
1435                  const shadowHost = n.getRootNode
1436                      ? (_a = n.getRootNode()) === null || _a === void 0 ? void 0 : _a.host
1437                      : null;
1438                  let rootShadowHost = shadowHost;
1439                  while ((_c = (_b = rootShadowHost === null || rootShadowHost === void 0 ? void 0 : rootShadowHost.getRootNode) === null || _b === void 0 ? void 0 : _b.call(rootShadowHost)) === null || _c === void 0 ? void 0 : _c.host)
1440                      rootShadowHost =
1441                          ((_e = (_d = rootShadowHost === null || rootShadowHost === void 0 ? void 0 : rootShadowHost.getRootNode) === null || _d === void 0 ? void 0 : _d.call(rootShadowHost)) === null || _e === void 0 ? void 0 : _e.host) ||
1442                              null;
1443                  const notInDoc = !this.doc.contains(n) &&
1444                      (!rootShadowHost || !this.doc.contains(rootShadowHost));
1445                  if (!n.parentNode || notInDoc) {
1446                      return;
1447                  }
1448                  const parentId = isShadowRoot(n.parentNode)
1449                      ? this.mirror.getId(shadowHost)
1450                      : this.mirror.getId(n.parentNode);
1451                  const nextId = getNextId(n);
1452                  if (parentId === -1 || nextId === -1) {
1453                      return addList.addNode(n);
1454                  }
1455                  let sn = serializeNodeWithId(n, {
1456                      doc: this.doc,
1457                      map: this.mirror.map,
1458                      blockClass: this.blockClass,
1459                      blockSelector: this.blockSelector,
1460                      unblockSelector: this.unblockSelector,
1461                      maskTextClass: this.maskTextClass,
1462                      maskTextSelector: this.maskTextSelector,
1463                      unmaskTextSelector: this.unmaskTextSelector,
1464                      maskInputSelector: this.maskInputSelector,
1465                      unmaskInputSelector: this.unmaskInputSelector,
1466                      skipChild: true,
1467                      inlineStylesheet: this.inlineStylesheet,
1468                      maskAllText: this.maskAllText,
1469                      maskInputOptions: this.maskInputOptions,
1470                      maskTextFn: this.maskTextFn,
1471                      maskInputFn: this.maskInputFn,
1472                      slimDOMOptions: this.slimDOMOptions,
1473                      recordCanvas: this.recordCanvas,
1474                      inlineImages: this.inlineImages,
1475                      onSerialize: (currentN) => {
1476                          if (isIframeINode(currentN)) {
1477                              this.iframeManager.addIframe(currentN);
1478                          }
1479                          if (hasShadowRoot(n)) {
1480                              this.shadowDomManager.addShadowRoot(n.shadowRoot, document);
1481                          }
1482                      },
1483                      onIframeLoad: (iframe, childSn) => {
1484                          this.iframeManager.attachIframe(iframe, childSn);
1485                          this.shadowDomManager.observeAttachShadow(iframe);
1486                      },
1487                  });
1488                  if (sn) {
1489                      adds.push({
1490                          parentId,
1491                          nextId,
1492                          node: sn,
1493                      });
1494                  }
1495              };
1496              while (this.mapRemoves.length) {
1497                  this.mirror.removeNodeFromMap(this.mapRemoves.shift());
1498              }
1499              for (const n of this.movedSet) {
1500                  if (isParentRemoved(this.removes, n, this.mirror) &&
1501                      !this.movedSet.has(n.parentNode)) {
1502                      continue;
1503                  }
1504                  pushAdd(n);
1505              }
1506              for (const n of this.addedSet) {
1507                  if (!isAncestorInSet(this.droppedSet, n) &&
1508                      !isParentRemoved(this.removes, n, this.mirror)) {
1509                      pushAdd(n);
1510                  }
1511                  else if (isAncestorInSet(this.movedSet, n)) {
1512                      pushAdd(n);
1513                  }
1514                  else {
1515                      this.droppedSet.add(n);
1516                  }
1517              }
1518              let candidate = null;
1519              while (addList.length) {
1520                  let node = null;
1521                  if (candidate) {
1522                      const parentId = this.mirror.getId(candidate.value.parentNode);
1523                      const nextId = getNextId(candidate.value);
1524                      if (parentId !== -1 && nextId !== -1) {
1525                          node = candidate;
1526                      }
1527                  }
1528                  if (!node) {
1529                      for (let index = addList.length - 1; index >= 0; index--) {
1530                          const _node = addList.get(index);
1531                          if (_node) {
1532                              const parentId = this.mirror.getId(_node.value.parentNode);
1533                              const nextId = getNextId(_node.value);
1534                              if (parentId !== -1 && nextId !== -1) {
1535                                  node = _node;
1536                                  break;
1537                              }
1538                          }
1539                      }
1540                  }
1541                  if (!node) {
1542                      while (addList.head) {
1543                          addList.removeNode(addList.head.value);
1544                      }
1545                      break;
1546                  }
1547                  candidate = node.previous;
1548                  addList.removeNode(node.value);
1549                  pushAdd(node.value);
1550              }
1551              const payload = {
1552                  texts: this.texts
1553                      .map((text) => ({
1554                      id: this.mirror.getId(text.node),
1555                      value: text.value,
1556                  }))
1557                      .filter((text) => this.mirror.has(text.id)),
1558                  attributes: this.attributes
1559                      .map((attribute) => ({
1560                      id: this.mirror.getId(attribute.node),
1561                      attributes: attribute.attributes,
1562                  }))
1563                      .filter((attribute) => this.mirror.has(attribute.id)),
1564                  removes: this.removes,
1565                  adds,
1566              };
1567              if (!payload.texts.length &&
1568                  !payload.attributes.length &&
1569                  !payload.removes.length &&
1570                  !payload.adds.length) {
1571                  return;
1572              }
1573              this.texts = [];
1574              this.attributes = [];
1575              this.removes = [];
1576              this.addedSet = new Set();
1577              this.movedSet = new Set();
1578              this.droppedSet = new Set();
1579              this.movedMap = {};
1580              this.mutationCb(payload);
1581          };
1582          this.processMutation = (m) => {
1583              if (isIgnored(m.target)) {
1584                  return;
1585              }
1586              switch (m.type) {
1587                  case 'characterData': {
1588                      const value = m.target.textContent;
1589                      if (!isBlocked(m.target, this.blockClass, this.blockSelector, this.unblockSelector) && value !== m.oldValue) {
1590                          this.texts.push({
1591                              value: needMaskingText(m.target, this.maskTextClass, this.maskTextSelector, this.unmaskTextSelector, this.maskAllText) && value
1592                                  ? this.maskTextFn
1593                                      ? this.maskTextFn(value)
1594                                      : value.replace(/[\S]/g, '*')
1595                                  : value,
1596                              node: m.target,
1597                          });
1598                      }
1599                      break;
1600                  }
1601                  case 'attributes': {
1602                      const target = m.target;
1603                      let value = target.getAttribute(m.attributeName);
1604                      if (m.attributeName === 'value') {
1605                          value = maskInputValue({
1606                              input: target,
1607                              maskInputSelector: this.maskInputSelector,
1608                              unmaskInputSelector: this.unmaskInputSelector,
1609                              maskInputOptions: this.maskInputOptions,
1610                              tagName: target.tagName,
1611                              type: target.getAttribute('type'),
1612                              value,
1613                              maskInputFn: this.maskInputFn,
1614                          });
1615                      }
1616                      if (isBlocked(m.target, this.blockClass, this.blockSelector, this.unblockSelector) || value === m.oldValue) {
1617                          return;
1618                      }
1619                      let item = this.attributes.find((a) => a.node === m.target);
1620                      if (!item) {
1621                          item = {
1622                              node: m.target,
1623                              attributes: {},
1624                          };
1625                          this.attributes.push(item);
1626                      }
1627                      if (m.attributeName === 'type' &&
1628                          target.tagName === 'INPUT' &&
1629                          (m.oldValue || '').toLowerCase() === 'password') {
1630                          target.setAttribute('data-rr-is-password', 'true');
1631                      }
1632                      if (m.attributeName === 'style') {
1633                          const old = this.doc.createElement('span');
1634                          if (m.oldValue) {
1635                              old.setAttribute('style', m.oldValue);
1636                          }
1637                          if (item.attributes.style === undefined ||
1638                              item.attributes.style === null) {
1639                              item.attributes.style = {};
1640                          }
1641                          try {
1642                              const styleObj = item.attributes.style;
1643                              for (const pname of Array.from(target.style)) {
1644                                  const newValue = target.style.getPropertyValue(pname);
1645                                  const newPriority = target.style.getPropertyPriority(pname);
1646                                  if (newValue !== old.style.getPropertyValue(pname) ||
1647                                      newPriority !== old.style.getPropertyPriority(pname)) {
1648                                      if (newPriority === '') {
1649                                          styleObj[pname] = newValue;
1650                                      }
1651                                      else {
1652                                          styleObj[pname] = [newValue, newPriority];
1653                                      }
1654                                  }
1655                              }
1656                              for (const pname of Array.from(old.style)) {
1657                                  if (target.style.getPropertyValue(pname) === '') {
1658                                      styleObj[pname] = false;
1659                                  }
1660                              }
1661                          }
1662                          catch (error) {
1663                              console.warn('[rrweb] Error when parsing update to style attribute:', error);
1664                          }
1665                      }
1666                      else {
1667                          const element = m.target;
1668                          item.attributes[m.attributeName] = transformAttribute(this.doc, element, element.tagName, m.attributeName, value, this.maskAllText, this.unmaskTextSelector, this.maskTextFn);
1669                      }
1670                      break;
1671                  }
1672                  case 'childList': {
1673                      m.addedNodes.forEach((n) => this.genAdds(n, m.target));
1674                      m.removedNodes.forEach((n) => {
1675                          const nodeId = this.mirror.getId(n);
1676                          const parentId = isShadowRoot(m.target)
1677                              ? this.mirror.getId(m.target.host)
1678                              : this.mirror.getId(m.target);
1679                          if (isBlocked(m.target, this.blockClass, this.blockSelector, this.unblockSelector) || isIgnored(n)) {
1680                              return;
1681                          }
1682                          if (this.addedSet.has(n)) {
1683                              deepDelete(this.addedSet, n);
1684                              this.droppedSet.add(n);
1685                          }
1686                          else if (this.addedSet.has(m.target) && nodeId === -1) ;
1687                          else if (isAncestorRemoved(m.target, this.mirror)) ;
1688                          else if (this.movedSet.has(n) &&
1689                              this.movedMap[moveKey(nodeId, parentId)]) {
1690                              deepDelete(this.movedSet, n);
1691                          }
1692                          else {
1693                              this.removes.push({
1694                                  parentId,
1695                                  id: nodeId,
1696                                  isShadow: isShadowRoot(m.target) ? true : undefined,
1697                              });
1698                          }
1699                          this.mapRemoves.push(n);
1700                      });
1701                      break;
1702                  }
1703              }
1704          };
1705          this.genAdds = (n, target) => {
1706              if (target && isBlocked(target, this.blockClass, this.blockSelector, this.unblockSelector)) {
1707                  return;
1708              }
1709              if (isINode(n)) {
1710                  if (isIgnored(n)) {
1711                      return;
1712                  }
1713                  this.movedSet.add(n);
1714                  let targetId = null;
1715                  if (target && isINode(target)) {
1716                      targetId = target.__sn.id;
1717                  }
1718                  if (targetId) {
1719                      this.movedMap[moveKey(n.__sn.id, targetId)] = true;
1720                  }
1721              }
1722              else {
1723                  this.addedSet.add(n);
1724                  this.droppedSet.delete(n);
1725              }
1726              if (!isBlocked(n, this.blockClass, this.blockSelector, this.unblockSelector))
1727                  n.childNodes.forEach((childN) => this.genAdds(childN));
1728          };
1729      }
1730      init(options) {
1731          [
1732              'mutationCb',
1733              'blockClass',
1734              'blockSelector',
1735              'unblockSelector',
1736              'maskTextClass',
1737              'maskTextSelector',
1738              'unmaskTextSelector',
1739              'maskInputSelector',
1740              'unmaskInputSelector',
1741              'inlineStylesheet',
1742              'maskAllText',
1743              'maskInputOptions',
1744              'maskTextFn',
1745              'maskInputFn',
1746              'recordCanvas',
1747              'inlineImages',
1748              'slimDOMOptions',
1749              'doc',
1750              'mirror',
1751              'iframeManager',
1752              'shadowDomManager',
1753              'canvasManager',
1754          ].forEach((key) => {
1755              this[key] = options[key];
1756          });
1757      }
1758      freeze() {
1759          this.frozen = true;
1760          this.canvasManager.freeze();
1761      }
1762      unfreeze() {
1763          this.frozen = false;
1764          this.canvasManager.unfreeze();
1765          this.emit();
1766      }
1767      isFrozen() {
1768          return this.frozen;
1769      }
1770      lock() {
1771          this.locked = true;
1772          this.canvasManager.lock();
1773      }
1774      unlock() {
1775          this.locked = false;
1776          this.canvasManager.unlock();
1777          this.emit();
1778      }
1779      reset() {
1780          this.shadowDomManager.reset();
1781          this.canvasManager.reset();
1782      }
1783  }
1784  function deepDelete(addsSet, n) {
1785      addsSet.delete(n);
1786      n.childNodes.forEach((childN) => deepDelete(addsSet, childN));
1787  }
1788  function isParentRemoved(removes, n, mirror) {
1789      const { parentNode } = n;
1790      if (!parentNode) {
1791          return false;
1792      }
1793      const parentId = mirror.getId(parentNode);
1794      if (removes.some((r) => r.id === parentId)) {
1795          return true;
1796      }
1797      return isParentRemoved(removes, parentNode, mirror);
1798  }
1799  function isAncestorInSet(set, n) {
1800      const { parentNode } = n;
1801      if (!parentNode) {
1802          return false;
1803      }
1804      if (set.has(parentNode)) {
1805          return true;
1806      }
1807      return isAncestorInSet(set, parentNode);
1808  }
1809  
1810  const callbackWrapper = (cb) => {
1811      const rrwebWrapped = (...rest) => {
1812          try {
1813              return cb(...rest);
1814          }
1815          catch (error) {
1816              try {
1817                  error.__rrweb__ = true;
1818              }
1819              catch (_a) {
1820              }
1821              throw error;
1822          }
1823      };
1824      return rrwebWrapped;
1825  };
1826  
1827  const mutationBuffers = [];
1828  function getEventTarget(event) {
1829      try {
1830          if ('composedPath' in event) {
1831              const path = event.composedPath();
1832              if (path.length) {
1833                  return path[0];
1834              }
1835          }
1836          else if ('path' in event && event.path.length) {
1837              return event.path[0];
1838          }
1839      }
1840      catch (_a) { }
1841      return event && event.target;
1842  }
1843  function initMutationObserver(options, rootEl) {
1844      var _a, _b;
1845      const mutationBuffer = new MutationBuffer();
1846      mutationBuffers.push(mutationBuffer);
1847      mutationBuffer.init(options);
1848      let mutationObserverCtor = window.MutationObserver ||
1849          window.__rrMutationObserver;
1850      const angularZoneSymbol = (_b = (_a = window === null || window === void 0 ? void 0 : window.Zone) === null || _a === void 0 ? void 0 : _a.__symbol__) === null || _b === void 0 ? void 0 : _b.call(_a, 'MutationObserver');
1851      if (angularZoneSymbol &&
1852          window[angularZoneSymbol]) {
1853          mutationObserverCtor = window[angularZoneSymbol];
1854      }
1855      const observer = new mutationObserverCtor(callbackWrapper((mutations) => {
1856          if (options.onMutation && options.onMutation(mutations) === false) {
1857              return;
1858          }
1859          mutationBuffer.processMutations(mutations);
1860      }));
1861      observer.observe(rootEl, {
1862          attributes: true,
1863          attributeOldValue: true,
1864          characterData: true,
1865          characterDataOldValue: true,
1866          childList: true,
1867          subtree: true,
1868      });
1869      return observer;
1870  }
1871  function initMoveObserver({ mousemoveCb, sampling, doc, mirror, }) {
1872      if (sampling.mousemove === false) {
1873          return () => { };
1874      }
1875      const threshold = typeof sampling.mousemove === 'number' ? sampling.mousemove : 50;
1876      const callbackThreshold = typeof sampling.mousemoveCallback === 'number'
1877          ? sampling.mousemoveCallback
1878          : 500;
1879      let positions = [];
1880      let timeBaseline;
1881      const wrappedCb = throttle$1((source) => {
1882          const totalOffset = Date.now() - timeBaseline;
1883          callbackWrapper(mousemoveCb)(positions.map((p) => {
1884              p.timeOffset -= totalOffset;
1885              return p;
1886          }), source);
1887          positions = [];
1888          timeBaseline = null;
1889      }, callbackThreshold);
1890      const updatePosition = throttle$1((evt) => {
1891          const target = getEventTarget(evt);
1892          const { clientX, clientY } = isTouchEvent(evt)
1893              ? evt.changedTouches[0]
1894              : evt;
1895          if (!timeBaseline) {
1896              timeBaseline = Date.now();
1897          }
1898          positions.push({
1899              x: clientX,
1900              y: clientY,
1901              id: mirror.getId(target),
1902              timeOffset: Date.now() - timeBaseline,
1903          });
1904          wrappedCb(typeof DragEvent !== 'undefined' && evt instanceof DragEvent
1905              ? IncrementalSource.Drag
1906              : evt instanceof MouseEvent
1907                  ? IncrementalSource.MouseMove
1908                  : IncrementalSource.TouchMove);
1909      }, threshold, {
1910          trailing: false,
1911      });
1912      const handlers = [
1913          on('mousemove', callbackWrapper(updatePosition), doc),
1914          on('touchmove', callbackWrapper(updatePosition), doc),
1915          on('drag', callbackWrapper(updatePosition), doc),
1916      ];
1917      return callbackWrapper(() => {
1918          handlers.forEach((h) => h());
1919      });
1920  }
1921  function initMouseInteractionObserver({ mouseInteractionCb, doc, mirror, blockClass, blockSelector, unblockSelector, sampling, }) {
1922      if (sampling.mouseInteraction === false) {
1923          return () => { };
1924      }
1925      const disableMap = sampling.mouseInteraction === true ||
1926          sampling.mouseInteraction === undefined
1927          ? {}
1928          : sampling.mouseInteraction;
1929      const handlers = [];
1930      const getHandler = (eventKey) => {
1931          return (event) => {
1932              const target = getEventTarget(event);
1933              if (isBlocked(target, blockClass, blockSelector, unblockSelector)) {
1934                  return;
1935              }
1936              const e = isTouchEvent(event) ? event.changedTouches[0] : event;
1937              if (!e) {
1938                  return;
1939              }
1940              const id = mirror.getId(target);
1941              const { clientX, clientY } = e;
1942              callbackWrapper(mouseInteractionCb)({
1943                  type: MouseInteractions[eventKey],
1944                  id,
1945                  x: clientX,
1946                  y: clientY,
1947              });
1948          };
1949      };
1950      Object.keys(MouseInteractions)
1951          .filter((key) => Number.isNaN(Number(key)) &&
1952          !key.endsWith('_Departed') &&
1953          disableMap[key] !== false)
1954          .forEach((eventKey) => {
1955          const eventName = eventKey.toLowerCase();
1956          const handler = callbackWrapper(getHandler(eventKey));
1957          handlers.push(on(eventName, handler, doc));
1958      });
1959      return callbackWrapper(() => {
1960          handlers.forEach((h) => h());
1961      });
1962  }
1963  function initScrollObserver({ scrollCb, doc, mirror, blockClass, blockSelector, unblockSelector, sampling, }) {
1964      const updatePosition = throttle$1((evt) => {
1965          const target = getEventTarget(evt);
1966          if (!target ||
1967              isBlocked(target, blockClass, blockSelector, unblockSelector)) {
1968              return;
1969          }
1970          const id = mirror.getId(target);
1971          if (target === doc) {
1972              const scrollEl = (doc.scrollingElement || doc.documentElement);
1973              callbackWrapper(scrollCb)({
1974                  id,
1975                  x: scrollEl.scrollLeft,
1976                  y: scrollEl.scrollTop,
1977              });
1978          }
1979          else {
1980              callbackWrapper(scrollCb)({
1981                  id,
1982                  x: target.scrollLeft,
1983                  y: target.scrollTop,
1984              });
1985          }
1986      }, sampling.scroll || 100);
1987      return on('scroll', callbackWrapper(updatePosition), doc);
1988  }
1989  function initViewportResizeObserver({ viewportResizeCb, }) {
1990      let lastH = -1;
1991      let lastW = -1;
1992      const updateDimension = throttle$1(() => {
1993          const height = getWindowHeight();
1994          const width = getWindowWidth();
1995          if (lastH !== height || lastW !== width) {
1996              callbackWrapper(viewportResizeCb)({
1997                  width: Number(width),
1998                  height: Number(height),
1999              });
2000              lastH = height;
2001              lastW = width;
2002          }
2003      }, 200);
2004      return on('resize', callbackWrapper(updateDimension), window);
2005  }
2006  function wrapEventWithUserTriggeredFlag(v, enable) {
2007      const value = Object.assign({}, v);
2008      if (!enable)
2009          delete value.userTriggered;
2010      return value;
2011  }
2012  const INPUT_TAGS = ['INPUT', 'TEXTAREA', 'SELECT'];
2013  const lastInputValueMap = new WeakMap();
2014  function initInputObserver({ inputCb, doc, mirror, blockClass, blockSelector, unblockSelector, ignoreClass, ignoreSelector, maskInputSelector, unmaskInputSelector, maskInputOptions, maskInputFn, sampling, userTriggeredOnInput, }) {
2015      function eventHandler(event) {
2016          let target = getEventTarget(event);
2017          const tagName = target && target.tagName;
2018          const userTriggered = event.isTrusted;
2019          if (tagName === 'OPTION')
2020              target = target.parentElement;
2021          if (!target ||
2022              !tagName ||
2023              INPUT_TAGS.indexOf(tagName) < 0 ||
2024              isBlocked(target, blockClass, blockSelector, unblockSelector)) {
2025              return;
2026          }
2027          const el = target;
2028          const type = getInputType(el);
2029          if (el.classList.contains(ignoreClass) ||
2030              (ignoreSelector && el.matches(ignoreSelector))) {
2031              return;
2032          }
2033          let text = getInputValue(el, tagName, type);
2034          let isChecked = false;
2035          if (type === 'radio' || type === 'checkbox') {
2036              isChecked = target.checked;
2037          }
2038          if (hasInputMaskOptions({
2039              maskInputOptions,
2040              maskInputSelector,
2041              tagName,
2042              type,
2043          })) {
2044              text = maskInputValue({
2045                  input: el,
2046                  maskInputOptions,
2047                  maskInputSelector,
2048                  unmaskInputSelector,
2049                  tagName,
2050                  type,
2051                  value: text,
2052                  maskInputFn,
2053              });
2054          }
2055          cbWithDedup(target, callbackWrapper(wrapEventWithUserTriggeredFlag)({ text, isChecked, userTriggered }, userTriggeredOnInput));
2056          const name = target.name;
2057          if (type === 'radio' && name && isChecked) {
2058              doc
2059                  .querySelectorAll(`input[type="radio"][name="${name}"]`)
2060                  .forEach((el) => {
2061                  if (el !== target) {
2062                      const text = maskInputValue({
2063                          input: el,
2064                          maskInputOptions,
2065                          maskInputSelector,
2066                          unmaskInputSelector,
2067                          tagName,
2068                          type,
2069                          value: getInputValue(el, tagName, type),
2070                          maskInputFn,
2071                      });
2072                      cbWithDedup(el, callbackWrapper(wrapEventWithUserTriggeredFlag)({
2073                          text,
2074                          isChecked: !isChecked,
2075                          userTriggered: false,
2076                      }, userTriggeredOnInput));
2077                  }
2078              });
2079          }
2080      }
2081      function cbWithDedup(target, v) {
2082          const lastInputValue = lastInputValueMap.get(target);
2083          if (!lastInputValue ||
2084              lastInputValue.text !== v.text ||
2085              lastInputValue.isChecked !== v.isChecked) {
2086              lastInputValueMap.set(target, v);
2087              const id = mirror.getId(target);
2088              inputCb(Object.assign(Object.assign({}, v), { id }));
2089          }
2090      }
2091      const events = sampling.input === 'last' ? ['change'] : ['input', 'change'];
2092      const handlers = events.map((eventName) => on(eventName, callbackWrapper(eventHandler), doc));
2093      const propertyDescriptor = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'value');
2094      const hookProperties = [
2095          [HTMLInputElement.prototype, 'value'],
2096          [HTMLInputElement.prototype, 'checked'],
2097          [HTMLSelectElement.prototype, 'value'],
2098          [HTMLTextAreaElement.prototype, 'value'],
2099          [HTMLSelectElement.prototype, 'selectedIndex'],
2100          [HTMLOptionElement.prototype, 'selected'],
2101      ];
2102      if (propertyDescriptor && propertyDescriptor.set) {
2103          handlers.push(...hookProperties.map((p) => hookSetter(p[0], p[1], {
2104              set() {
2105                  callbackWrapper(eventHandler)({ target: this });
2106              },
2107          })));
2108      }
2109      return callbackWrapper(() => {
2110          handlers.forEach((h) => h());
2111      });
2112  }
2113  function getNestedCSSRulePositions(rule) {
2114      const positions = [];
2115      function recurse(childRule, pos) {
2116          if ((hasNestedCSSRule('CSSGroupingRule') &&
2117              childRule.parentRule instanceof CSSGroupingRule) ||
2118              (hasNestedCSSRule('CSSMediaRule') &&
2119                  childRule.parentRule instanceof CSSMediaRule) ||
2120              (hasNestedCSSRule('CSSSupportsRule') &&
2121                  childRule.parentRule instanceof CSSSupportsRule) ||
2122              (hasNestedCSSRule('CSSConditionRule') &&
2123                  childRule.parentRule instanceof CSSConditionRule)) {
2124              const rules = Array.from(childRule.parentRule.cssRules);
2125              const index = rules.indexOf(childRule);
2126              pos.unshift(index);
2127          }
2128          else {
2129              const rules = Array.from(childRule.parentStyleSheet.cssRules);
2130              const index = rules.indexOf(childRule);
2131              pos.unshift(index);
2132          }
2133          return pos;
2134      }
2135      return recurse(rule, positions);
2136  }
2137  function initStyleSheetObserver({ styleSheetRuleCb, mirror }, { win }) {
2138      if (!win.CSSStyleSheet || !win.CSSStyleSheet.prototype) {
2139          return () => { };
2140      }
2141      const insertRule = win.CSSStyleSheet.prototype.insertRule;
2142      win.CSSStyleSheet.prototype.insertRule = new Proxy(insertRule, {
2143          apply: callbackWrapper((target, thisArg, argumentsList) => {
2144              const [rule, index] = argumentsList;
2145              const id = mirror.getId(thisArg.ownerNode);
2146              if (id !== -1) {
2147                  styleSheetRuleCb({
2148                      id,
2149                      adds: [{ rule, index }],
2150                  });
2151              }
2152              return target.apply(thisArg, argumentsList);
2153          }),
2154      });
2155      const deleteRule = win.CSSStyleSheet.prototype.deleteRule;
2156      win.CSSStyleSheet.prototype.deleteRule = new Proxy(deleteRule, {
2157          apply: callbackWrapper((target, thisArg, argumentsList) => {
2158              const [index] = argumentsList;
2159              const id = mirror.getId(thisArg.ownerNode);
2160              if (id !== -1) {
2161                  styleSheetRuleCb({
2162                      id,
2163                      removes: [{ index }],
2164                  });
2165              }
2166              return target.apply(thisArg, argumentsList);
2167          }),
2168      });
2169      const supportedNestedCSSRuleTypes = {};
2170      if (canMonkeyPatchNestedCSSRule('CSSGroupingRule')) {
2171          supportedNestedCSSRuleTypes.CSSGroupingRule = win.CSSGroupingRule;
2172      }
2173      else {
2174          if (canMonkeyPatchNestedCSSRule('CSSMediaRule')) {
2175              supportedNestedCSSRuleTypes.CSSMediaRule = win.CSSMediaRule;
2176          }
2177          if (canMonkeyPatchNestedCSSRule('CSSConditionRule')) {
2178              supportedNestedCSSRuleTypes.CSSConditionRule = win.CSSConditionRule;
2179          }
2180          if (canMonkeyPatchNestedCSSRule('CSSSupportsRule')) {
2181              supportedNestedCSSRuleTypes.CSSSupportsRule = win.CSSSupportsRule;
2182          }
2183      }
2184      const unmodifiedFunctions = {};
2185      Object.entries(supportedNestedCSSRuleTypes).forEach(([typeKey, type]) => {
2186          unmodifiedFunctions[typeKey] = {
2187              insertRule: type.prototype.insertRule,
2188              deleteRule: type.prototype.deleteRule,
2189          };
2190          type.prototype.insertRule = new Proxy(unmodifiedFunctions[typeKey].insertRule, {
2191              apply: callbackWrapper((target, thisArg, argumentsList) => {
2192                  const [rule, index] = argumentsList;
2193                  const id = mirror.getId(thisArg.parentStyleSheet.ownerNode);
2194                  if (id !== -1) {
2195                      styleSheetRuleCb({
2196                          id,
2197                          adds: [
2198                              {
2199                                  rule,
2200                                  index: [
2201                                      ...getNestedCSSRulePositions(thisArg),
2202                                      index || 0,
2203                                  ],
2204                              },
2205                          ],
2206                      });
2207                  }
2208                  return target.apply(thisArg, argumentsList);
2209              }),
2210          });
2211          type.prototype.deleteRule = new Proxy(unmodifiedFunctions[typeKey].deleteRule, {
2212              apply: callbackWrapper((target, thisArg, argumentsList) => {
2213                  const [index] = argumentsList;
2214                  const id = mirror.getId(thisArg.parentStyleSheet.ownerNode);
2215                  if (id !== -1) {
2216                      styleSheetRuleCb({
2217                          id,
2218                          removes: [
2219                              { index: [...getNestedCSSRulePositions(thisArg), index] },
2220                          ],
2221                      });
2222                  }
2223                  return target.apply(thisArg, argumentsList);
2224              }),
2225          });
2226      });
2227      return callbackWrapper(() => {
2228          win.CSSStyleSheet.prototype.insertRule = insertRule;
2229          win.CSSStyleSheet.prototype.deleteRule = deleteRule;
2230          Object.entries(supportedNestedCSSRuleTypes).forEach(([typeKey, type]) => {
2231              type.prototype.insertRule = unmodifiedFunctions[typeKey].insertRule;
2232              type.prototype.deleteRule = unmodifiedFunctions[typeKey].deleteRule;
2233          });
2234      });
2235  }
2236  function initStyleDeclarationObserver({ styleDeclarationCb, mirror }, { win }) {
2237      const setProperty = win.CSSStyleDeclaration.prototype.setProperty;
2238      win.CSSStyleDeclaration.prototype.setProperty = new Proxy(setProperty, {
2239          apply: callbackWrapper((target, thisArg, argumentsList) => {
2240              var _a, _b;
2241              const [property, value, priority] = argumentsList;
2242              const id = mirror.getId((_b = (_a = thisArg.parentRule) === null || _a === void 0 ? void 0 : _a.parentStyleSheet) === null || _b === void 0 ? void 0 : _b.ownerNode);
2243              if (id !== -1) {
2244                  styleDeclarationCb({
2245                      id,
2246                      set: {
2247                          property,
2248                          value,
2249                          priority,
2250                      },
2251                      index: getNestedCSSRulePositions(thisArg.parentRule),
2252                  });
2253              }
2254              return target.apply(thisArg, argumentsList);
2255          }),
2256      });
2257      const removeProperty = win.CSSStyleDeclaration.prototype.removeProperty;
2258      win.CSSStyleDeclaration.prototype.removeProperty = new Proxy(removeProperty, {
2259          apply: callbackWrapper((target, thisArg, argumentsList) => {
2260              var _a, _b;
2261              const [property] = argumentsList;
2262              const id = mirror.getId((_b = (_a = thisArg.parentRule) === null || _a === void 0 ? void 0 : _a.parentStyleSheet) === null || _b === void 0 ? void 0 : _b.ownerNode);
2263              if (id !== -1) {
2264                  styleDeclarationCb({
2265                      id,
2266                      remove: {
2267                          property,
2268                      },
2269                      index: getNestedCSSRulePositions(thisArg.parentRule),
2270                  });
2271              }
2272              return target.apply(thisArg, argumentsList);
2273          }),
2274      });
2275      return callbackWrapper(() => {
2276          win.CSSStyleDeclaration.prototype.setProperty = setProperty;
2277          win.CSSStyleDeclaration.prototype.removeProperty = removeProperty;
2278      });
2279  }
2280  function initMediaInteractionObserver({ mediaInteractionCb, blockClass, blockSelector, unblockSelector, mirror, sampling, }) {
2281      const handler = (type) => throttle$1(callbackWrapper((event) => {
2282          const target = getEventTarget(event);
2283          if (!target ||
2284              isBlocked(target, blockClass, blockSelector, unblockSelector)) {
2285              return;
2286          }
2287          const { currentTime, volume, muted } = target;
2288          mediaInteractionCb({
2289              type,
2290              id: mirror.getId(target),
2291              currentTime,
2292              volume,
2293              muted,
2294          });
2295      }), sampling.media || 500);
2296      const handlers = [
2297          on('play', handler(0)),
2298          on('pause', handler(1)),
2299          on('seeked', handler(2)),
2300          on('volumechange', handler(3)),
2301      ];
2302      return callbackWrapper(() => {
2303          handlers.forEach((h) => h());
2304      });
2305  }
2306  function initFontObserver({ fontCb, doc }) {
2307      const win = doc.defaultView;
2308      if (!win) {
2309          return () => { };
2310      }
2311      const handlers = [];
2312      const fontMap = new WeakMap();
2313      const originalFontFace = win.FontFace;
2314      win.FontFace = function FontFace(family, source, descriptors) {
2315          const fontFace = new originalFontFace(family, source, descriptors);
2316          fontMap.set(fontFace, {
2317              family,
2318              buffer: typeof source !== 'string',
2319              descriptors,
2320              fontSource: typeof source === 'string'
2321                  ? source
2322                  :
2323                      JSON.stringify(Array.from(new Uint8Array(source))),
2324          });
2325          return fontFace;
2326      };
2327      const restoreHandler = patch(doc.fonts, 'add', function (original) {
2328          return function (fontFace) {
2329              setTimeout(() => {
2330                  const p = fontMap.get(fontFace);
2331                  if (p) {
2332                      fontCb(p);
2333                      fontMap.delete(fontFace);
2334                  }
2335              }, 0);
2336              return original.apply(this, [fontFace]);
2337          };
2338      });
2339      handlers.push(() => {
2340          win.FontFace = originalFontFace;
2341      });
2342      handlers.push(restoreHandler);
2343      return callbackWrapper(() => {
2344          handlers.forEach((h) => h());
2345      });
2346  }
2347  function mergeHooks(o, hooks) {
2348      const { mutationCb, mousemoveCb, mouseInteractionCb, scrollCb, viewportResizeCb, inputCb, mediaInteractionCb, styleSheetRuleCb, styleDeclarationCb, canvasMutationCb, fontCb, } = o;
2349      o.mutationCb = (...p) => {
2350          if (hooks.mutation) {
2351              hooks.mutation(...p);
2352          }
2353          mutationCb(...p);
2354      };
2355      o.mousemoveCb = (...p) => {
2356          if (hooks.mousemove) {
2357              hooks.mousemove(...p);
2358          }
2359          mousemoveCb(...p);
2360      };
2361      o.mouseInteractionCb = (...p) => {
2362          if (hooks.mouseInteraction) {
2363              hooks.mouseInteraction(...p);
2364          }
2365          mouseInteractionCb(...p);
2366      };
2367      o.scrollCb = (...p) => {
2368          if (hooks.scroll) {
2369              hooks.scroll(...p);
2370          }
2371          scrollCb(...p);
2372      };
2373      o.viewportResizeCb = (...p) => {
2374          if (hooks.viewportResize) {
2375              hooks.viewportResize(...p);
2376          }
2377          viewportResizeCb(...p);
2378      };
2379      o.inputCb = (...p) => {
2380          if (hooks.input) {
2381              hooks.input(...p);
2382          }
2383          inputCb(...p);
2384      };
2385      o.mediaInteractionCb = (...p) => {
2386          if (hooks.mediaInteaction) {
2387              hooks.mediaInteaction(...p);
2388          }
2389          mediaInteractionCb(...p);
2390      };
2391      o.styleSheetRuleCb = (...p) => {
2392          if (hooks.styleSheetRule) {
2393              hooks.styleSheetRule(...p);
2394          }
2395          styleSheetRuleCb(...p);
2396      };
2397      o.styleDeclarationCb = (...p) => {
2398          if (hooks.styleDeclaration) {
2399              hooks.styleDeclaration(...p);
2400          }
2401          styleDeclarationCb(...p);
2402      };
2403      o.canvasMutationCb = (...p) => {
2404          if (hooks.canvasMutation) {
2405              hooks.canvasMutation(...p);
2406          }
2407          canvasMutationCb(...p);
2408      };
2409      o.fontCb = (...p) => {
2410          if (hooks.font) {
2411              hooks.font(...p);
2412          }
2413          fontCb(...p);
2414      };
2415  }
2416  function initObservers(o, hooks = {}) {
2417      const currentWindow = o.doc.defaultView;
2418      if (!currentWindow) {
2419          return () => { };
2420      }
2421      mergeHooks(o, hooks);
2422      const mutationObserver = initMutationObserver(o, o.doc);
2423      const mousemoveHandler = initMoveObserver(o);
2424      const mouseInteractionHandler = initMouseInteractionObserver(o);
2425      const scrollHandler = initScrollObserver(o);
2426      const viewportResizeHandler = initViewportResizeObserver(o);
2427      const inputHandler = initInputObserver(o);
2428      const mediaInteractionHandler = initMediaInteractionObserver(o);
2429      const styleSheetObserver = initStyleSheetObserver(o, { win: currentWindow });
2430      const styleDeclarationObserver = initStyleDeclarationObserver(o, {
2431          win: currentWindow,
2432      });
2433      const fontObserver = o.collectFonts ? initFontObserver(o) : () => { };
2434      const pluginHandlers = [];
2435      for (const plugin of o.plugins) {
2436          pluginHandlers.push(plugin.observer(plugin.callback, currentWindow, plugin.options));
2437      }
2438      return callbackWrapper(() => {
2439          mutationBuffers.forEach((b) => b.reset());
2440          mutationObserver.disconnect();
2441          mousemoveHandler();
2442          mouseInteractionHandler();
2443          scrollHandler();
2444          viewportResizeHandler();
2445          inputHandler();
2446          mediaInteractionHandler();
2447          try {
2448              styleSheetObserver();
2449              styleDeclarationObserver();
2450          }
2451          catch (e) {
2452          }
2453          fontObserver();
2454          pluginHandlers.forEach((h) => h());
2455      });
2456  }
2457  function hasNestedCSSRule(prop) {
2458      return typeof window[prop] !== 'undefined';
2459  }
2460  function canMonkeyPatchNestedCSSRule(prop) {
2461      return Boolean(typeof window[prop] !== 'undefined' &&
2462          window[prop].prototype &&
2463          'insertRule' in window[prop].prototype &&
2464          'deleteRule' in window[prop].prototype);
2465  }
2466  
2467  class IframeManager {
2468      constructor(options) {
2469          this.iframes = new WeakMap();
2470          this.mutationCb = options.mutationCb;
2471      }
2472      addIframe(iframeEl) {
2473          this.iframes.set(iframeEl, true);
2474      }
2475      addLoadListener(cb) {
2476          this.loadListener = cb;
2477      }
2478      attachIframe(iframeEl, childSn) {
2479          var _a;
2480          this.mutationCb({
2481              adds: [
2482                  {
2483                      parentId: iframeEl.__sn.id,
2484                      nextId: null,
2485                      node: childSn,
2486                  },
2487              ],
2488              removes: [],
2489              texts: [],
2490              attributes: [],
2491              isAttachIframe: true,
2492          });
2493          (_a = this.loadListener) === null || _a === void 0 ? void 0 : _a.call(this, iframeEl);
2494      }
2495  }
2496  
2497  class ShadowDomManager {
2498      constructor(options) {
2499          this.restorePatches = [];
2500          this.mutationCb = options.mutationCb;
2501          this.scrollCb = options.scrollCb;
2502          this.bypassOptions = options.bypassOptions;
2503          this.mirror = options.mirror;
2504          const manager = this;
2505          this.restorePatches.push(patch(HTMLElement.prototype, 'attachShadow', function (original) {
2506              return function () {
2507                  const shadowRoot = original.apply(this, arguments);
2508                  if (this.shadowRoot)
2509                      manager.addShadowRoot(this.shadowRoot, this.ownerDocument);
2510                  return shadowRoot;
2511              };
2512          }));
2513      }
2514      addShadowRoot(shadowRoot, doc) {
2515          initMutationObserver(Object.assign(Object.assign({}, this.bypassOptions), { doc, mutationCb: this.mutationCb, mirror: this.mirror, shadowDomManager: this }), shadowRoot);
2516          initScrollObserver(Object.assign(Object.assign({}, this.bypassOptions), { scrollCb: this.scrollCb, doc: shadowRoot, mirror: this.mirror }));
2517      }
2518      observeAttachShadow(iframeElement) {
2519          if (iframeElement.contentWindow) {
2520              const manager = this;
2521              this.restorePatches.push(patch(iframeElement.contentWindow.HTMLElement.prototype, 'attachShadow', function (original) {
2522                  return function () {
2523                      const shadowRoot = original.apply(this, arguments);
2524                      if (this.shadowRoot)
2525                          manager.addShadowRoot(this.shadowRoot, iframeElement.contentDocument);
2526                      return shadowRoot;
2527                  };
2528              }));
2529          }
2530      }
2531      reset() {
2532          this.restorePatches.forEach((restorePatch) => restorePatch());
2533      }
2534  }
2535  
2536  /******************************************************************************
2537  Copyright (c) Microsoft Corporation.
2538  
2539  Permission to use, copy, modify, and/or distribute this software for any
2540  purpose with or without fee is hereby granted.
2541  
2542  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
2543  REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
2544  AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
2545  INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
2546  LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
2547  OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
2548  PERFORMANCE OF THIS SOFTWARE.
2549  ***************************************************************************** */
2550  
2551  function __rest(s, e) {
2552      var t = {};
2553      for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
2554          t[p] = s[p];
2555      if (s != null && typeof Object.getOwnPropertySymbols === "function")
2556          for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
2557              if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
2558                  t[p[i]] = s[p[i]];
2559          }
2560      return t;
2561  }
2562  
2563  function initCanvas2DMutationObserver(cb, win, blockClass, unblockSelector, blockSelector, mirror) {
2564      const handlers = [];
2565      const props2D = Object.getOwnPropertyNames(win.CanvasRenderingContext2D.prototype);
2566      for (const prop of props2D) {
2567          try {
2568              if (typeof win.CanvasRenderingContext2D.prototype[prop] !== 'function') {
2569                  continue;
2570              }
2571              const restoreHandler = patch(win.CanvasRenderingContext2D.prototype, prop, function (original) {
2572                  return function (...args) {
2573                      if (!isBlocked(this.canvas, blockClass, blockSelector, unblockSelector)) {
2574                          setTimeout(() => {
2575                              const recordArgs = [...args];
2576                              if (prop === 'drawImage') {
2577                                  if (recordArgs[0] &&
2578                                      recordArgs[0] instanceof HTMLCanvasElement) {
2579                                      const canvas = recordArgs[0];
2580                                      const ctx = canvas.getContext('2d');
2581                                      let imgd = ctx === null || ctx === void 0 ? void 0 : ctx.getImageData(0, 0, canvas.width, canvas.height);
2582                                      let pix = imgd === null || imgd === void 0 ? void 0 : imgd.data;
2583                                      recordArgs[0] = JSON.stringify(pix);
2584                                  }
2585                              }
2586                              cb(this.canvas, {
2587                                  type: CanvasContext['2D'],
2588                                  property: prop,
2589                                  args: recordArgs,
2590                              });
2591                          }, 0);
2592                      }
2593                      return original.apply(this, args);
2594                  };
2595              });
2596              handlers.push(restoreHandler);
2597          }
2598          catch (_a) {
2599              const hookHandler = hookSetter(win.CanvasRenderingContext2D.prototype, prop, {
2600                  set(v) {
2601                      cb(this.canvas, {
2602                          type: CanvasContext['2D'],
2603                          property: prop,
2604                          args: [v],
2605                          setter: true,
2606                      });
2607                  },
2608              });
2609              handlers.push(hookHandler);
2610          }
2611      }
2612      return () => {
2613          handlers.forEach((h) => h());
2614      };
2615  }
2616  
2617  function initCanvasContextObserver(win, blockClass, blockSelector, unblockSelector) {
2618      const handlers = [];
2619      try {
2620          const restoreHandler = patch(win.HTMLCanvasElement.prototype, 'getContext', function (original) {
2621              return function (contextType, ...args) {
2622                  if (!isBlocked(this, blockClass, blockSelector, unblockSelector)) {
2623                      if (!('__context' in this))
2624                          this.__context = contextType;
2625                  }
2626                  return original.apply(this, [contextType, ...args]);
2627              };
2628          });
2629          handlers.push(restoreHandler);
2630      }
2631      catch (_a) {
2632          console.error('failed to patch HTMLCanvasElement.prototype.getContext');
2633      }
2634      return () => {
2635          handlers.forEach((h) => h());
2636      };
2637  }
2638  
2639  /*
2640   * base64-arraybuffer 1.0.2 <https://github.com/niklasvh/base64-arraybuffer>
2641   * Copyright (c) 2022 Niklas von Hertzen <https://hertzen.com>
2642   * Released under MIT License
2643   */
2644  var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
2645  // Use a lookup table to find the index.
2646  var lookup = typeof Uint8Array === 'undefined' ? [] : new Uint8Array(256);
2647  for (var i = 0; i < chars.length; i++) {
2648      lookup[chars.charCodeAt(i)] = i;
2649  }
2650  var encode = function (arraybuffer) {
2651      var bytes = new Uint8Array(arraybuffer), i, len = bytes.length, base64 = '';
2652      for (i = 0; i < len; i += 3) {
2653          base64 += chars[bytes[i] >> 2];
2654          base64 += chars[((bytes[i] & 3) << 4) | (bytes[i + 1] >> 4)];
2655          base64 += chars[((bytes[i + 1] & 15) << 2) | (bytes[i + 2] >> 6)];
2656          base64 += chars[bytes[i + 2] & 63];
2657      }
2658      if (len % 3 === 2) {
2659          base64 = base64.substring(0, base64.length - 1) + '=';
2660      }
2661      else if (len % 3 === 1) {
2662          base64 = base64.substring(0, base64.length - 2) + '==';
2663      }
2664      return base64;
2665  };
2666  
2667  const webGLVarMap = new Map();
2668  function variableListFor(ctx, ctor) {
2669      let contextMap = webGLVarMap.get(ctx);
2670      if (!contextMap) {
2671          contextMap = new Map();
2672          webGLVarMap.set(ctx, contextMap);
2673      }
2674      if (!contextMap.has(ctor)) {
2675          contextMap.set(ctor, []);
2676      }
2677      return contextMap.get(ctor);
2678  }
2679  const saveWebGLVar = (value, win, ctx) => {
2680      if (!value ||
2681          !(isInstanceOfWebGLObject(value, win) || typeof value === 'object'))
2682          return;
2683      const name = value.constructor.name;
2684      const list = variableListFor(ctx, name);
2685      let index = list.indexOf(value);
2686      if (index === -1) {
2687          index = list.length;
2688          list.push(value);
2689      }
2690      return index;
2691  };
2692  function serializeArg(value, win, ctx) {
2693      if (value instanceof Array) {
2694          return value.map((arg) => serializeArg(arg, win, ctx));
2695      }
2696      else if (value === null) {
2697          return value;
2698      }
2699      else if (value instanceof Float32Array ||
2700          value instanceof Float64Array ||
2701          value instanceof Int32Array ||
2702          value instanceof Uint32Array ||
2703          value instanceof Uint8Array ||
2704          value instanceof Uint16Array ||
2705          value instanceof Int16Array ||
2706          value instanceof Int8Array ||
2707          value instanceof Uint8ClampedArray) {
2708          const name = value.constructor.name;
2709          return {
2710              rr_type: name,
2711              args: [Object.values(value)],
2712          };
2713      }
2714      else if (value instanceof ArrayBuffer) {
2715          const name = value.constructor.name;
2716          const base64 = encode(value);
2717          return {
2718              rr_type: name,
2719              base64,
2720          };
2721      }
2722      else if (value instanceof DataView) {
2723          const name = value.constructor.name;
2724          return {
2725              rr_type: name,
2726              args: [
2727                  serializeArg(value.buffer, win, ctx),
2728                  value.byteOffset,
2729                  value.byteLength,
2730              ],
2731          };
2732      }
2733      else if (value instanceof HTMLImageElement) {
2734          const name = value.constructor.name;
2735          const { src } = value;
2736          return {
2737              rr_type: name,
2738              src,
2739          };
2740      }
2741      else if (value instanceof ImageData) {
2742          const name = value.constructor.name;
2743          return {
2744              rr_type: name,
2745              args: [serializeArg(value.data, win, ctx), value.width, value.height],
2746          };
2747      }
2748      else if (isInstanceOfWebGLObject(value, win) || typeof value === 'object') {
2749          const name = value.constructor.name;
2750          const index = saveWebGLVar(value, win, ctx);
2751          return {
2752              rr_type: name,
2753              index: index,
2754          };
2755      }
2756      return value;
2757  }
2758  const serializeArgs = (args, win, ctx) => {
2759      return [...args].map((arg) => serializeArg(arg, win, ctx));
2760  };
2761  const isInstanceOfWebGLObject = (value, win) => {
2762      const webGLConstructorNames = [
2763          'WebGLActiveInfo',
2764          'WebGLBuffer',
2765          'WebGLFramebuffer',
2766          'WebGLProgram',
2767          'WebGLRenderbuffer',
2768          'WebGLShader',
2769          'WebGLShaderPrecisionFormat',
2770          'WebGLTexture',
2771          'WebGLUniformLocation',
2772          'WebGLVertexArrayObject',
2773          'WebGLVertexArrayObjectOES',
2774      ];
2775      const supportedWebGLConstructorNames = webGLConstructorNames.filter((name) => typeof win[name] === 'function');
2776      return Boolean(supportedWebGLConstructorNames.find((name) => value instanceof win[name]));
2777  };
2778  
2779  function patchGLPrototype(prototype, type, cb, blockClass, unblockSelector, blockSelector, mirror, win) {
2780      const handlers = [];
2781      const props = Object.getOwnPropertyNames(prototype);
2782      for (const prop of props) {
2783          try {
2784              if (typeof prototype[prop] !== 'function') {
2785                  continue;
2786              }
2787              const restoreHandler = patch(prototype, prop, function (original) {
2788                  return function (...args) {
2789                      const result = original.apply(this, args);
2790                      saveWebGLVar(result, win, prototype);
2791                      if (!isBlocked(this.canvas, blockClass, blockSelector, unblockSelector)) {
2792                          const id = mirror.getId(this.canvas);
2793                          const recordArgs = serializeArgs([...args], win, prototype);
2794                          const mutation = {
2795                              type,
2796                              property: prop,
2797                              args: recordArgs,
2798                          };
2799                          cb(this.canvas, mutation);
2800                      }
2801                      return result;
2802                  };
2803              });
2804              handlers.push(restoreHandler);
2805          }
2806          catch (_a) {
2807              const hookHandler = hookSetter(prototype, prop, {
2808                  set(v) {
2809                      cb(this.canvas, {
2810                          type,
2811                          property: prop,
2812                          args: [v],
2813                          setter: true,
2814                      });
2815                  },
2816              });
2817              handlers.push(hookHandler);
2818          }
2819      }
2820      return handlers;
2821  }
2822  function initCanvasWebGLMutationObserver(cb, win, blockClass, blockSelector, unblockSelector, mirror) {
2823      const handlers = [];
2824      handlers.push(...patchGLPrototype(win.WebGLRenderingContext.prototype, CanvasContext.WebGL, cb, blockClass, blockSelector, unblockSelector, mirror, win));
2825      if (typeof win.WebGL2RenderingContext !== 'undefined') {
2826          handlers.push(...patchGLPrototype(win.WebGL2RenderingContext.prototype, CanvasContext.WebGL2, cb, blockClass, blockSelector, unblockSelector, mirror, win));
2827      }
2828      return () => {
2829          handlers.forEach((h) => h());
2830      };
2831  }
2832  
2833  class CanvasManager {
2834      reset() {
2835          this.pendingCanvasMutations.clear();
2836          this.resetObservers && this.resetObservers();
2837      }
2838      freeze() {
2839          this.frozen = true;
2840      }
2841      unfreeze() {
2842          this.frozen = false;
2843      }
2844      lock() {
2845          this.locked = true;
2846      }
2847      unlock() {
2848          this.locked = false;
2849      }
2850      constructor(options) {
2851          this.pendingCanvasMutations = new Map();
2852          this.rafStamps = { latestId: 0, invokeId: null };
2853          this.frozen = false;
2854          this.locked = false;
2855          this.processMutation = function (target, mutation) {
2856              const newFrame = this.rafStamps.invokeId &&
2857                  this.rafStamps.latestId !== this.rafStamps.invokeId;
2858              if (newFrame || !this.rafStamps.invokeId)
2859                  this.rafStamps.invokeId = this.rafStamps.latestId;
2860              if (!this.pendingCanvasMutations.has(target)) {
2861                  this.pendingCanvasMutations.set(target, []);
2862              }
2863              this.pendingCanvasMutations.get(target).push(mutation);
2864          };
2865          this.mutationCb = options.mutationCb;
2866          this.mirror = options.mirror;
2867          if (options.recordCanvas === true)
2868              this.initCanvasMutationObserver(options.win, options.blockClass, options.blockSelector, options.unblockSelector);
2869      }
2870      initCanvasMutationObserver(win, blockClass, unblockSelector, blockSelector) {
2871          this.startRAFTimestamping();
2872          this.startPendingCanvasMutationFlusher();
2873          const canvasContextReset = initCanvasContextObserver(win, blockClass, blockSelector, unblockSelector);
2874          const canvas2DReset = initCanvas2DMutationObserver(this.processMutation.bind(this), win, blockClass, blockSelector, unblockSelector, this.mirror);
2875          const canvasWebGL1and2Reset = initCanvasWebGLMutationObserver(this.processMutation.bind(this), win, blockClass, blockSelector, unblockSelector, this.mirror);
2876          this.resetObservers = () => {
2877              canvasContextReset();
2878              canvas2DReset();
2879              canvasWebGL1and2Reset();
2880          };
2881      }
2882      startPendingCanvasMutationFlusher() {
2883          requestAnimationFrame(() => this.flushPendingCanvasMutations());
2884      }
2885      startRAFTimestamping() {
2886          const setLatestRAFTimestamp = (timestamp) => {
2887              this.rafStamps.latestId = timestamp;
2888              requestAnimationFrame(setLatestRAFTimestamp);
2889          };
2890          requestAnimationFrame(setLatestRAFTimestamp);
2891      }
2892      flushPendingCanvasMutations() {
2893          this.pendingCanvasMutations.forEach((values, canvas) => {
2894              const id = this.mirror.getId(canvas);
2895              this.flushPendingCanvasMutationFor(canvas, id);
2896          });
2897          requestAnimationFrame(() => this.flushPendingCanvasMutations());
2898      }
2899      flushPendingCanvasMutationFor(canvas, id) {
2900          if (this.frozen || this.locked) {
2901              return;
2902          }
2903          const valuesWithType = this.pendingCanvasMutations.get(canvas);
2904          if (!valuesWithType || id === -1)
2905              return;
2906          const values = valuesWithType.map((value) => {
2907              const rest = __rest(value, ["type"]);
2908              return rest;
2909          });
2910          const { type } = valuesWithType[0];
2911          this.mutationCb({ id, type, commands: values });
2912          this.pendingCanvasMutations.delete(canvas);
2913      }
2914  }
2915  
2916  function wrapEvent(e) {
2917      return Object.assign(Object.assign({}, e), { timestamp: Date.now() });
2918  }
2919  let wrappedEmit;
2920  let takeFullSnapshot;
2921  const mirror = createMirror();
2922  function record(options = {}) {
2923      const { emit, checkoutEveryNms, checkoutEveryNth, blockClass = 'rr-block', blockSelector = null, unblockSelector = null, ignoreClass = 'rr-ignore', ignoreSelector = null, maskTextClass = 'rr-mask', maskTextSelector = null, maskInputSelector = null, unmaskTextSelector = null, unmaskInputSelector = null, inlineStylesheet = true, maskAllText = false, maskAllInputs, maskInputOptions: _maskInputOptions, slimDOMOptions: _slimDOMOptions, maskInputFn, maskTextFn, hooks, packFn, sampling = {}, mousemoveWait, recordCanvas = false, userTriggeredOnInput = false, collectFonts = false, inlineImages = false, plugins, keepIframeSrcFn = () => false, onMutation, } = options;
2924      if (!emit) {
2925          throw new Error('emit function is required');
2926      }
2927      if (mousemoveWait !== undefined && sampling.mousemove === undefined) {
2928          sampling.mousemove = mousemoveWait;
2929      }
2930      const maskInputOptions = maskAllInputs === true
2931          ? {
2932              color: true,
2933              date: true,
2934              'datetime-local': true,
2935              email: true,
2936              month: true,
2937              number: true,
2938              range: true,
2939              search: true,
2940              tel: true,
2941              text: true,
2942              time: true,
2943              url: true,
2944              week: true,
2945              textarea: true,
2946              select: true,
2947              radio: true,
2948              checkbox: true,
2949          }
2950          : _maskInputOptions !== undefined
2951              ? _maskInputOptions
2952              : {};
2953      const slimDOMOptions = _slimDOMOptions === true || _slimDOMOptions === 'all'
2954          ? {
2955              script: true,
2956              comment: true,
2957              headFavicon: true,
2958              headWhitespace: true,
2959              headMetaSocial: true,
2960              headMetaRobots: true,
2961              headMetaHttpEquiv: true,
2962              headMetaVerification: true,
2963              headMetaAuthorship: _slimDOMOptions === 'all',
2964              headMetaDescKeywords: _slimDOMOptions === 'all',
2965          }
2966          : _slimDOMOptions
2967              ? _slimDOMOptions
2968              : {};
2969      polyfill();
2970      let lastFullSnapshotEvent;
2971      let incrementalSnapshotCount = 0;
2972      const eventProcessor = (e) => {
2973          for (const plugin of plugins || []) {
2974              if (plugin.eventProcessor) {
2975                  e = plugin.eventProcessor(e);
2976              }
2977          }
2978          if (packFn) {
2979              e = packFn(e);
2980          }
2981          return e;
2982      };
2983      wrappedEmit = (e, isCheckout) => {
2984          var _a;
2985          if (((_a = mutationBuffers[0]) === null || _a === void 0 ? void 0 : _a.isFrozen()) &&
2986              e.type !== EventType.FullSnapshot &&
2987              !(e.type === EventType.IncrementalSnapshot &&
2988                  e.data.source === IncrementalSource.Mutation)) {
2989              mutationBuffers.forEach((buf) => buf.unfreeze());
2990          }
2991          emit(eventProcessor(e), isCheckout);
2992          if (e.type === EventType.FullSnapshot) {
2993              lastFullSnapshotEvent = e;
2994              incrementalSnapshotCount = 0;
2995          }
2996          else if (e.type === EventType.IncrementalSnapshot) {
2997              if (e.data.source === IncrementalSource.Mutation &&
2998                  e.data.isAttachIframe) {
2999                  return;
3000              }
3001              incrementalSnapshotCount++;
3002              const exceedCount = checkoutEveryNth && incrementalSnapshotCount >= checkoutEveryNth;
3003              const exceedTime = checkoutEveryNms &&
3004                  e.timestamp - lastFullSnapshotEvent.timestamp > checkoutEveryNms;
3005              if (exceedCount || exceedTime) {
3006                  takeFullSnapshot(true);
3007              }
3008          }
3009      };
3010      const wrappedMutationEmit = (m) => {
3011          wrappedEmit(wrapEvent({
3012              type: EventType.IncrementalSnapshot,
3013              data: Object.assign({ source: IncrementalSource.Mutation }, m),
3014          }));
3015      };
3016      const wrappedScrollEmit = (p) => wrappedEmit(wrapEvent({
3017          type: EventType.IncrementalSnapshot,
3018          data: Object.assign({ source: IncrementalSource.Scroll }, p),
3019      }));
3020      const wrappedCanvasMutationEmit = (p) => wrappedEmit(wrapEvent({
3021          type: EventType.IncrementalSnapshot,
3022          data: Object.assign({ source: IncrementalSource.CanvasMutation }, p),
3023      }));
3024      const iframeManager = new IframeManager({
3025          mutationCb: wrappedMutationEmit,
3026      });
3027      const canvasManager = new CanvasManager({
3028          recordCanvas,
3029          mutationCb: wrappedCanvasMutationEmit,
3030          win: window,
3031          blockClass,
3032          blockSelector,
3033          unblockSelector,
3034          mirror,
3035      });
3036      const shadowDomManager = new ShadowDomManager({
3037          mutationCb: wrappedMutationEmit,
3038          scrollCb: wrappedScrollEmit,
3039          bypassOptions: {
3040              onMutation,
3041              blockClass,
3042              blockSelector,
3043              unblockSelector,
3044              maskTextClass,
3045              maskTextSelector,
3046              unmaskTextSelector,
3047              maskInputSelector,
3048              unmaskInputSelector,
3049              inlineStylesheet,
3050              maskAllText,
3051              maskInputOptions,
3052              maskTextFn,
3053              maskInputFn,
3054              recordCanvas,
3055              inlineImages,
3056              sampling,
3057              slimDOMOptions,
3058              iframeManager,
3059              canvasManager,
3060          },
3061          mirror,
3062      });
3063      takeFullSnapshot = (isCheckout = false) => {
3064          var _a, _b, _c, _d;
3065          wrappedEmit(wrapEvent({
3066              type: EventType.Meta,
3067              data: {
3068                  href: window.location.href,
3069                  width: getWindowWidth(),
3070                  height: getWindowHeight(),
3071              },
3072          }), isCheckout);
3073          mutationBuffers.forEach((buf) => buf.lock());
3074          const [node, idNodeMap] = snapshot(document, {
3075              blockClass,
3076              blockSelector,
3077              unblockSelector,
3078              maskTextClass,
3079              maskTextSelector,
3080              unmaskTextSelector,
3081              maskInputSelector,
3082              unmaskInputSelector,
3083              inlineStylesheet,
3084              maskAllText,
3085              maskAllInputs: maskInputOptions,
3086              maskTextFn,
3087              slimDOM: slimDOMOptions,
3088              recordCanvas,
3089              inlineImages,
3090              onSerialize: (n) => {
3091                  if (isIframeINode(n)) {
3092                      iframeManager.addIframe(n);
3093                  }
3094                  if (hasShadowRoot(n)) {
3095                      shadowDomManager.addShadowRoot(n.shadowRoot, document);
3096                  }
3097              },
3098              onIframeLoad: (iframe, childSn) => {
3099                  iframeManager.attachIframe(iframe, childSn);
3100                  shadowDomManager.observeAttachShadow(iframe);
3101              },
3102              keepIframeSrcFn,
3103          });
3104          if (!node) {
3105              return console.warn('Failed to snapshot the document');
3106          }
3107          mirror.map = idNodeMap;
3108          wrappedEmit(wrapEvent({
3109              type: EventType.FullSnapshot,
3110              data: {
3111                  node,
3112                  initialOffset: {
3113                      left: window.pageXOffset !== undefined
3114                          ? window.pageXOffset
3115                          : (document === null || document === void 0 ? void 0 : document.documentElement.scrollLeft) ||
3116                              ((_b = (_a = document === null || document === void 0 ? void 0 : document.body) === null || _a === void 0 ? void 0 : _a.parentElement) === null || _b === void 0 ? void 0 : _b.scrollLeft) ||
3117                              (document === null || document === void 0 ? void 0 : document.body.scrollLeft) ||
3118                              0,
3119                      top: window.pageYOffset !== undefined
3120                          ? window.pageYOffset
3121                          : (document === null || document === void 0 ? void 0 : document.documentElement.scrollTop) ||
3122                              ((_d = (_c = document === null || document === void 0 ? void 0 : document.body) === null || _c === void 0 ? void 0 : _c.parentElement) === null || _d === void 0 ? void 0 : _d.scrollTop) ||
3123                              (document === null || document === void 0 ? void 0 : document.body.scrollTop) ||
3124                              0,
3125                  },
3126              },
3127          }));
3128          mutationBuffers.forEach((buf) => buf.unlock());
3129      };
3130      try {
3131          const handlers = [];
3132          handlers.push(on('DOMContentLoaded', () => {
3133              wrappedEmit(wrapEvent({
3134                  type: EventType.DomContentLoaded,
3135                  data: {},
3136              }));
3137          }));
3138          const observe = (doc) => {
3139              var _a;
3140              return callbackWrapper(initObservers)({
3141                  onMutation,
3142                  mutationCb: wrappedMutationEmit,
3143                  mousemoveCb: (positions, source) => wrappedEmit(wrapEvent({
3144                      type: EventType.IncrementalSnapshot,
3145                      data: {
3146                          source,
3147                          positions,
3148                      },
3149                  })),
3150                  mouseInteractionCb: (d) => wrappedEmit(wrapEvent({
3151                      type: EventType.IncrementalSnapshot,
3152                      data: Object.assign({ source: IncrementalSource.MouseInteraction }, d),
3153                  })),
3154                  scrollCb: wrappedScrollEmit,
3155                  viewportResizeCb: (d) => wrappedEmit(wrapEvent({
3156                      type: EventType.IncrementalSnapshot,
3157                      data: Object.assign({ source: IncrementalSource.ViewportResize }, d),
3158                  })),
3159                  inputCb: (v) => wrappedEmit(wrapEvent({
3160                      type: EventType.IncrementalSnapshot,
3161                      data: Object.assign({ source: IncrementalSource.Input }, v),
3162                  })),
3163                  mediaInteractionCb: (p) => wrappedEmit(wrapEvent({
3164                      type: EventType.IncrementalSnapshot,
3165                      data: Object.assign({ source: IncrementalSource.MediaInteraction }, p),
3166                  })),
3167                  styleSheetRuleCb: (r) => wrappedEmit(wrapEvent({
3168                      type: EventType.IncrementalSnapshot,
3169                      data: Object.assign({ source: IncrementalSource.StyleSheetRule }, r),
3170                  })),
3171                  styleDeclarationCb: (r) => wrappedEmit(wrapEvent({
3172                      type: EventType.IncrementalSnapshot,
3173                      data: Object.assign({ source: IncrementalSource.StyleDeclaration }, r),
3174                  })),
3175                  canvasMutationCb: wrappedCanvasMutationEmit,
3176                  fontCb: (p) => wrappedEmit(wrapEvent({
3177                      type: EventType.IncrementalSnapshot,
3178                      data: Object.assign({ source: IncrementalSource.Font }, p),
3179                  })),
3180                  blockClass,
3181                  ignoreClass,
3182                  ignoreSelector,
3183                  maskTextClass,
3184                  maskTextSelector,
3185                  unmaskTextSelector,
3186                  maskInputSelector,
3187                  unmaskInputSelector,
3188                  maskInputOptions,
3189                  inlineStylesheet,
3190                  sampling,
3191                  recordCanvas,
3192                  inlineImages,
3193                  userTriggeredOnInput,
3194                  collectFonts,
3195                  doc,
3196                  maskAllText,
3197                  maskInputFn,
3198                  maskTextFn,
3199                  blockSelector,
3200                  unblockSelector,
3201                  slimDOMOptions,
3202                  mirror,
3203                  iframeManager,
3204                  shadowDomManager,
3205                  canvasManager,
3206                  plugins: ((_a = plugins === null || plugins === void 0 ? void 0 : plugins.filter((p) => p.observer)) === null || _a === void 0 ? void 0 : _a.map((p) => ({
3207                      observer: p.observer,
3208                      options: p.options,
3209                      callback: (payload) => wrappedEmit(wrapEvent({
3210                          type: EventType.Plugin,
3211                          data: {
3212                              plugin: p.name,
3213                              payload,
3214                          },
3215                      })),
3216                  }))) || [],
3217              }, hooks);
3218          };
3219          iframeManager.addLoadListener((iframeEl) => {
3220              try {
3221                  handlers.push(observe(iframeEl.contentDocument));
3222              }
3223              catch (error) {
3224                  console.warn(error);
3225              }
3226          });
3227          const init = () => {
3228              takeFullSnapshot();
3229              handlers.push(observe(document));
3230          };
3231          if (document.readyState === 'interactive' ||
3232              document.readyState === 'complete') {
3233              init();
3234          }
3235          else {
3236              handlers.push(on('load', () => {
3237                  wrappedEmit(wrapEvent({
3238                      type: EventType.Load,
3239                      data: {},
3240                  }));
3241                  init();
3242              }, window));
3243          }
3244          return () => {
3245              handlers.forEach((h) => h());
3246          };
3247      }
3248      catch (error) {
3249          console.warn(error);
3250      }
3251  }
3252  record.addCustomEvent = (tag, payload) => {
3253      if (!wrappedEmit) {
3254          throw new Error('please add custom event after start recording');
3255      }
3256      wrappedEmit(wrapEvent({
3257          type: EventType.Custom,
3258          data: {
3259              tag,
3260              payload,
3261          },
3262      }));
3263  };
3264  record.freezePage = () => {
3265      mutationBuffers.forEach((buf) => buf.freeze());
3266  };
3267  record.takeFullSnapshot = (isCheckout) => {
3268      if (!takeFullSnapshot) {
3269          throw new Error('please take full snapshot after start recording');
3270      }
3271      takeFullSnapshot(isCheckout);
3272  };
3273  record.mirror = mirror;
3274  
3275  /**
3276   * Add a breadcrumb event to replay.
3277   */
3278  function addBreadcrumbEvent(replay, breadcrumb) {
3279    if (breadcrumb.category === 'sentry.transaction') {
3280      return;
3281    }
3282  
3283    if (['ui.click', 'ui.input'].includes(breadcrumb.category )) {
3284      replay.triggerUserActivity();
3285    } else {
3286      replay.checkAndHandleExpiredSession();
3287    }
3288  
3289    replay.addUpdate(() => {
3290      void replay.throttledAddEvent({
3291        type: EventType.Custom,
3292        // TODO: We were converting from ms to seconds for breadcrumbs, spans,
3293        // but maybe we should just keep them as milliseconds
3294        timestamp: (breadcrumb.timestamp || 0) * 1000,
3295        data: {
3296          tag: 'breadcrumb',
3297          // normalize to max. 10 depth and 1_000 properties per object
3298          payload: normalize(breadcrumb, 10, 1000),
3299        },
3300      });
3301  
3302      // Do not flush after console log messages
3303      return breadcrumb.category === 'console';
3304    });
3305  }
3306  
3307  const INTERACTIVE_SELECTOR = 'button,a';
3308  
3309  /**
3310   * For clicks, we check if the target is inside of a button or link
3311   * If so, we use this as the target instead
3312   * This is useful because if you click on the image in <button><img></button>,
3313   * The target will be the image, not the button, which we don't want here
3314   */
3315  function getClickTargetNode(event) {
3316    const target = getTargetNode(event);
3317  
3318    if (!target || !(target instanceof Element)) {
3319      return target;
3320    }
3321  
3322    const closestInteractive = target.closest(INTERACTIVE_SELECTOR);
3323    return closestInteractive || target;
3324  }
3325  
3326  /** Get the event target node. */
3327  function getTargetNode(event) {
3328    if (isEventWithTarget(event)) {
3329      return event.target ;
3330    }
3331  
3332    return event;
3333  }
3334  
3335  function isEventWithTarget(event) {
3336    return typeof event === 'object' && !!event && 'target' in event;
3337  }
3338  
3339  let handlers;
3340  
3341  /**
3342   * Register a handler to be called when `window.open()` is called.
3343   * Returns a cleanup function.
3344   */
3345  function onWindowOpen(cb) {
3346    // Ensure to only register this once
3347    if (!handlers) {
3348      handlers = [];
3349      monkeyPatchWindowOpen();
3350    }
3351  
3352    handlers.push(cb);
3353  
3354    return () => {
3355      const pos = handlers ? handlers.indexOf(cb) : -1;
3356      if (pos > -1) {
3357        (handlers ).splice(pos, 1);
3358      }
3359    };
3360  }
3361  
3362  function monkeyPatchWindowOpen() {
3363    fill(WINDOW, 'open', function (originalWindowOpen) {
3364      return function (...args) {
3365        if (handlers) {
3366          try {
3367            handlers.forEach(handler => handler());
3368          } catch (e) {
3369            // ignore errors in here
3370          }
3371        }
3372  
3373        return originalWindowOpen.apply(WINDOW, args);
3374      };
3375    });
3376  }
3377  
3378  /** Handle a click. */
3379  function handleClick(clickDetector, clickBreadcrumb, node) {
3380    clickDetector.handleClick(clickBreadcrumb, node);
3381  }
3382  
3383  /** A click detector class that can be used to detect slow or rage clicks on elements. */
3384  class ClickDetector  {
3385    // protected for testing
3386     __init() {this._lastMutation = 0;}
3387     __init2() {this._lastScroll = 0;}
3388  
3389     __init3() {this._clicks = [];}
3390  
3391     constructor(
3392      replay,
3393      slowClickConfig,
3394      // Just for easier testing
3395      _addBreadcrumbEvent = addBreadcrumbEvent,
3396    ) {ClickDetector.prototype.__init.call(this);ClickDetector.prototype.__init2.call(this);ClickDetector.prototype.__init3.call(this);
3397      // We want everything in s, but options are in ms
3398      this._timeout = slowClickConfig.timeout / 1000;
3399      this._multiClickTimeout = slowClickConfig.multiClickTimeout / 1000;
3400      this._threshold = slowClickConfig.threshold / 1000;
3401      this._scollTimeout = slowClickConfig.scrollTimeout / 1000;
3402      this._replay = replay;
3403      this._ignoreSelector = slowClickConfig.ignoreSelector;
3404      this._addBreadcrumbEvent = _addBreadcrumbEvent;
3405    }
3406  
3407    /** Register click detection handlers on mutation or scroll. */
3408     addListeners() {
3409      const mutationHandler = () => {
3410        this._lastMutation = nowInSeconds();
3411      };
3412  
3413      const scrollHandler = () => {
3414        this._lastScroll = nowInSeconds();
3415      };
3416  
3417      const cleanupWindowOpen = onWindowOpen(() => {
3418        // Treat window.open as mutation
3419        this._lastMutation = nowInSeconds();
3420      });
3421  
3422      const clickHandler = (event) => {
3423        if (!event.target) {
3424          return;
3425        }
3426  
3427        const node = getClickTargetNode(event);
3428        if (node) {
3429          this._handleMultiClick(node );
3430        }
3431      };
3432  
3433      const obs = new MutationObserver(mutationHandler);
3434  
3435      obs.observe(WINDOW.document.documentElement, {
3436        attributes: true,
3437        characterData: true,
3438        childList: true,
3439        subtree: true,
3440      });
3441  
3442      WINDOW.addEventListener('scroll', scrollHandler, { passive: true });
3443      WINDOW.addEventListener('click', clickHandler, { passive: true });
3444  
3445      this._teardown = () => {
3446        WINDOW.removeEventListener('scroll', scrollHandler);
3447        WINDOW.removeEventListener('click', clickHandler);
3448        cleanupWindowOpen();
3449  
3450        obs.disconnect();
3451        this._clicks = [];
3452        this._lastMutation = 0;
3453        this._lastScroll = 0;
3454      };
3455    }
3456  
3457    /** Clean up listeners. */
3458     removeListeners() {
3459      if (this._teardown) {
3460        this._teardown();
3461      }
3462  
3463      if (this._checkClickTimeout) {
3464        clearTimeout(this._checkClickTimeout);
3465      }
3466    }
3467  
3468    /** Handle a click */
3469     handleClick(breadcrumb, node) {
3470      if (ignoreElement(node, this._ignoreSelector) || !isClickBreadcrumb(breadcrumb)) {
3471        return;
3472      }
3473  
3474      const click = this._getClick(node);
3475  
3476      if (click) {
3477        // this means a click on the same element was captured in the last 1s, so we consider this a multi click
3478        return;
3479      }
3480  
3481      const newClick = {
3482        timestamp: breadcrumb.timestamp,
3483        clickBreadcrumb: breadcrumb,
3484        // Set this to 0 so we know it originates from the click breadcrumb
3485        clickCount: 0,
3486        node,
3487      };
3488      this._clicks.push(newClick);
3489  
3490      // If this is the first new click, set a timeout to check for multi clicks
3491      if (this._clicks.length === 1) {
3492        this._scheduleCheckClicks();
3493      }
3494    }
3495  
3496    /** Count multiple clicks on elements. */
3497     _handleMultiClick(node) {
3498      const click = this._getClick(node);
3499  
3500      if (!click) {
3501        return;
3502      }
3503  
3504      click.clickCount++;
3505    }
3506  
3507    /** Try to get an existing click on the given element. */
3508     _getClick(node) {
3509      const now = nowInSeconds();
3510  
3511      // Find any click on the same element in the last second
3512      // If one exists, we consider this click as a double/triple/etc click
3513      return this._clicks.find(click => click.node === node && now - click.timestamp < this._multiClickTimeout);
3514    }
3515  
3516    /** Check the clicks that happened. */
3517     _checkClicks() {
3518      const timedOutClicks = [];
3519  
3520      const now = nowInSeconds();
3521  
3522      this._clicks.forEach(click => {
3523        if (!click.mutationAfter && this._lastMutation) {
3524          click.mutationAfter = click.timestamp <= this._lastMutation ? this._lastMutation - click.timestamp : undefined;
3525        }
3526        if (!click.scrollAfter && this._lastScroll) {
3527          click.scrollAfter = click.timestamp <= this._lastScroll ? this._lastScroll - click.timestamp : undefined;
3528        }
3529  
3530        // If an action happens after the multi click threshold, we can skip waiting and handle the click right away
3531        const actionTime = click.scrollAfter || click.mutationAfter || 0;
3532        if (actionTime && actionTime >= this._multiClickTimeout) {
3533          timedOutClicks.push(click);
3534          return;
3535        }
3536  
3537        if (click.timestamp + this._timeout <= now) {
3538          timedOutClicks.push(click);
3539        }
3540      });
3541  
3542      // Remove "old" clicks
3543      for (const click of timedOutClicks) {
3544        this._generateBreadcrumbs(click);
3545  
3546        const pos = this._clicks.indexOf(click);
3547        if (pos !== -1) {
3548          this._clicks.splice(pos, 1);
3549        }
3550      }
3551  
3552      // Trigger new check, unless no clicks left
3553      if (this._clicks.length) {
3554        this._scheduleCheckClicks();
3555      }
3556    }
3557  
3558    /** Generate matching breadcrumb(s) for the click. */
3559     _generateBreadcrumbs(click) {
3560      const replay = this._replay;
3561      const hadScroll = click.scrollAfter && click.scrollAfter <= this._scollTimeout;
3562      const hadMutation = click.mutationAfter && click.mutationAfter <= this._threshold;
3563  
3564      const isSlowClick = !hadScroll && !hadMutation;
3565      const { clickCount, clickBreadcrumb } = click;
3566  
3567      // Slow click
3568      if (isSlowClick) {
3569        // If `mutationAfter` is set, it means a mutation happened after the threshold, but before the timeout
3570        // If not, it means we just timed out without scroll & mutation
3571        const timeAfterClickMs = Math.min(click.mutationAfter || this._timeout, this._timeout) * 1000;
3572        const endReason = timeAfterClickMs < this._timeout * 1000 ? 'mutation' : 'timeout';
3573  
3574        const breadcrumb = {
3575          type: 'default',
3576          message: clickBreadcrumb.message,
3577          timestamp: clickBreadcrumb.timestamp,
3578          category: 'ui.slowClickDetected',
3579          data: {
3580            ...clickBreadcrumb.data,
3581            url: WINDOW.location.href,
3582            route: replay.getCurrentRoute(),
3583            timeAfterClickMs,
3584            endReason,
3585            // If clickCount === 0, it means multiClick was not correctly captured here
3586            // - we still want to send 1 in this case
3587            clickCount: clickCount || 1,
3588          },
3589        };
3590  
3591        this._addBreadcrumbEvent(replay, breadcrumb);
3592        return;
3593      }
3594  
3595      // Multi click
3596      if (clickCount > 1) {
3597        const breadcrumb = {
3598          type: 'default',
3599          message: clickBreadcrumb.message,
3600          timestamp: clickBreadcrumb.timestamp,
3601          category: 'ui.multiClick',
3602          data: {
3603            ...clickBreadcrumb.data,
3604            url: WINDOW.location.href,
3605            route: replay.getCurrentRoute(),
3606            clickCount,
3607            metric: true,
3608          },
3609        };
3610  
3611        this._addBreadcrumbEvent(replay, breadcrumb);
3612      }
3613    }
3614  
3615    /** Schedule to check current clicks. */
3616     _scheduleCheckClicks() {
3617      this._checkClickTimeout = setTimeout(() => this._checkClicks(), 1000);
3618    }
3619  }
3620  
3621  const SLOW_CLICK_TAGS = ['A', 'BUTTON', 'INPUT'];
3622  
3623  /** exported for tests only */
3624  function ignoreElement(node, ignoreSelector) {
3625    if (!SLOW_CLICK_TAGS.includes(node.tagName)) {
3626      return true;
3627    }
3628  
3629    // If <input> tag, we only want to consider input[type='submit'] & input[type='button']
3630    if (node.tagName === 'INPUT' && !['submit', 'button'].includes(node.getAttribute('type') || '')) {
3631      return true;
3632    }
3633  
3634    // If <a> tag, detect special variants that may not lead to an action
3635    // If target !== _self, we may open the link somewhere else, which would lead to no action
3636    // Also, when downloading a file, we may not leave the page, but still not trigger an action
3637    if (
3638      node.tagName === 'A' &&
3639      (node.hasAttribute('download') || (node.hasAttribute('target') && node.getAttribute('target') !== '_self'))
3640    ) {
3641      return true;
3642    }
3643  
3644    if (ignoreSelector && node.matches(ignoreSelector)) {
3645      return true;
3646    }
3647  
3648    return false;
3649  }
3650  
3651  function isClickBreadcrumb(breadcrumb) {
3652    return !!(breadcrumb.data && typeof breadcrumb.data.nodeId === 'number' && breadcrumb.timestamp);
3653  }
3654  
3655  // This is good enough for us, and is easier to test/mock than `timestampInSeconds`
3656  function nowInSeconds() {
3657    return Date.now() / 1000;
3658  }
3659  
3660  /**
3661   * Create a breadcrumb for a replay.
3662   */
3663  function createBreadcrumb(
3664    breadcrumb,
3665  ) {
3666    return {
3667      timestamp: Date.now() / 1000,
3668      type: 'default',
3669      ...breadcrumb,
3670    };
3671  }
3672  
3673  var NodeType;
3674  (function (NodeType) {
3675      NodeType[NodeType["Document"] = 0] = "Document";
3676      NodeType[NodeType["DocumentType"] = 1] = "DocumentType";
3677      NodeType[NodeType["Element"] = 2] = "Element";
3678      NodeType[NodeType["Text"] = 3] = "Text";
3679      NodeType[NodeType["CDATA"] = 4] = "CDATA";
3680      NodeType[NodeType["Comment"] = 5] = "Comment";
3681  })(NodeType || (NodeType = {}));
3682  
3683  // Note that these are the serialized attributes and not attributes directly on
3684  // the DOM Node. Attributes we are interested in:
3685  const ATTRIBUTES_TO_RECORD = new Set([
3686    'id',
3687    'class',
3688    'aria-label',
3689    'role',
3690    'name',
3691    'alt',
3692    'title',
3693    'data-test-id',
3694    'data-testid',
3695    'disabled',
3696    'aria-disabled',
3697  ]);
3698  
3699  /**
3700   * Inclusion list of attributes that we want to record from the DOM element
3701   */
3702  function getAttributesToRecord(attributes) {
3703    const obj = {};
3704    for (const key in attributes) {
3705      if (ATTRIBUTES_TO_RECORD.has(key)) {
3706        let normalizedKey = key;
3707  
3708        if (key === 'data-testid' || key === 'data-test-id') {
3709          normalizedKey = 'testId';
3710        }
3711  
3712        obj[normalizedKey] = attributes[key];
3713      }
3714    }
3715  
3716    return obj;
3717  }
3718  
3719  const handleDomListener = (
3720    replay,
3721  ) => {
3722    return (handlerData) => {
3723      if (!replay.isEnabled()) {
3724        return;
3725      }
3726  
3727      const result = handleDom(handlerData);
3728  
3729      if (!result) {
3730        return;
3731      }
3732  
3733      const isClick = handlerData.name === 'click';
3734      const event = isClick && (handlerData.event );
3735      // Ignore clicks if ctrl/alt/meta keys are held down as they alter behavior of clicks (e.g. open in new tab)
3736      if (isClick && replay.clickDetector && event && !event.altKey && !event.metaKey && !event.ctrlKey) {
3737        handleClick(
3738          replay.clickDetector,
3739          result ,
3740          getClickTargetNode(handlerData.event) ,
3741        );
3742      }
3743  
3744      addBreadcrumbEvent(replay, result);
3745    };
3746  };
3747  
3748  /** Get the base DOM breadcrumb. */
3749  function getBaseDomBreadcrumb(target, message) {
3750    // `__sn` property is the serialized node created by rrweb
3751    const serializedNode = target && isRrwebNode(target) && target.__sn.type === NodeType.Element ? target.__sn : null;
3752  
3753    return {
3754      message,
3755      data: serializedNode
3756        ? {
3757            nodeId: serializedNode.id,
3758            node: {
3759              id: serializedNode.id,
3760              tagName: serializedNode.tagName,
3761              textContent: target
3762                ? Array.from(target.childNodes)
3763                    .map(
3764                      (node) => '__sn' in node && node.__sn.type === NodeType.Text && node.__sn.textContent,
3765                    )
3766                    .filter(Boolean) // filter out empty values
3767                    .map(text => (text ).trim())
3768                    .join('')
3769                : '',
3770              attributes: getAttributesToRecord(serializedNode.attributes),
3771            },
3772          }
3773        : {},
3774    };
3775  }
3776  
3777  /**
3778   * An event handler to react to DOM events.
3779   * Exported for tests.
3780   */
3781  function handleDom(handlerData) {
3782    const { target, message } = getDomTarget(handlerData);
3783  
3784    return createBreadcrumb({
3785      category: `ui.${handlerData.name}`,
3786      ...getBaseDomBreadcrumb(target, message),
3787    });
3788  }
3789  
3790  function getDomTarget(handlerData) {
3791    const isClick = handlerData.name === 'click';
3792  
3793    let message;
3794    let target = null;
3795  
3796    // Accessing event.target can throw (see getsentry/raven-js#838, #768)
3797    try {
3798      target = isClick ? getClickTargetNode(handlerData.event) : getTargetNode(handlerData.event);
3799      message = htmlTreeAsString(target, { maxStringLength: 200 }) || '<unknown>';
3800    } catch (e) {
3801      message = '<unknown>';
3802    }
3803  
3804    return { target, message };
3805  }
3806  
3807  function isRrwebNode(node) {
3808    return '__sn' in node;
3809  }
3810  
3811  /** Handle keyboard events & create breadcrumbs. */
3812  function handleKeyboardEvent(replay, event) {
3813    if (!replay.isEnabled()) {
3814      return;
3815    }
3816  
3817    // Update user activity, but do not restart recording as it can create
3818    // noisy/low-value replays (e.g. user comes back from idle, hits alt-tab, new
3819    // session with a single "keydown" breadcrumb is created)
3820    replay.updateUserActivity();
3821  
3822    const breadcrumb = getKeyboardBreadcrumb(event);
3823  
3824    if (!breadcrumb) {
3825      return;
3826    }
3827  
3828    addBreadcrumbEvent(replay, breadcrumb);
3829  }
3830  
3831  /** exported only for tests */
3832  function getKeyboardBreadcrumb(event) {
3833    const { metaKey, shiftKey, ctrlKey, altKey, key, target } = event;
3834  
3835    // never capture for input fields
3836    if (!target || isInputElement(target ) || !key) {
3837      return null;
3838    }
3839  
3840    // Note: We do not consider shift here, as that means "uppercase"
3841    const hasModifierKey = metaKey || ctrlKey || altKey;
3842    const isCharacterKey = key.length === 1; // other keys like Escape, Tab, etc have a longer length
3843  
3844    // Do not capture breadcrumb if only a word key is pressed
3845    // This could leak e.g. user input
3846    if (!hasModifierKey && isCharacterKey) {
3847      return null;
3848    }
3849  
3850    const message = htmlTreeAsString(target, { maxStringLength: 200 }) || '<unknown>';
3851    const baseBreadcrumb = getBaseDomBreadcrumb(target , message);
3852  
3853    return createBreadcrumb({
3854      category: 'ui.keyDown',
3855      message,
3856      data: {
3857        ...baseBreadcrumb.data,
3858        metaKey,
3859        shiftKey,
3860        ctrlKey,
3861        altKey,
3862        key,
3863      },
3864    });
3865  }
3866  
3867  function isInputElement(target) {
3868    return target.tagName === 'INPUT' || target.tagName === 'TEXTAREA' || target.isContentEditable;
3869  }
3870  
3871  const NAVIGATION_ENTRY_KEYS = [
3872    'name',
3873    'type',
3874    'startTime',
3875    'transferSize',
3876    'duration',
3877  ];
3878  
3879  function isNavigationEntryEqual(a) {
3880    return function (b) {
3881      return NAVIGATION_ENTRY_KEYS.every(key => a[key] === b[key]);
3882    };
3883  }
3884  
3885  /**
3886   * There are some difficulties diagnosing why there are duplicate navigation
3887   * entries. We've witnessed several intermittent results:
3888   * - duplicate entries have duration = 0
3889   * - duplicate entries are the same object reference
3890   * - none of the above
3891   *
3892   * Compare the values of several keys to determine if the entries are duplicates or not.
3893   */
3894  // TODO (high-prio): Figure out wth is returned here
3895  // eslint-disable-next-line @typescript-eslint/explicit-function-return-type
3896  function dedupePerformanceEntries(
3897    currentList,
3898    newList,
3899  ) {
3900    // Partition `currentList` into 3 different lists based on entryType
3901    const [existingNavigationEntries, existingLcpEntries, existingEntries] = currentList.reduce(
3902      (acc, entry) => {
3903        if (entry.entryType === 'navigation') {
3904          acc[0].push(entry );
3905        } else if (entry.entryType === 'largest-contentful-paint') {
3906          acc[1].push(entry );
3907        } else {
3908          acc[2].push(entry);
3909        }
3910        return acc;
3911      },
3912      [[], [], []],
3913    );
3914  
3915    const newEntries = [];
3916    const newNavigationEntries = [];
3917    let newLcpEntry = existingLcpEntries.length
3918      ? existingLcpEntries[existingLcpEntries.length - 1] // Take the last element as list is sorted
3919      : undefined;
3920  
3921    newList.forEach(entry => {
3922      if (entry.entryType === 'largest-contentful-paint') {
3923        // We want the latest LCP event only
3924        if (!newLcpEntry || newLcpEntry.startTime < entry.startTime) {
3925          newLcpEntry = entry;
3926        }
3927        return;
3928      }
3929  
3930      if (entry.entryType === 'navigation') {
3931        const navigationEntry = entry ;
3932  
3933        // Check if the navigation entry is contained in currentList or newList
3934        if (
3935          // Ignore any navigation entries with duration 0, as they are likely duplicates
3936          entry.duration > 0 &&
3937          // Ensure new entry does not already exist in existing entries
3938          !existingNavigationEntries.find(isNavigationEntryEqual(navigationEntry)) &&
3939          // Ensure new entry does not already exist in new list of navigation entries
3940          !newNavigationEntries.find(isNavigationEntryEqual(navigationEntry))
3941        ) {
3942          newNavigationEntries.push(navigationEntry);
3943        }
3944  
3945        // Otherwise this navigation entry is considered a duplicate and is thrown away
3946        return;
3947      }
3948  
3949      newEntries.push(entry);
3950    });
3951  
3952    // Re-combine and sort by startTime
3953    return [
3954      ...(newLcpEntry ? [newLcpEntry] : []),
3955      ...existingNavigationEntries,
3956      ...existingEntries,
3957      ...newEntries,
3958      ...newNavigationEntries,
3959    ].sort((a, b) => a.startTime - b.startTime);
3960  }
3961  
3962  /**
3963   * Sets up a PerformanceObserver to listen to all performance entry types.
3964   */
3965  function setupPerformanceObserver(replay) {
3966    const performanceObserverHandler = (list) => {
3967      // For whatever reason the observer was returning duplicate navigation
3968      // entries (the other entry types were not duplicated).
3969      const newPerformanceEntries = dedupePerformanceEntries(
3970        replay.performanceEvents,
3971        list.getEntries() ,
3972      );
3973      replay.performanceEvents = newPerformanceEntries;
3974    };
3975  
3976    const performanceObserver = new PerformanceObserver(performanceObserverHandler);
3977  
3978    [
3979      'element',
3980      'event',
3981      'first-input',
3982      'largest-contentful-paint',
3983      'layout-shift',
3984      'longtask',
3985      'navigation',
3986      'paint',
3987      'resource',
3988    ].forEach(type => {
3989      try {
3990        performanceObserver.observe({
3991          type,
3992          buffered: true,
3993        });
3994      } catch (e) {
3995        // This can throw if an entry type is not supported in the browser.
3996        // Ignore these errors.
3997      }
3998    });
3999  
4000    return performanceObserver;
4001  }
4002  
4003  const r = `/*! pako 2.1.0 https://github.com/nodeca/pako @license (MIT AND Zlib) */
4004  function t(t){let e=t.length;for(;--e>=0;)t[e]=0}const e=new Uint8Array([0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0]),a=new Uint8Array([0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13]),i=new Uint8Array([0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7]),n=new Uint8Array([16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15]),s=new Array(576);t(s);const r=new Array(60);t(r);const o=new Array(512);t(o);const l=new Array(256);t(l);const h=new Array(29);t(h);const d=new Array(30);function _(t,e,a,i,n){this.static_tree=t,this.extra_bits=e,this.extra_base=a,this.elems=i,this.max_length=n,this.has_stree=t&&t.length}let f,c,u;function w(t,e){this.dyn_tree=t,this.max_code=0,this.stat_desc=e}t(d);const m=t=>t<256?o[t]:o[256+(t>>>7)],b=(t,e)=>{t.pending_buf[t.pending++]=255&e,t.pending_buf[t.pending++]=e>>>8&255},g=(t,e,a)=>{t.bi_valid>16-a?(t.bi_buf|=e<<t.bi_valid&65535,b(t,t.bi_buf),t.bi_buf=e>>16-t.bi_valid,t.bi_valid+=a-16):(t.bi_buf|=e<<t.bi_valid&65535,t.bi_valid+=a)},p=(t,e,a)=>{g(t,a[2*e],a[2*e+1])},k=(t,e)=>{let a=0;do{a|=1&t,t>>>=1,a<<=1}while(--e>0);return a>>>1},v=(t,e,a)=>{const i=new Array(16);let n,s,r=0;for(n=1;n<=15;n++)r=r+a[n-1]<<1,i[n]=r;for(s=0;s<=e;s++){let e=t[2*s+1];0!==e&&(t[2*s]=k(i[e]++,e))}},y=t=>{let e;for(e=0;e<286;e++)t.dyn_ltree[2*e]=0;for(e=0;e<30;e++)t.dyn_dtree[2*e]=0;for(e=0;e<19;e++)t.bl_tree[2*e]=0;t.dyn_ltree[512]=1,t.opt_len=t.static_len=0,t.sym_next=t.matches=0},x=t=>{t.bi_valid>8?b(t,t.bi_buf):t.bi_valid>0&&(t.pending_buf[t.pending++]=t.bi_buf),t.bi_buf=0,t.bi_valid=0},z=(t,e,a,i)=>{const n=2*e,s=2*a;return t[n]<t[s]||t[n]===t[s]&&i[e]<=i[a]},A=(t,e,a)=>{const i=t.heap[a];let n=a<<1;for(;n<=t.heap_len&&(n<t.heap_len&&z(e,t.heap[n+1],t.heap[n],t.depth)&&n++,!z(e,i,t.heap[n],t.depth));)t.heap[a]=t.heap[n],a=n,n<<=1;t.heap[a]=i},E=(t,i,n)=>{let s,r,o,_,f=0;if(0!==t.sym_next)do{s=255&t.pending_buf[t.sym_buf+f++],s+=(255&t.pending_buf[t.sym_buf+f++])<<8,r=t.pending_buf[t.sym_buf+f++],0===s?p(t,r,i):(o=l[r],p(t,o+256+1,i),_=e[o],0!==_&&(r-=h[o],g(t,r,_)),s--,o=m(s),p(t,o,n),_=a[o],0!==_&&(s-=d[o],g(t,s,_)))}while(f<t.sym_next);p(t,256,i)},R=(t,e)=>{const a=e.dyn_tree,i=e.stat_desc.static_tree,n=e.stat_desc.has_stree,s=e.stat_desc.elems;let r,o,l,h=-1;for(t.heap_len=0,t.heap_max=573,r=0;r<s;r++)0!==a[2*r]?(t.heap[++t.heap_len]=h=r,t.depth[r]=0):a[2*r+1]=0;for(;t.heap_len<2;)l=t.heap[++t.heap_len]=h<2?++h:0,a[2*l]=1,t.depth[l]=0,t.opt_len--,n&&(t.static_len-=i[2*l+1]);for(e.max_code=h,r=t.heap_len>>1;r>=1;r--)A(t,a,r);l=s;do{r=t.heap[1],t.heap[1]=t.heap[t.heap_len--],A(t,a,1),o=t.heap[1],t.heap[--t.heap_max]=r,t.heap[--t.heap_max]=o,a[2*l]=a[2*r]+a[2*o],t.depth[l]=(t.depth[r]>=t.depth[o]?t.depth[r]:t.depth[o])+1,a[2*r+1]=a[2*o+1]=l,t.heap[1]=l++,A(t,a,1)}while(t.heap_len>=2);t.heap[--t.heap_max]=t.heap[1],((t,e)=>{const a=e.dyn_tree,i=e.max_code,n=e.stat_desc.static_tree,s=e.stat_desc.has_stree,r=e.stat_desc.extra_bits,o=e.stat_desc.extra_base,l=e.stat_desc.max_length;let h,d,_,f,c,u,w=0;for(f=0;f<=15;f++)t.bl_count[f]=0;for(a[2*t.heap[t.heap_max]+1]=0,h=t.heap_max+1;h<573;h++)d=t.heap[h],f=a[2*a[2*d+1]+1]+1,f>l&&(f=l,w++),a[2*d+1]=f,d>i||(t.bl_count[f]++,c=0,d>=o&&(c=r[d-o]),u=a[2*d],t.opt_len+=u*(f+c),s&&(t.static_len+=u*(n[2*d+1]+c)));if(0!==w){do{for(f=l-1;0===t.bl_count[f];)f--;t.bl_count[f]--,t.bl_count[f+1]+=2,t.bl_count[l]--,w-=2}while(w>0);for(f=l;0!==f;f--)for(d=t.bl_count[f];0!==d;)_=t.heap[--h],_>i||(a[2*_+1]!==f&&(t.opt_len+=(f-a[2*_+1])*a[2*_],a[2*_+1]=f),d--)}})(t,e),v(a,h,t.bl_count)},Z=(t,e,a)=>{let i,n,s=-1,r=e[1],o=0,l=7,h=4;for(0===r&&(l=138,h=3),e[2*(a+1)+1]=65535,i=0;i<=a;i++)n=r,r=e[2*(i+1)+1],++o<l&&n===r||(o<h?t.bl_tree[2*n]+=o:0!==n?(n!==s&&t.bl_tree[2*n]++,t.bl_tree[32]++):o<=10?t.bl_tree[34]++:t.bl_tree[36]++,o=0,s=n,0===r?(l=138,h=3):n===r?(l=6,h=3):(l=7,h=4))},U=(t,e,a)=>{let i,n,s=-1,r=e[1],o=0,l=7,h=4;for(0===r&&(l=138,h=3),i=0;i<=a;i++)if(n=r,r=e[2*(i+1)+1],!(++o<l&&n===r)){if(o<h)do{p(t,n,t.bl_tree)}while(0!=--o);else 0!==n?(n!==s&&(p(t,n,t.bl_tree),o--),p(t,16,t.bl_tree),g(t,o-3,2)):o<=10?(p(t,17,t.bl_tree),g(t,o-3,3)):(p(t,18,t.bl_tree),g(t,o-11,7));o=0,s=n,0===r?(l=138,h=3):n===r?(l=6,h=3):(l=7,h=4)}};let S=!1;const D=(t,e,a,i)=>{g(t,0+(i?1:0),3),x(t),b(t,a),b(t,~a),a&&t.pending_buf.set(t.window.subarray(e,e+a),t.pending),t.pending+=a};var T=(t,e,a,i)=>{let o,l,h=0;t.level>0?(2===t.strm.data_type&&(t.strm.data_type=(t=>{let e,a=4093624447;for(e=0;e<=31;e++,a>>>=1)if(1&a&&0!==t.dyn_ltree[2*e])return 0;if(0!==t.dyn_ltree[18]||0!==t.dyn_ltree[20]||0!==t.dyn_ltree[26])return 1;for(e=32;e<256;e++)if(0!==t.dyn_ltree[2*e])return 1;return 0})(t)),R(t,t.l_desc),R(t,t.d_desc),h=(t=>{let e;for(Z(t,t.dyn_ltree,t.l_desc.max_code),Z(t,t.dyn_dtree,t.d_desc.max_code),R(t,t.bl_desc),e=18;e>=3&&0===t.bl_tree[2*n[e]+1];e--);return t.opt_len+=3*(e+1)+5+5+4,e})(t),o=t.opt_len+3+7>>>3,l=t.static_len+3+7>>>3,l<=o&&(o=l)):o=l=a+5,a+4<=o&&-1!==e?D(t,e,a,i):4===t.strategy||l===o?(g(t,2+(i?1:0),3),E(t,s,r)):(g(t,4+(i?1:0),3),((t,e,a,i)=>{let s;for(g(t,e-257,5),g(t,a-1,5),g(t,i-4,4),s=0;s<i;s++)g(t,t.bl_tree[2*n[s]+1],3);U(t,t.dyn_ltree,e-1),U(t,t.dyn_dtree,a-1)})(t,t.l_desc.max_code+1,t.d_desc.max_code+1,h+1),E(t,t.dyn_ltree,t.dyn_dtree)),y(t),i&&x(t)},O={_tr_init:t=>{S||((()=>{let t,n,w,m,b;const g=new Array(16);for(w=0,m=0;m<28;m++)for(h[m]=w,t=0;t<1<<e[m];t++)l[w++]=m;for(l[w-1]=m,b=0,m=0;m<16;m++)for(d[m]=b,t=0;t<1<<a[m];t++)o[b++]=m;for(b>>=7;m<30;m++)for(d[m]=b<<7,t=0;t<1<<a[m]-7;t++)o[256+b++]=m;for(n=0;n<=15;n++)g[n]=0;for(t=0;t<=143;)s[2*t+1]=8,t++,g[8]++;for(;t<=255;)s[2*t+1]=9,t++,g[9]++;for(;t<=279;)s[2*t+1]=7,t++,g[7]++;for(;t<=287;)s[2*t+1]=8,t++,g[8]++;for(v(s,287,g),t=0;t<30;t++)r[2*t+1]=5,r[2*t]=k(t,5);f=new _(s,e,257,286,15),c=new _(r,a,0,30,15),u=new _(new Array(0),i,0,19,7)})(),S=!0),t.l_desc=new w(t.dyn_ltree,f),t.d_desc=new w(t.dyn_dtree,c),t.bl_desc=new w(t.bl_tree,u),t.bi_buf=0,t.bi_valid=0,y(t)},_tr_stored_block:D,_tr_flush_block:T,_tr_tally:(t,e,a)=>(t.pending_buf[t.sym_buf+t.sym_next++]=e,t.pending_buf[t.sym_buf+t.sym_next++]=e>>8,t.pending_buf[t.sym_buf+t.sym_next++]=a,0===e?t.dyn_ltree[2*a]++:(t.matches++,e--,t.dyn_ltree[2*(l[a]+256+1)]++,t.dyn_dtree[2*m(e)]++),t.sym_next===t.sym_end),_tr_align:t=>{g(t,2,3),p(t,256,s),(t=>{16===t.bi_valid?(b(t,t.bi_buf),t.bi_buf=0,t.bi_valid=0):t.bi_valid>=8&&(t.pending_buf[t.pending++]=255&t.bi_buf,t.bi_buf>>=8,t.bi_valid-=8)})(t)}};var F=(t,e,a,i)=>{let n=65535&t|0,s=t>>>16&65535|0,r=0;for(;0!==a;){r=a>2e3?2e3:a,a-=r;do{n=n+e[i++]|0,s=s+n|0}while(--r);n%=65521,s%=65521}return n|s<<16|0};const L=new Uint32Array((()=>{let t,e=[];for(var a=0;a<256;a++){t=a;for(var i=0;i<8;i++)t=1&t?3988292384^t>>>1:t>>>1;e[a]=t}return e})());var N=(t,e,a,i)=>{const n=L,s=i+a;t^=-1;for(let a=i;a<s;a++)t=t>>>8^n[255&(t^e[a])];return-1^t},I={2:"need dictionary",1:"stream end",0:"","-1":"file error","-2":"stream error","-3":"data error","-4":"insufficient memory","-5":"buffer error","-6":"incompatible version"},B={Z_NO_FLUSH:0,Z_PARTIAL_FLUSH:1,Z_SYNC_FLUSH:2,Z_FULL_FLUSH:3,Z_FINISH:4,Z_BLOCK:5,Z_TREES:6,Z_OK:0,Z_STREAM_END:1,Z_NEED_DICT:2,Z_ERRNO:-1,Z_STREAM_ERROR:-2,Z_DATA_ERROR:-3,Z_MEM_ERROR:-4,Z_BUF_ERROR:-5,Z_NO_COMPRESSION:0,Z_BEST_SPEED:1,Z_BEST_COMPRESSION:9,Z_DEFAULT_COMPRESSION:-1,Z_FILTERED:1,Z_HUFFMAN_ONLY:2,Z_RLE:3,Z_FIXED:4,Z_DEFAULT_STRATEGY:0,Z_BINARY:0,Z_TEXT:1,Z_UNKNOWN:2,Z_DEFLATED:8};const{_tr_init:C,_tr_stored_block:H,_tr_flush_block:M,_tr_tally:j,_tr_align:K}=O,{Z_NO_FLUSH:P,Z_PARTIAL_FLUSH:Y,Z_FULL_FLUSH:G,Z_FINISH:X,Z_BLOCK:W,Z_OK:q,Z_STREAM_END:J,Z_STREAM_ERROR:Q,Z_DATA_ERROR:V,Z_BUF_ERROR:$,Z_DEFAULT_COMPRESSION:tt,Z_FILTERED:et,Z_HUFFMAN_ONLY:at,Z_RLE:it,Z_FIXED:nt,Z_DEFAULT_STRATEGY:st,Z_UNKNOWN:rt,Z_DEFLATED:ot}=B,lt=(t,e)=>(t.msg=I[e],e),ht=t=>2*t-(t>4?9:0),dt=t=>{let e=t.length;for(;--e>=0;)t[e]=0},_t=t=>{let e,a,i,n=t.w_size;e=t.hash_size,i=e;do{a=t.head[--i],t.head[i]=a>=n?a-n:0}while(--e);e=n,i=e;do{a=t.prev[--i],t.prev[i]=a>=n?a-n:0}while(--e)};let ft=(t,e,a)=>(e<<t.hash_shift^a)&t.hash_mask;const ct=t=>{const e=t.state;let a=e.pending;a>t.avail_out&&(a=t.avail_out),0!==a&&(t.output.set(e.pending_buf.subarray(e.pending_out,e.pending_out+a),t.next_out),t.next_out+=a,e.pending_out+=a,t.total_out+=a,t.avail_out-=a,e.pending-=a,0===e.pending&&(e.pending_out=0))},ut=(t,e)=>{M(t,t.block_start>=0?t.block_start:-1,t.strstart-t.block_start,e),t.block_start=t.strstart,ct(t.strm)},wt=(t,e)=>{t.pending_buf[t.pending++]=e},mt=(t,e)=>{t.pending_buf[t.pending++]=e>>>8&255,t.pending_buf[t.pending++]=255&e},bt=(t,e,a,i)=>{let n=t.avail_in;return n>i&&(n=i),0===n?0:(t.avail_in-=n,e.set(t.input.subarray(t.next_in,t.next_in+n),a),1===t.state.wrap?t.adler=F(t.adler,e,n,a):2===t.state.wrap&&(t.adler=N(t.adler,e,n,a)),t.next_in+=n,t.total_in+=n,n)},gt=(t,e)=>{let a,i,n=t.max_chain_length,s=t.strstart,r=t.prev_length,o=t.nice_match;const l=t.strstart>t.w_size-262?t.strstart-(t.w_size-262):0,h=t.window,d=t.w_mask,_=t.prev,f=t.strstart+258;let c=h[s+r-1],u=h[s+r];t.prev_length>=t.good_match&&(n>>=2),o>t.lookahead&&(o=t.lookahead);do{if(a=e,h[a+r]===u&&h[a+r-1]===c&&h[a]===h[s]&&h[++a]===h[s+1]){s+=2,a++;do{}while(h[++s]===h[++a]&&h[++s]===h[++a]&&h[++s]===h[++a]&&h[++s]===h[++a]&&h[++s]===h[++a]&&h[++s]===h[++a]&&h[++s]===h[++a]&&h[++s]===h[++a]&&s<f);if(i=258-(f-s),s=f-258,i>r){if(t.match_start=e,r=i,i>=o)break;c=h[s+r-1],u=h[s+r]}}}while((e=_[e&d])>l&&0!=--n);return r<=t.lookahead?r:t.lookahead},pt=t=>{const e=t.w_size;let a,i,n;do{if(i=t.window_size-t.lookahead-t.strstart,t.strstart>=e+(e-262)&&(t.window.set(t.window.subarray(e,e+e-i),0),t.match_start-=e,t.strstart-=e,t.block_start-=e,t.insert>t.strstart&&(t.insert=t.strstart),_t(t),i+=e),0===t.strm.avail_in)break;if(a=bt(t.strm,t.window,t.strstart+t.lookahead,i),t.lookahead+=a,t.lookahead+t.insert>=3)for(n=t.strstart-t.insert,t.ins_h=t.window[n],t.ins_h=ft(t,t.ins_h,t.window[n+1]);t.insert&&(t.ins_h=ft(t,t.ins_h,t.window[n+3-1]),t.prev[n&t.w_mask]=t.head[t.ins_h],t.head[t.ins_h]=n,n++,t.insert--,!(t.lookahead+t.insert<3)););}while(t.lookahead<262&&0!==t.strm.avail_in)},kt=(t,e)=>{let a,i,n,s=t.pending_buf_size-5>t.w_size?t.w_size:t.pending_buf_size-5,r=0,o=t.strm.avail_in;do{if(a=65535,n=t.bi_valid+42>>3,t.strm.avail_out<n)break;if(n=t.strm.avail_out-n,i=t.strstart-t.block_start,a>i+t.strm.avail_in&&(a=i+t.strm.avail_in),a>n&&(a=n),a<s&&(0===a&&e!==X||e===P||a!==i+t.strm.avail_in))break;r=e===X&&a===i+t.strm.avail_in?1:0,H(t,0,0,r),t.pending_buf[t.pending-4]=a,t.pending_buf[t.pending-3]=a>>8,t.pending_buf[t.pending-2]=~a,t.pending_buf[t.pending-1]=~a>>8,ct(t.strm),i&&(i>a&&(i=a),t.strm.output.set(t.window.subarray(t.block_start,t.block_start+i),t.strm.next_out),t.strm.next_out+=i,t.strm.avail_out-=i,t.strm.total_out+=i,t.block_start+=i,a-=i),a&&(bt(t.strm,t.strm.output,t.strm.next_out,a),t.strm.next_out+=a,t.strm.avail_out-=a,t.strm.total_out+=a)}while(0===r);return o-=t.strm.avail_in,o&&(o>=t.w_size?(t.matches=2,t.window.set(t.strm.input.subarray(t.strm.next_in-t.w_size,t.strm.next_in),0),t.strstart=t.w_size,t.insert=t.strstart):(t.window_size-t.strstart<=o&&(t.strstart-=t.w_size,t.window.set(t.window.subarray(t.w_size,t.w_size+t.strstart),0),t.matches<2&&t.matches++,t.insert>t.strstart&&(t.insert=t.strstart)),t.window.set(t.strm.input.subarray(t.strm.next_in-o,t.strm.next_in),t.strstart),t.strstart+=o,t.insert+=o>t.w_size-t.insert?t.w_size-t.insert:o),t.block_start=t.strstart),t.high_water<t.strstart&&(t.high_water=t.strstart),r?4:e!==P&&e!==X&&0===t.strm.avail_in&&t.strstart===t.block_start?2:(n=t.window_size-t.strstart,t.strm.avail_in>n&&t.block_start>=t.w_size&&(t.block_start-=t.w_size,t.strstart-=t.w_size,t.window.set(t.window.subarray(t.w_size,t.w_size+t.strstart),0),t.matches<2&&t.matches++,n+=t.w_size,t.insert>t.strstart&&(t.insert=t.strstart)),n>t.strm.avail_in&&(n=t.strm.avail_in),n&&(bt(t.strm,t.window,t.strstart,n),t.strstart+=n,t.insert+=n>t.w_size-t.insert?t.w_size-t.insert:n),t.high_water<t.strstart&&(t.high_water=t.strstart),n=t.bi_valid+42>>3,n=t.pending_buf_size-n>65535?65535:t.pending_buf_size-n,s=n>t.w_size?t.w_size:n,i=t.strstart-t.block_start,(i>=s||(i||e===X)&&e!==P&&0===t.strm.avail_in&&i<=n)&&(a=i>n?n:i,r=e===X&&0===t.strm.avail_in&&a===i?1:0,H(t,t.block_start,a,r),t.block_start+=a,ct(t.strm)),r?3:1)},vt=(t,e)=>{let a,i;for(;;){if(t.lookahead<262){if(pt(t),t.lookahead<262&&e===P)return 1;if(0===t.lookahead)break}if(a=0,t.lookahead>=3&&(t.ins_h=ft(t,t.ins_h,t.window[t.strstart+3-1]),a=t.prev[t.strstart&t.w_mask]=t.head[t.ins_h],t.head[t.ins_h]=t.strstart),0!==a&&t.strstart-a<=t.w_size-262&&(t.match_length=gt(t,a)),t.match_length>=3)if(i=j(t,t.strstart-t.match_start,t.match_length-3),t.lookahead-=t.match_length,t.match_length<=t.max_lazy_match&&t.lookahead>=3){t.match_length--;do{t.strstart++,t.ins_h=ft(t,t.ins_h,t.window[t.strstart+3-1]),a=t.prev[t.strstart&t.w_mask]=t.head[t.ins_h],t.head[t.ins_h]=t.strstart}while(0!=--t.match_length);t.strstart++}else t.strstart+=t.match_length,t.match_length=0,t.ins_h=t.window[t.strstart],t.ins_h=ft(t,t.ins_h,t.window[t.strstart+1]);else i=j(t,0,t.window[t.strstart]),t.lookahead--,t.strstart++;if(i&&(ut(t,!1),0===t.strm.avail_out))return 1}return t.insert=t.strstart<2?t.strstart:2,e===X?(ut(t,!0),0===t.strm.avail_out?3:4):t.sym_next&&(ut(t,!1),0===t.strm.avail_out)?1:2},yt=(t,e)=>{let a,i,n;for(;;){if(t.lookahead<262){if(pt(t),t.lookahead<262&&e===P)return 1;if(0===t.lookahead)break}if(a=0,t.lookahead>=3&&(t.ins_h=ft(t,t.ins_h,t.window[t.strstart+3-1]),a=t.prev[t.strstart&t.w_mask]=t.head[t.ins_h],t.head[t.ins_h]=t.strstart),t.prev_length=t.match_length,t.prev_match=t.match_start,t.match_length=2,0!==a&&t.prev_length<t.max_lazy_match&&t.strstart-a<=t.w_size-262&&(t.match_length=gt(t,a),t.match_length<=5&&(t.strategy===et||3===t.match_length&&t.strstart-t.match_start>4096)&&(t.match_length=2)),t.prev_length>=3&&t.match_length<=t.prev_length){n=t.strstart+t.lookahead-3,i=j(t,t.strstart-1-t.prev_match,t.prev_length-3),t.lookahead-=t.prev_length-1,t.prev_length-=2;do{++t.strstart<=n&&(t.ins_h=ft(t,t.ins_h,t.window[t.strstart+3-1]),a=t.prev[t.strstart&t.w_mask]=t.head[t.ins_h],t.head[t.ins_h]=t.strstart)}while(0!=--t.prev_length);if(t.match_available=0,t.match_length=2,t.strstart++,i&&(ut(t,!1),0===t.strm.avail_out))return 1}else if(t.match_available){if(i=j(t,0,t.window[t.strstart-1]),i&&ut(t,!1),t.strstart++,t.lookahead--,0===t.strm.avail_out)return 1}else t.match_available=1,t.strstart++,t.lookahead--}return t.match_available&&(i=j(t,0,t.window[t.strstart-1]),t.match_available=0),t.insert=t.strstart<2?t.strstart:2,e===X?(ut(t,!0),0===t.strm.avail_out?3:4):t.sym_next&&(ut(t,!1),0===t.strm.avail_out)?1:2};function xt(t,e,a,i,n){this.good_length=t,this.max_lazy=e,this.nice_length=a,this.max_chain=i,this.func=n}const zt=[new xt(0,0,0,0,kt),new xt(4,4,8,4,vt),new xt(4,5,16,8,vt),new xt(4,6,32,32,vt),new xt(4,4,16,16,yt),new xt(8,16,32,32,yt),new xt(8,16,128,128,yt),new xt(8,32,128,256,yt),new xt(32,128,258,1024,yt),new xt(32,258,258,4096,yt)];function At(){this.strm=null,this.status=0,this.pending_buf=null,this.pending_buf_size=0,this.pending_out=0,this.pending=0,this.wrap=0,this.gzhead=null,this.gzindex=0,this.method=ot,this.last_flush=-1,this.w_size=0,this.w_bits=0,this.w_mask=0,this.window=null,this.window_size=0,this.prev=null,this.head=null,this.ins_h=0,this.hash_size=0,this.hash_bits=0,this.hash_mask=0,this.hash_shift=0,this.block_start=0,this.match_length=0,this.prev_match=0,this.match_available=0,this.strstart=0,this.match_start=0,this.lookahead=0,this.prev_length=0,this.max_chain_length=0,this.max_lazy_match=0,this.level=0,this.strategy=0,this.good_match=0,this.nice_match=0,this.dyn_ltree=new Uint16Array(1146),this.dyn_dtree=new Uint16Array(122),this.bl_tree=new Uint16Array(78),dt(this.dyn_ltree),dt(this.dyn_dtree),dt(this.bl_tree),this.l_desc=null,this.d_desc=null,this.bl_desc=null,this.bl_count=new Uint16Array(16),this.heap=new Uint16Array(573),dt(this.heap),this.heap_len=0,this.heap_max=0,this.depth=new Uint16Array(573),dt(this.depth),this.sym_buf=0,this.lit_bufsize=0,this.sym_next=0,this.sym_end=0,this.opt_len=0,this.static_len=0,this.matches=0,this.insert=0,this.bi_buf=0,this.bi_valid=0}const Et=t=>{if(!t)return 1;const e=t.state;return!e||e.strm!==t||42!==e.status&&57!==e.status&&69!==e.status&&73!==e.status&&91!==e.status&&103!==e.status&&113!==e.status&&666!==e.status?1:0},Rt=t=>{if(Et(t))return lt(t,Q);t.total_in=t.total_out=0,t.data_type=rt;const e=t.state;return e.pending=0,e.pending_out=0,e.wrap<0&&(e.wrap=-e.wrap),e.status=2===e.wrap?57:e.wrap?42:113,t.adler=2===e.wrap?0:1,e.last_flush=-2,C(e),q},Zt=t=>{const e=Rt(t);var a;return e===q&&((a=t.state).window_size=2*a.w_size,dt(a.head),a.max_lazy_match=zt[a.level].max_lazy,a.good_match=zt[a.level].good_length,a.nice_match=zt[a.level].nice_length,a.max_chain_length=zt[a.level].max_chain,a.strstart=0,a.block_start=0,a.lookahead=0,a.insert=0,a.match_length=a.prev_length=2,a.match_available=0,a.ins_h=0),e},Ut=(t,e,a,i,n,s)=>{if(!t)return Q;let r=1;if(e===tt&&(e=6),i<0?(r=0,i=-i):i>15&&(r=2,i-=16),n<1||n>9||a!==ot||i<8||i>15||e<0||e>9||s<0||s>nt||8===i&&1!==r)return lt(t,Q);8===i&&(i=9);const o=new At;return t.state=o,o.strm=t,o.status=42,o.wrap=r,o.gzhead=null,o.w_bits=i,o.w_size=1<<o.w_bits,o.w_mask=o.w_size-1,o.hash_bits=n+7,o.hash_size=1<<o.hash_bits,o.hash_mask=o.hash_size-1,o.hash_shift=~~((o.hash_bits+3-1)/3),o.window=new Uint8Array(2*o.w_size),o.head=new Uint16Array(o.hash_size),o.prev=new Uint16Array(o.w_size),o.lit_bufsize=1<<n+6,o.pending_buf_size=4*o.lit_bufsize,o.pending_buf=new Uint8Array(o.pending_buf_size),o.sym_buf=o.lit_bufsize,o.sym_end=3*(o.lit_bufsize-1),o.level=e,o.strategy=s,o.method=a,Zt(t)};var St={deflateInit:(t,e)=>Ut(t,e,ot,15,8,st),deflateInit2:Ut,deflateReset:Zt,deflateResetKeep:Rt,deflateSetHeader:(t,e)=>Et(t)||2!==t.state.wrap?Q:(t.state.gzhead=e,q),deflate:(t,e)=>{if(Et(t)||e>W||e<0)return t?lt(t,Q):Q;const a=t.state;if(!t.output||0!==t.avail_in&&!t.input||666===a.status&&e!==X)return lt(t,0===t.avail_out?$:Q);const i=a.last_flush;if(a.last_flush=e,0!==a.pending){if(ct(t),0===t.avail_out)return a.last_flush=-1,q}else if(0===t.avail_in&&ht(e)<=ht(i)&&e!==X)return lt(t,$);if(666===a.status&&0!==t.avail_in)return lt(t,$);if(42===a.status&&0===a.wrap&&(a.status=113),42===a.status){let e=ot+(a.w_bits-8<<4)<<8,i=-1;if(i=a.strategy>=at||a.level<2?0:a.level<6?1:6===a.level?2:3,e|=i<<6,0!==a.strstart&&(e|=32),e+=31-e%31,mt(a,e),0!==a.strstart&&(mt(a,t.adler>>>16),mt(a,65535&t.adler)),t.adler=1,a.status=113,ct(t),0!==a.pending)return a.last_flush=-1,q}if(57===a.status)if(t.adler=0,wt(a,31),wt(a,139),wt(a,8),a.gzhead)wt(a,(a.gzhead.text?1:0)+(a.gzhead.hcrc?2:0)+(a.gzhead.extra?4:0)+(a.gzhead.name?8:0)+(a.gzhead.comment?16:0)),wt(a,255&a.gzhead.time),wt(a,a.gzhead.time>>8&255),wt(a,a.gzhead.time>>16&255),wt(a,a.gzhead.time>>24&255),wt(a,9===a.level?2:a.strategy>=at||a.level<2?4:0),wt(a,255&a.gzhead.os),a.gzhead.extra&&a.gzhead.extra.length&&(wt(a,255&a.gzhead.extra.length),wt(a,a.gzhead.extra.length>>8&255)),a.gzhead.hcrc&&(t.adler=N(t.adler,a.pending_buf,a.pending,0)),a.gzindex=0,a.status=69;else if(wt(a,0),wt(a,0),wt(a,0),wt(a,0),wt(a,0),wt(a,9===a.level?2:a.strategy>=at||a.level<2?4:0),wt(a,3),a.status=113,ct(t),0!==a.pending)return a.last_flush=-1,q;if(69===a.status){if(a.gzhead.extra){let e=a.pending,i=(65535&a.gzhead.extra.length)-a.gzindex;for(;a.pending+i>a.pending_buf_size;){let n=a.pending_buf_size-a.pending;if(a.pending_buf.set(a.gzhead.extra.subarray(a.gzindex,a.gzindex+n),a.pending),a.pending=a.pending_buf_size,a.gzhead.hcrc&&a.pending>e&&(t.adler=N(t.adler,a.pending_buf,a.pending-e,e)),a.gzindex+=n,ct(t),0!==a.pending)return a.last_flush=-1,q;e=0,i-=n}let n=new Uint8Array(a.gzhead.extra);a.pending_buf.set(n.subarray(a.gzindex,a.gzindex+i),a.pending),a.pending+=i,a.gzhead.hcrc&&a.pending>e&&(t.adler=N(t.adler,a.pending_buf,a.pending-e,e)),a.gzindex=0}a.status=73}if(73===a.status){if(a.gzhead.name){let e,i=a.pending;do{if(a.pending===a.pending_buf_size){if(a.gzhead.hcrc&&a.pending>i&&(t.adler=N(t.adler,a.pending_buf,a.pending-i,i)),ct(t),0!==a.pending)return a.last_flush=-1,q;i=0}e=a.gzindex<a.gzhead.name.length?255&a.gzhead.name.charCodeAt(a.gzindex++):0,wt(a,e)}while(0!==e);a.gzhead.hcrc&&a.pending>i&&(t.adler=N(t.adler,a.pending_buf,a.pending-i,i)),a.gzindex=0}a.status=91}if(91===a.status){if(a.gzhead.comment){let e,i=a.pending;do{if(a.pending===a.pending_buf_size){if(a.gzhead.hcrc&&a.pending>i&&(t.adler=N(t.adler,a.pending_buf,a.pending-i,i)),ct(t),0!==a.pending)return a.last_flush=-1,q;i=0}e=a.gzindex<a.gzhead.comment.length?255&a.gzhead.comment.charCodeAt(a.gzindex++):0,wt(a,e)}while(0!==e);a.gzhead.hcrc&&a.pending>i&&(t.adler=N(t.adler,a.pending_buf,a.pending-i,i))}a.status=103}if(103===a.status){if(a.gzhead.hcrc){if(a.pending+2>a.pending_buf_size&&(ct(t),0!==a.pending))return a.last_flush=-1,q;wt(a,255&t.adler),wt(a,t.adler>>8&255),t.adler=0}if(a.status=113,ct(t),0!==a.pending)return a.last_flush=-1,q}if(0!==t.avail_in||0!==a.lookahead||e!==P&&666!==a.status){let i=0===a.level?kt(a,e):a.strategy===at?((t,e)=>{let a;for(;;){if(0===t.lookahead&&(pt(t),0===t.lookahead)){if(e===P)return 1;break}if(t.match_length=0,a=j(t,0,t.window[t.strstart]),t.lookahead--,t.strstart++,a&&(ut(t,!1),0===t.strm.avail_out))return 1}return t.insert=0,e===X?(ut(t,!0),0===t.strm.avail_out?3:4):t.sym_next&&(ut(t,!1),0===t.strm.avail_out)?1:2})(a,e):a.strategy===it?((t,e)=>{let a,i,n,s;const r=t.window;for(;;){if(t.lookahead<=258){if(pt(t),t.lookahead<=258&&e===P)return 1;if(0===t.lookahead)break}if(t.match_length=0,t.lookahead>=3&&t.strstart>0&&(n=t.strstart-1,i=r[n],i===r[++n]&&i===r[++n]&&i===r[++n])){s=t.strstart+258;do{}while(i===r[++n]&&i===r[++n]&&i===r[++n]&&i===r[++n]&&i===r[++n]&&i===r[++n]&&i===r[++n]&&i===r[++n]&&n<s);t.match_length=258-(s-n),t.match_length>t.lookahead&&(t.match_length=t.lookahead)}if(t.match_length>=3?(a=j(t,1,t.match_length-3),t.lookahead-=t.match_length,t.strstart+=t.match_length,t.match_length=0):(a=j(t,0,t.window[t.strstart]),t.lookahead--,t.strstart++),a&&(ut(t,!1),0===t.strm.avail_out))return 1}return t.insert=0,e===X?(ut(t,!0),0===t.strm.avail_out?3:4):t.sym_next&&(ut(t,!1),0===t.strm.avail_out)?1:2})(a,e):zt[a.level].func(a,e);if(3!==i&&4!==i||(a.status=666),1===i||3===i)return 0===t.avail_out&&(a.last_flush=-1),q;if(2===i&&(e===Y?K(a):e!==W&&(H(a,0,0,!1),e===G&&(dt(a.head),0===a.lookahead&&(a.strstart=0,a.block_start=0,a.insert=0))),ct(t),0===t.avail_out))return a.last_flush=-1,q}return e!==X?q:a.wrap<=0?J:(2===a.wrap?(wt(a,255&t.adler),wt(a,t.adler>>8&255),wt(a,t.adler>>16&255),wt(a,t.adler>>24&255),wt(a,255&t.total_in),wt(a,t.total_in>>8&255),wt(a,t.total_in>>16&255),wt(a,t.total_in>>24&255)):(mt(a,t.adler>>>16),mt(a,65535&t.adler)),ct(t),a.wrap>0&&(a.wrap=-a.wrap),0!==a.pending?q:J)},deflateEnd:t=>{if(Et(t))return Q;const e=t.state.status;return t.state=null,113===e?lt(t,V):q},deflateSetDictionary:(t,e)=>{let a=e.length;if(Et(t))return Q;const i=t.state,n=i.wrap;if(2===n||1===n&&42!==i.status||i.lookahead)return Q;if(1===n&&(t.adler=F(t.adler,e,a,0)),i.wrap=0,a>=i.w_size){0===n&&(dt(i.head),i.strstart=0,i.block_start=0,i.insert=0);let t=new Uint8Array(i.w_size);t.set(e.subarray(a-i.w_size,a),0),e=t,a=i.w_size}const s=t.avail_in,r=t.next_in,o=t.input;for(t.avail_in=a,t.next_in=0,t.input=e,pt(i);i.lookahead>=3;){let t=i.strstart,e=i.lookahead-2;do{i.ins_h=ft(i,i.ins_h,i.window[t+3-1]),i.prev[t&i.w_mask]=i.head[i.ins_h],i.head[i.ins_h]=t,t++}while(--e);i.strstart=t,i.lookahead=2,pt(i)}return i.strstart+=i.lookahead,i.block_start=i.strstart,i.insert=i.lookahead,i.lookahead=0,i.match_length=i.prev_length=2,i.match_available=0,t.next_in=r,t.input=o,t.avail_in=s,i.wrap=n,q},deflateInfo:"pako deflate (from Nodeca project)"};const Dt=(t,e)=>Object.prototype.hasOwnProperty.call(t,e);var Tt=function(t){const e=Array.prototype.slice.call(arguments,1);for(;e.length;){const a=e.shift();if(a){if("object"!=typeof a)throw new TypeError(a+"must be non-object");for(const e in a)Dt(a,e)&&(t[e]=a[e])}}return t},Ot=t=>{let e=0;for(let a=0,i=t.length;a<i;a++)e+=t[a].length;const a=new Uint8Array(e);for(let e=0,i=0,n=t.length;e<n;e++){let n=t[e];a.set(n,i),i+=n.length}return a};let Ft=!0;try{String.fromCharCode.apply(null,new Uint8Array(1))}catch(t){Ft=!1}const Lt=new Uint8Array(256);for(let t=0;t<256;t++)Lt[t]=t>=252?6:t>=248?5:t>=240?4:t>=224?3:t>=192?2:1;Lt[254]=Lt[254]=1;var Nt=t=>{if("function"==typeof TextEncoder&&TextEncoder.prototype.encode)return(new TextEncoder).encode(t);let e,a,i,n,s,r=t.length,o=0;for(n=0;n<r;n++)a=t.charCodeAt(n),55296==(64512&a)&&n+1<r&&(i=t.charCodeAt(n+1),56320==(64512&i)&&(a=65536+(a-55296<<10)+(i-56320),n++)),o+=a<128?1:a<2048?2:a<65536?3:4;for(e=new Uint8Array(o),s=0,n=0;s<o;n++)a=t.charCodeAt(n),55296==(64512&a)&&n+1<r&&(i=t.charCodeAt(n+1),56320==(64512&i)&&(a=65536+(a-55296<<10)+(i-56320),n++)),a<128?e[s++]=a:a<2048?(e[s++]=192|a>>>6,e[s++]=128|63&a):a<65536?(e[s++]=224|a>>>12,e[s++]=128|a>>>6&63,e[s++]=128|63&a):(e[s++]=240|a>>>18,e[s++]=128|a>>>12&63,e[s++]=128|a>>>6&63,e[s++]=128|63&a);return e},It=(t,e)=>{const a=e||t.length;if("function"==typeof TextDecoder&&TextDecoder.prototype.decode)return(new TextDecoder).decode(t.subarray(0,e));let i,n;const s=new Array(2*a);for(n=0,i=0;i<a;){let e=t[i++];if(e<128){s[n++]=e;continue}let r=Lt[e];if(r>4)s[n++]=65533,i+=r-1;else{for(e&=2===r?31:3===r?15:7;r>1&&i<a;)e=e<<6|63&t[i++],r--;r>1?s[n++]=65533:e<65536?s[n++]=e:(e-=65536,s[n++]=55296|e>>10&1023,s[n++]=56320|1023&e)}}return((t,e)=>{if(e<65534&&t.subarray&&Ft)return String.fromCharCode.apply(null,t.length===e?t:t.subarray(0,e));let a="";for(let i=0;i<e;i++)a+=String.fromCharCode(t[i]);return a})(s,n)},Bt=(t,e)=>{(e=e||t.length)>t.length&&(e=t.length);let a=e-1;for(;a>=0&&128==(192&t[a]);)a--;return a<0||0===a?e:a+Lt[t[a]]>e?a:e};var Ct=function(){this.input=null,this.next_in=0,this.avail_in=0,this.total_in=0,this.output=null,this.next_out=0,this.avail_out=0,this.total_out=0,this.msg="",this.state=null,this.data_type=2,this.adler=0};const Ht=Object.prototype.toString,{Z_NO_FLUSH:Mt,Z_SYNC_FLUSH:jt,Z_FULL_FLUSH:Kt,Z_FINISH:Pt,Z_OK:Yt,Z_STREAM_END:Gt,Z_DEFAULT_COMPRESSION:Xt,Z_DEFAULT_STRATEGY:Wt,Z_DEFLATED:qt}=B;function Jt(t){this.options=Tt({level:Xt,method:qt,chunkSize:16384,windowBits:15,memLevel:8,strategy:Wt},t||{});let e=this.options;e.raw&&e.windowBits>0?e.windowBits=-e.windowBits:e.gzip&&e.windowBits>0&&e.windowBits<16&&(e.windowBits+=16),this.err=0,this.msg="",this.ended=!1,this.chunks=[],this.strm=new Ct,this.strm.avail_out=0;let a=St.deflateInit2(this.strm,e.level,e.method,e.windowBits,e.memLevel,e.strategy);if(a!==Yt)throw new Error(I[a]);if(e.header&&St.deflateSetHeader(this.strm,e.header),e.dictionary){let t;if(t="string"==typeof e.dictionary?Nt(e.dictionary):"[object ArrayBuffer]"===Ht.call(e.dictionary)?new Uint8Array(e.dictionary):e.dictionary,a=St.deflateSetDictionary(this.strm,t),a!==Yt)throw new Error(I[a]);this._dict_set=!0}}function Qt(t,e){const a=new Jt(e);if(a.push(t,!0),a.err)throw a.msg||I[a.err];return a.result}Jt.prototype.push=function(t,e){const a=this.strm,i=this.options.chunkSize;let n,s;if(this.ended)return!1;for(s=e===~~e?e:!0===e?Pt:Mt,"string"==typeof t?a.input=Nt(t):"[object ArrayBuffer]"===Ht.call(t)?a.input=new Uint8Array(t):a.input=t,a.next_in=0,a.avail_in=a.input.length;;)if(0===a.avail_out&&(a.output=new Uint8Array(i),a.next_out=0,a.avail_out=i),(s===jt||s===Kt)&&a.avail_out<=6)this.onData(a.output.subarray(0,a.next_out)),a.avail_out=0;else{if(n=St.deflate(a,s),n===Gt)return a.next_out>0&&this.onData(a.output.subarray(0,a.next_out)),n=St.deflateEnd(this.strm),this.onEnd(n),this.ended=!0,n===Yt;if(0!==a.avail_out){if(s>0&&a.next_out>0)this.onData(a.output.subarray(0,a.next_out)),a.avail_out=0;else if(0===a.avail_in)break}else this.onData(a.output)}return!0},Jt.prototype.onData=function(t){this.chunks.push(t)},Jt.prototype.onEnd=function(t){t===Yt&&(this.result=Ot(this.chunks)),this.chunks=[],this.err=t,this.msg=this.strm.msg};var Vt={Deflate:Jt,deflate:Qt,deflateRaw:function(t,e){return(e=e||{}).raw=!0,Qt(t,e)},gzip:function(t,e){return(e=e||{}).gzip=!0,Qt(t,e)},constants:B};var $t=function(t,e){let a,i,n,s,r,o,l,h,d,_,f,c,u,w,m,b,g,p,k,v,y,x,z,A;const E=t.state;a=t.next_in,z=t.input,i=a+(t.avail_in-5),n=t.next_out,A=t.output,s=n-(e-t.avail_out),r=n+(t.avail_out-257),o=E.dmax,l=E.wsize,h=E.whave,d=E.wnext,_=E.window,f=E.hold,c=E.bits,u=E.lencode,w=E.distcode,m=(1<<E.lenbits)-1,b=(1<<E.distbits)-1;t:do{c<15&&(f+=z[a++]<<c,c+=8,f+=z[a++]<<c,c+=8),g=u[f&m];e:for(;;){if(p=g>>>24,f>>>=p,c-=p,p=g>>>16&255,0===p)A[n++]=65535&g;else{if(!(16&p)){if(0==(64&p)){g=u[(65535&g)+(f&(1<<p)-1)];continue e}if(32&p){E.mode=16191;break t}t.msg="invalid literal/length code",E.mode=16209;break t}k=65535&g,p&=15,p&&(c<p&&(f+=z[a++]<<c,c+=8),k+=f&(1<<p)-1,f>>>=p,c-=p),c<15&&(f+=z[a++]<<c,c+=8,f+=z[a++]<<c,c+=8),g=w[f&b];a:for(;;){if(p=g>>>24,f>>>=p,c-=p,p=g>>>16&255,!(16&p)){if(0==(64&p)){g=w[(65535&g)+(f&(1<<p)-1)];continue a}t.msg="invalid distance code",E.mode=16209;break t}if(v=65535&g,p&=15,c<p&&(f+=z[a++]<<c,c+=8,c<p&&(f+=z[a++]<<c,c+=8)),v+=f&(1<<p)-1,v>o){t.msg="invalid distance too far back",E.mode=16209;break t}if(f>>>=p,c-=p,p=n-s,v>p){if(p=v-p,p>h&&E.sane){t.msg="invalid distance too far back",E.mode=16209;break t}if(y=0,x=_,0===d){if(y+=l-p,p<k){k-=p;do{A[n++]=_[y++]}while(--p);y=n-v,x=A}}else if(d<p){if(y+=l+d-p,p-=d,p<k){k-=p;do{A[n++]=_[y++]}while(--p);if(y=0,d<k){p=d,k-=p;do{A[n++]=_[y++]}while(--p);y=n-v,x=A}}}else if(y+=d-p,p<k){k-=p;do{A[n++]=_[y++]}while(--p);y=n-v,x=A}for(;k>2;)A[n++]=x[y++],A[n++]=x[y++],A[n++]=x[y++],k-=3;k&&(A[n++]=x[y++],k>1&&(A[n++]=x[y++]))}else{y=n-v;do{A[n++]=A[y++],A[n++]=A[y++],A[n++]=A[y++],k-=3}while(k>2);k&&(A[n++]=A[y++],k>1&&(A[n++]=A[y++]))}break}}break}}while(a<i&&n<r);k=c>>3,a-=k,c-=k<<3,f&=(1<<c)-1,t.next_in=a,t.next_out=n,t.avail_in=a<i?i-a+5:5-(a-i),t.avail_out=n<r?r-n+257:257-(n-r),E.hold=f,E.bits=c};const te=new Uint16Array([3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258,0,0]),ee=new Uint8Array([16,16,16,16,16,16,16,16,17,17,17,17,18,18,18,18,19,19,19,19,20,20,20,20,21,21,21,21,16,72,78]),ae=new Uint16Array([1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0]),ie=new Uint8Array([16,16,16,16,17,17,18,18,19,19,20,20,21,21,22,22,23,23,24,24,25,25,26,26,27,27,28,28,29,29,64,64]);var ne=(t,e,a,i,n,s,r,o)=>{const l=o.bits;let h,d,_,f,c,u,w=0,m=0,b=0,g=0,p=0,k=0,v=0,y=0,x=0,z=0,A=null;const E=new Uint16Array(16),R=new Uint16Array(16);let Z,U,S,D=null;for(w=0;w<=15;w++)E[w]=0;for(m=0;m<i;m++)E[e[a+m]]++;for(p=l,g=15;g>=1&&0===E[g];g--);if(p>g&&(p=g),0===g)return n[s++]=20971520,n[s++]=20971520,o.bits=1,0;for(b=1;b<g&&0===E[b];b++);for(p<b&&(p=b),y=1,w=1;w<=15;w++)if(y<<=1,y-=E[w],y<0)return-1;if(y>0&&(0===t||1!==g))return-1;for(R[1]=0,w=1;w<15;w++)R[w+1]=R[w]+E[w];for(m=0;m<i;m++)0!==e[a+m]&&(r[R[e[a+m]]++]=m);if(0===t?(A=D=r,u=20):1===t?(A=te,D=ee,u=257):(A=ae,D=ie,u=0),z=0,m=0,w=b,c=s,k=p,v=0,_=-1,x=1<<p,f=x-1,1===t&&x>852||2===t&&x>592)return 1;for(;;){Z=w-v,r[m]+1<u?(U=0,S=r[m]):r[m]>=u?(U=D[r[m]-u],S=A[r[m]-u]):(U=96,S=0),h=1<<w-v,d=1<<k,b=d;do{d-=h,n[c+(z>>v)+d]=Z<<24|U<<16|S|0}while(0!==d);for(h=1<<w-1;z&h;)h>>=1;if(0!==h?(z&=h-1,z+=h):z=0,m++,0==--E[w]){if(w===g)break;w=e[a+r[m]]}if(w>p&&(z&f)!==_){for(0===v&&(v=p),c+=b,k=w-v,y=1<<k;k+v<g&&(y-=E[k+v],!(y<=0));)k++,y<<=1;if(x+=1<<k,1===t&&x>852||2===t&&x>592)return 1;_=z&f,n[_]=p<<24|k<<16|c-s|0}}return 0!==z&&(n[c+z]=w-v<<24|64<<16|0),o.bits=p,0};const{Z_FINISH:se,Z_BLOCK:re,Z_TREES:oe,Z_OK:le,Z_STREAM_END:he,Z_NEED_DICT:de,Z_STREAM_ERROR:_e,Z_DATA_ERROR:fe,Z_MEM_ERROR:ce,Z_BUF_ERROR:ue,Z_DEFLATED:we}=B,me=16209,be=t=>(t>>>24&255)+(t>>>8&65280)+((65280&t)<<8)+((255&t)<<24);function ge(){this.strm=null,this.mode=0,this.last=!1,this.wrap=0,this.havedict=!1,this.flags=0,this.dmax=0,this.check=0,this.total=0,this.head=null,this.wbits=0,this.wsize=0,this.whave=0,this.wnext=0,this.window=null,this.hold=0,this.bits=0,this.length=0,this.offset=0,this.extra=0,this.lencode=null,this.distcode=null,this.lenbits=0,this.distbits=0,this.ncode=0,this.nlen=0,this.ndist=0,this.have=0,this.next=null,this.lens=new Uint16Array(320),this.work=new Uint16Array(288),this.lendyn=null,this.distdyn=null,this.sane=0,this.back=0,this.was=0}const pe=t=>{if(!t)return 1;const e=t.state;return!e||e.strm!==t||e.mode<16180||e.mode>16211?1:0},ke=t=>{if(pe(t))return _e;const e=t.state;return t.total_in=t.total_out=e.total=0,t.msg="",e.wrap&&(t.adler=1&e.wrap),e.mode=16180,e.last=0,e.havedict=0,e.flags=-1,e.dmax=32768,e.head=null,e.hold=0,e.bits=0,e.lencode=e.lendyn=new Int32Array(852),e.distcode=e.distdyn=new Int32Array(592),e.sane=1,e.back=-1,le},ve=t=>{if(pe(t))return _e;const e=t.state;return e.wsize=0,e.whave=0,e.wnext=0,ke(t)},ye=(t,e)=>{let a;if(pe(t))return _e;const i=t.state;return e<0?(a=0,e=-e):(a=5+(e>>4),e<48&&(e&=15)),e&&(e<8||e>15)?_e:(null!==i.window&&i.wbits!==e&&(i.window=null),i.wrap=a,i.wbits=e,ve(t))},xe=(t,e)=>{if(!t)return _e;const a=new ge;t.state=a,a.strm=t,a.window=null,a.mode=16180;const i=ye(t,e);return i!==le&&(t.state=null),i};let ze,Ae,Ee=!0;const Re=t=>{if(Ee){ze=new Int32Array(512),Ae=new Int32Array(32);let e=0;for(;e<144;)t.lens[e++]=8;for(;e<256;)t.lens[e++]=9;for(;e<280;)t.lens[e++]=7;for(;e<288;)t.lens[e++]=8;for(ne(1,t.lens,0,288,ze,0,t.work,{bits:9}),e=0;e<32;)t.lens[e++]=5;ne(2,t.lens,0,32,Ae,0,t.work,{bits:5}),Ee=!1}t.lencode=ze,t.lenbits=9,t.distcode=Ae,t.distbits=5},Ze=(t,e,a,i)=>{let n;const s=t.state;return null===s.window&&(s.wsize=1<<s.wbits,s.wnext=0,s.whave=0,s.window=new Uint8Array(s.wsize)),i>=s.wsize?(s.window.set(e.subarray(a-s.wsize,a),0),s.wnext=0,s.whave=s.wsize):(n=s.wsize-s.wnext,n>i&&(n=i),s.window.set(e.subarray(a-i,a-i+n),s.wnext),(i-=n)?(s.window.set(e.subarray(a-i,a),0),s.wnext=i,s.whave=s.wsize):(s.wnext+=n,s.wnext===s.wsize&&(s.wnext=0),s.whave<s.wsize&&(s.whave+=n))),0};var Ue={inflateReset:ve,inflateReset2:ye,inflateResetKeep:ke,inflateInit:t=>xe(t,15),inflateInit2:xe,inflate:(t,e)=>{let a,i,n,s,r,o,l,h,d,_,f,c,u,w,m,b,g,p,k,v,y,x,z=0;const A=new Uint8Array(4);let E,R;const Z=new Uint8Array([16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15]);if(pe(t)||!t.output||!t.input&&0!==t.avail_in)return _e;a=t.state,16191===a.mode&&(a.mode=16192),r=t.next_out,n=t.output,l=t.avail_out,s=t.next_in,i=t.input,o=t.avail_in,h=a.hold,d=a.bits,_=o,f=l,x=le;t:for(;;)switch(a.mode){case 16180:if(0===a.wrap){a.mode=16192;break}for(;d<16;){if(0===o)break t;o--,h+=i[s++]<<d,d+=8}if(2&a.wrap&&35615===h){0===a.wbits&&(a.wbits=15),a.check=0,A[0]=255&h,A[1]=h>>>8&255,a.check=N(a.check,A,2,0),h=0,d=0,a.mode=16181;break}if(a.head&&(a.head.done=!1),!(1&a.wrap)||(((255&h)<<8)+(h>>8))%31){t.msg="incorrect header check",a.mode=me;break}if((15&h)!==we){t.msg="unknown compression method",a.mode=me;break}if(h>>>=4,d-=4,y=8+(15&h),0===a.wbits&&(a.wbits=y),y>15||y>a.wbits){t.msg="invalid window size",a.mode=me;break}a.dmax=1<<a.wbits,a.flags=0,t.adler=a.check=1,a.mode=512&h?16189:16191,h=0,d=0;break;case 16181:for(;d<16;){if(0===o)break t;o--,h+=i[s++]<<d,d+=8}if(a.flags=h,(255&a.flags)!==we){t.msg="unknown compression method",a.mode=me;break}if(57344&a.flags){t.msg="unknown header flags set",a.mode=me;break}a.head&&(a.head.text=h>>8&1),512&a.flags&&4&a.wrap&&(A[0]=255&h,A[1]=h>>>8&255,a.check=N(a.check,A,2,0)),h=0,d=0,a.mode=16182;case 16182:for(;d<32;){if(0===o)break t;o--,h+=i[s++]<<d,d+=8}a.head&&(a.head.time=h),512&a.flags&&4&a.wrap&&(A[0]=255&h,A[1]=h>>>8&255,A[2]=h>>>16&255,A[3]=h>>>24&255,a.check=N(a.check,A,4,0)),h=0,d=0,a.mode=16183;case 16183:for(;d<16;){if(0===o)break t;o--,h+=i[s++]<<d,d+=8}a.head&&(a.head.xflags=255&h,a.head.os=h>>8),512&a.flags&&4&a.wrap&&(A[0]=255&h,A[1]=h>>>8&255,a.check=N(a.check,A,2,0)),h=0,d=0,a.mode=16184;case 16184:if(1024&a.flags){for(;d<16;){if(0===o)break t;o--,h+=i[s++]<<d,d+=8}a.length=h,a.head&&(a.head.extra_len=h),512&a.flags&&4&a.wrap&&(A[0]=255&h,A[1]=h>>>8&255,a.check=N(a.check,A,2,0)),h=0,d=0}else a.head&&(a.head.extra=null);a.mode=16185;case 16185:if(1024&a.flags&&(c=a.length,c>o&&(c=o),c&&(a.head&&(y=a.head.extra_len-a.length,a.head.extra||(a.head.extra=new Uint8Array(a.head.extra_len)),a.head.extra.set(i.subarray(s,s+c),y)),512&a.flags&&4&a.wrap&&(a.check=N(a.check,i,c,s)),o-=c,s+=c,a.length-=c),a.length))break t;a.length=0,a.mode=16186;case 16186:if(2048&a.flags){if(0===o)break t;c=0;do{y=i[s+c++],a.head&&y&&a.length<65536&&(a.head.name+=String.fromCharCode(y))}while(y&&c<o);if(512&a.flags&&4&a.wrap&&(a.check=N(a.check,i,c,s)),o-=c,s+=c,y)break t}else a.head&&(a.head.name=null);a.length=0,a.mode=16187;case 16187:if(4096&a.flags){if(0===o)break t;c=0;do{y=i[s+c++],a.head&&y&&a.length<65536&&(a.head.comment+=String.fromCharCode(y))}while(y&&c<o);if(512&a.flags&&4&a.wrap&&(a.check=N(a.check,i,c,s)),o-=c,s+=c,y)break t}else a.head&&(a.head.comment=null);a.mode=16188;case 16188:if(512&a.flags){for(;d<16;){if(0===o)break t;o--,h+=i[s++]<<d,d+=8}if(4&a.wrap&&h!==(65535&a.check)){t.msg="header crc mismatch",a.mode=me;break}h=0,d=0}a.head&&(a.head.hcrc=a.flags>>9&1,a.head.done=!0),t.adler=a.check=0,a.mode=16191;break;case 16189:for(;d<32;){if(0===o)break t;o--,h+=i[s++]<<d,d+=8}t.adler=a.check=be(h),h=0,d=0,a.mode=16190;case 16190:if(0===a.havedict)return t.next_out=r,t.avail_out=l,t.next_in=s,t.avail_in=o,a.hold=h,a.bits=d,de;t.adler=a.check=1,a.mode=16191;case 16191:if(e===re||e===oe)break t;case 16192:if(a.last){h>>>=7&d,d-=7&d,a.mode=16206;break}for(;d<3;){if(0===o)break t;o--,h+=i[s++]<<d,d+=8}switch(a.last=1&h,h>>>=1,d-=1,3&h){case 0:a.mode=16193;break;case 1:if(Re(a),a.mode=16199,e===oe){h>>>=2,d-=2;break t}break;case 2:a.mode=16196;break;case 3:t.msg="invalid block type",a.mode=me}h>>>=2,d-=2;break;case 16193:for(h>>>=7&d,d-=7&d;d<32;){if(0===o)break t;o--,h+=i[s++]<<d,d+=8}if((65535&h)!=(h>>>16^65535)){t.msg="invalid stored block lengths",a.mode=me;break}if(a.length=65535&h,h=0,d=0,a.mode=16194,e===oe)break t;case 16194:a.mode=16195;case 16195:if(c=a.length,c){if(c>o&&(c=o),c>l&&(c=l),0===c)break t;n.set(i.subarray(s,s+c),r),o-=c,s+=c,l-=c,r+=c,a.length-=c;break}a.mode=16191;break;case 16196:for(;d<14;){if(0===o)break t;o--,h+=i[s++]<<d,d+=8}if(a.nlen=257+(31&h),h>>>=5,d-=5,a.ndist=1+(31&h),h>>>=5,d-=5,a.ncode=4+(15&h),h>>>=4,d-=4,a.nlen>286||a.ndist>30){t.msg="too many length or distance symbols",a.mode=me;break}a.have=0,a.mode=16197;case 16197:for(;a.have<a.ncode;){for(;d<3;){if(0===o)break t;o--,h+=i[s++]<<d,d+=8}a.lens[Z[a.have++]]=7&h,h>>>=3,d-=3}for(;a.have<19;)a.lens[Z[a.have++]]=0;if(a.lencode=a.lendyn,a.lenbits=7,E={bits:a.lenbits},x=ne(0,a.lens,0,19,a.lencode,0,a.work,E),a.lenbits=E.bits,x){t.msg="invalid code lengths set",a.mode=me;break}a.have=0,a.mode=16198;case 16198:for(;a.have<a.nlen+a.ndist;){for(;z=a.lencode[h&(1<<a.lenbits)-1],m=z>>>24,b=z>>>16&255,g=65535&z,!(m<=d);){if(0===o)break t;o--,h+=i[s++]<<d,d+=8}if(g<16)h>>>=m,d-=m,a.lens[a.have++]=g;else{if(16===g){for(R=m+2;d<R;){if(0===o)break t;o--,h+=i[s++]<<d,d+=8}if(h>>>=m,d-=m,0===a.have){t.msg="invalid bit length repeat",a.mode=me;break}y=a.lens[a.have-1],c=3+(3&h),h>>>=2,d-=2}else if(17===g){for(R=m+3;d<R;){if(0===o)break t;o--,h+=i[s++]<<d,d+=8}h>>>=m,d-=m,y=0,c=3+(7&h),h>>>=3,d-=3}else{for(R=m+7;d<R;){if(0===o)break t;o--,h+=i[s++]<<d,d+=8}h>>>=m,d-=m,y=0,c=11+(127&h),h>>>=7,d-=7}if(a.have+c>a.nlen+a.ndist){t.msg="invalid bit length repeat",a.mode=me;break}for(;c--;)a.lens[a.have++]=y}}if(a.mode===me)break;if(0===a.lens[256]){t.msg="invalid code -- missing end-of-block",a.mode=me;break}if(a.lenbits=9,E={bits:a.lenbits},x=ne(1,a.lens,0,a.nlen,a.lencode,0,a.work,E),a.lenbits=E.bits,x){t.msg="invalid literal/lengths set",a.mode=me;break}if(a.distbits=6,a.distcode=a.distdyn,E={bits:a.distbits},x=ne(2,a.lens,a.nlen,a.ndist,a.distcode,0,a.work,E),a.distbits=E.bits,x){t.msg="invalid distances set",a.mode=me;break}if(a.mode=16199,e===oe)break t;case 16199:a.mode=16200;case 16200:if(o>=6&&l>=258){t.next_out=r,t.avail_out=l,t.next_in=s,t.avail_in=o,a.hold=h,a.bits=d,$t(t,f),r=t.next_out,n=t.output,l=t.avail_out,s=t.next_in,i=t.input,o=t.avail_in,h=a.hold,d=a.bits,16191===a.mode&&(a.back=-1);break}for(a.back=0;z=a.lencode[h&(1<<a.lenbits)-1],m=z>>>24,b=z>>>16&255,g=65535&z,!(m<=d);){if(0===o)break t;o--,h+=i[s++]<<d,d+=8}if(b&&0==(240&b)){for(p=m,k=b,v=g;z=a.lencode[v+((h&(1<<p+k)-1)>>p)],m=z>>>24,b=z>>>16&255,g=65535&z,!(p+m<=d);){if(0===o)break t;o--,h+=i[s++]<<d,d+=8}h>>>=p,d-=p,a.back+=p}if(h>>>=m,d-=m,a.back+=m,a.length=g,0===b){a.mode=16205;break}if(32&b){a.back=-1,a.mode=16191;break}if(64&b){t.msg="invalid literal/length code",a.mode=me;break}a.extra=15&b,a.mode=16201;case 16201:if(a.extra){for(R=a.extra;d<R;){if(0===o)break t;o--,h+=i[s++]<<d,d+=8}a.length+=h&(1<<a.extra)-1,h>>>=a.extra,d-=a.extra,a.back+=a.extra}a.was=a.length,a.mode=16202;case 16202:for(;z=a.distcode[h&(1<<a.distbits)-1],m=z>>>24,b=z>>>16&255,g=65535&z,!(m<=d);){if(0===o)break t;o--,h+=i[s++]<<d,d+=8}if(0==(240&b)){for(p=m,k=b,v=g;z=a.distcode[v+((h&(1<<p+k)-1)>>p)],m=z>>>24,b=z>>>16&255,g=65535&z,!(p+m<=d);){if(0===o)break t;o--,h+=i[s++]<<d,d+=8}h>>>=p,d-=p,a.back+=p}if(h>>>=m,d-=m,a.back+=m,64&b){t.msg="invalid distance code",a.mode=me;break}a.offset=g,a.extra=15&b,a.mode=16203;case 16203:if(a.extra){for(R=a.extra;d<R;){if(0===o)break t;o--,h+=i[s++]<<d,d+=8}a.offset+=h&(1<<a.extra)-1,h>>>=a.extra,d-=a.extra,a.back+=a.extra}if(a.offset>a.dmax){t.msg="invalid distance too far back",a.mode=me;break}a.mode=16204;case 16204:if(0===l)break t;if(c=f-l,a.offset>c){if(c=a.offset-c,c>a.whave&&a.sane){t.msg="invalid distance too far back",a.mode=me;break}c>a.wnext?(c-=a.wnext,u=a.wsize-c):u=a.wnext-c,c>a.length&&(c=a.length),w=a.window}else w=n,u=r-a.offset,c=a.length;c>l&&(c=l),l-=c,a.length-=c;do{n[r++]=w[u++]}while(--c);0===a.length&&(a.mode=16200);break;case 16205:if(0===l)break t;n[r++]=a.length,l--,a.mode=16200;break;case 16206:if(a.wrap){for(;d<32;){if(0===o)break t;o--,h|=i[s++]<<d,d+=8}if(f-=l,t.total_out+=f,a.total+=f,4&a.wrap&&f&&(t.adler=a.check=a.flags?N(a.check,n,f,r-f):F(a.check,n,f,r-f)),f=l,4&a.wrap&&(a.flags?h:be(h))!==a.check){t.msg="incorrect data check",a.mode=me;break}h=0,d=0}a.mode=16207;case 16207:if(a.wrap&&a.flags){for(;d<32;){if(0===o)break t;o--,h+=i[s++]<<d,d+=8}if(4&a.wrap&&h!==(4294967295&a.total)){t.msg="incorrect length check",a.mode=me;break}h=0,d=0}a.mode=16208;case 16208:x=he;break t;case me:x=fe;break t;case 16210:return ce;default:return _e}return t.next_out=r,t.avail_out=l,t.next_in=s,t.avail_in=o,a.hold=h,a.bits=d,(a.wsize||f!==t.avail_out&&a.mode<me&&(a.mode<16206||e!==se))&&Ze(t,t.output,t.next_out,f-t.avail_out),_-=t.avail_in,f-=t.avail_out,t.total_in+=_,t.total_out+=f,a.total+=f,4&a.wrap&&f&&(t.adler=a.check=a.flags?N(a.check,n,f,t.next_out-f):F(a.check,n,f,t.next_out-f)),t.data_type=a.bits+(a.last?64:0)+(16191===a.mode?128:0)+(16199===a.mode||16194===a.mode?256:0),(0===_&&0===f||e===se)&&x===le&&(x=ue),x},inflateEnd:t=>{if(pe(t))return _e;let e=t.state;return e.window&&(e.window=null),t.state=null,le},inflateGetHeader:(t,e)=>{if(pe(t))return _e;const a=t.state;return 0==(2&a.wrap)?_e:(a.head=e,e.done=!1,le)},inflateSetDictionary:(t,e)=>{const a=e.length;let i,n,s;return pe(t)?_e:(i=t.state,0!==i.wrap&&16190!==i.mode?_e:16190===i.mode&&(n=1,n=F(n,e,a,0),n!==i.check)?fe:(s=Ze(t,e,a,a),s?(i.mode=16210,ce):(i.havedict=1,le)))},inflateInfo:"pako inflate (from Nodeca project)"};var Se=function(){this.text=0,this.time=0,this.xflags=0,this.os=0,this.extra=null,this.extra_len=0,this.name="",this.comment="",this.hcrc=0,this.done=!1};const De=Object.prototype.toString,{Z_NO_FLUSH:Te,Z_FINISH:Oe,Z_OK:Fe,Z_STREAM_END:Le,Z_NEED_DICT:Ne,Z_STREAM_ERROR:Ie,Z_DATA_ERROR:Be,Z_MEM_ERROR:Ce}=B;function He(t){this.options=Tt({chunkSize:65536,windowBits:15,to:""},t||{});const e=this.options;e.raw&&e.windowBits>=0&&e.windowBits<16&&(e.windowBits=-e.windowBits,0===e.windowBits&&(e.windowBits=-15)),!(e.windowBits>=0&&e.windowBits<16)||t&&t.windowBits||(e.windowBits+=32),e.windowBits>15&&e.windowBits<48&&0==(15&e.windowBits)&&(e.windowBits|=15),this.err=0,this.msg="",this.ended=!1,this.chunks=[],this.strm=new Ct,this.strm.avail_out=0;let a=Ue.inflateInit2(this.strm,e.windowBits);if(a!==Fe)throw new Error(I[a]);if(this.header=new Se,Ue.inflateGetHeader(this.strm,this.header),e.dictionary&&("string"==typeof e.dictionary?e.dictionary=Nt(e.dictionary):"[object ArrayBuffer]"===De.call(e.dictionary)&&(e.dictionary=new Uint8Array(e.dictionary)),e.raw&&(a=Ue.inflateSetDictionary(this.strm,e.dictionary),a!==Fe)))throw new Error(I[a])}He.prototype.push=function(t,e){const a=this.strm,i=this.options.chunkSize,n=this.options.dictionary;let s,r,o;if(this.ended)return!1;for(r=e===~~e?e:!0===e?Oe:Te,"[object ArrayBuffer]"===De.call(t)?a.input=new Uint8Array(t):a.input=t,a.next_in=0,a.avail_in=a.input.length;;){for(0===a.avail_out&&(a.output=new Uint8Array(i),a.next_out=0,a.avail_out=i),s=Ue.inflate(a,r),s===Ne&&n&&(s=Ue.inflateSetDictionary(a,n),s===Fe?s=Ue.inflate(a,r):s===Be&&(s=Ne));a.avail_in>0&&s===Le&&a.state.wrap>0&&0!==t[a.next_in];)Ue.inflateReset(a),s=Ue.inflate(a,r);switch(s){case Ie:case Be:case Ne:case Ce:return this.onEnd(s),this.ended=!0,!1}if(o=a.avail_out,a.next_out&&(0===a.avail_out||s===Le))if("string"===this.options.to){let t=Bt(a.output,a.next_out),e=a.next_out-t,n=It(a.output,t);a.next_out=e,a.avail_out=i-e,e&&a.output.set(a.output.subarray(t,t+e),0),this.onData(n)}else this.onData(a.output.length===a.next_out?a.output:a.output.subarray(0,a.next_out));if(s!==Fe||0!==o){if(s===Le)return s=Ue.inflateEnd(this.strm),this.onEnd(s),this.ended=!0,!0;if(0===a.avail_in)break}}return!0},He.prototype.onData=function(t){this.chunks.push(t)},He.prototype.onEnd=function(t){t===Fe&&("string"===this.options.to?this.result=this.chunks.join(""):this.result=Ot(this.chunks)),this.chunks=[],this.err=t,this.msg=this.strm.msg};const{Deflate:Me,deflate:je,deflateRaw:Ke,gzip:Pe}=Vt;var Ye=Me,Ge=je,Xe=B;const We=new class{constructor(){this._init()}clear(){this._init()}addEvent(t){if(!t)throw new Error("Adding invalid event");const e=this._hasEvents?",":"";this.deflate.push(e+t,Xe.Z_SYNC_FLUSH),this._hasEvents=!0}finish(){if(this.deflate.push("]",Xe.Z_FINISH),this.deflate.err)throw this.deflate.err;const t=this.deflate.result;return this._init(),t}_init(){this._hasEvents=!1,this.deflate=new Ye,this.deflate.push("[",Xe.Z_NO_FLUSH)}},qe={clear:()=>{We.clear()},addEvent:t=>We.addEvent(t),finish:()=>We.finish(),compress:t=>function(t){return Ge(t)}(t)};addEventListener("message",(function(t){const e=t.data.method,a=t.data.id,i=t.data.arg;if(e in qe&&"function"==typeof qe[e])try{const t=qe[e](i);postMessage({id:a,method:e,success:!0,response:t})}catch(t){postMessage({id:a,method:e,success:!1,response:t.message}),console.error(t)}})),postMessage({id:void 0,method:"init",success:!0,response:void 0});`;
4005  
4006  function e(){const e=new Blob([r]);return URL.createObjectURL(e)}
4007  
4008  /**
4009   * Converts a timestamp to ms, if it was in s, or keeps it as ms.
4010   */
4011  function timestampToMs(timestamp) {
4012    const isMs = timestamp > 9999999999;
4013    return isMs ? timestamp : timestamp * 1000;
4014  }
4015  
4016  /** This error indicates that the event buffer size exceeded the limit.. */
4017  class EventBufferSizeExceededError extends Error {
4018     constructor() {
4019      super(`Event buffer exceeded maximum size of ${REPLAY_MAX_EVENT_BUFFER_SIZE}.`);
4020    }
4021  }
4022  
4023  /**
4024   * A basic event buffer that does not do any compression.
4025   * Used as fallback if the compression worker cannot be loaded or is disabled.
4026   */
4027  class EventBufferArray  {
4028    /** All the events that are buffered to be sent. */
4029  
4030     __init() {this._totalSize = 0;}
4031  
4032     constructor() {EventBufferArray.prototype.__init.call(this);
4033      this.events = [];
4034    }
4035  
4036    /** @inheritdoc */
4037     get hasEvents() {
4038      return this.events.length > 0;
4039    }
4040  
4041    /** @inheritdoc */
4042     get type() {
4043      return 'sync';
4044    }
4045  
4046    /** @inheritdoc */
4047     destroy() {
4048      this.events = [];
4049    }
4050  
4051    /** @inheritdoc */
4052     async addEvent(event) {
4053      const eventSize = JSON.stringify(event).length;
4054      this._totalSize += eventSize;
4055      if (this._totalSize > REPLAY_MAX_EVENT_BUFFER_SIZE) {
4056        throw new EventBufferSizeExceededError();
4057      }
4058  
4059      this.events.push(event);
4060    }
4061  
4062    /** @inheritdoc */
4063     finish() {
4064      return new Promise(resolve => {
4065        // Make a copy of the events array reference and immediately clear the
4066        // events member so that we do not lose new events while uploading
4067        // attachment.
4068        const eventsRet = this.events;
4069        this.clear();
4070        resolve(JSON.stringify(eventsRet));
4071      });
4072    }
4073  
4074    /** @inheritdoc */
4075     clear() {
4076      this.events = [];
4077      this._totalSize = 0;
4078    }
4079  
4080    /** @inheritdoc */
4081     getEarliestTimestamp() {
4082      const timestamp = this.events.map(event => event.timestamp).sort()[0];
4083  
4084      if (!timestamp) {
4085        return null;
4086      }
4087  
4088      return timestampToMs(timestamp);
4089    }
4090  }
4091  
4092  /**
4093   * Event buffer that uses a web worker to compress events.
4094   * Exported only for testing.
4095   */
4096  class WorkerHandler {
4097  
4098     constructor(worker) {
4099      this._worker = worker;
4100      this._id = 0;
4101    }
4102  
4103    /**
4104     * Ensure the worker is ready (or not).
4105     * This will either resolve when the worker is ready, or reject if an error occured.
4106     */
4107     ensureReady() {
4108      // Ensure we only check once
4109      if (this._ensureReadyPromise) {
4110        return this._ensureReadyPromise;
4111      }
4112  
4113      this._ensureReadyPromise = new Promise((resolve, reject) => {
4114        this._worker.addEventListener(
4115          'message',
4116          ({ data }) => {
4117            if ((data ).success) {
4118              resolve();
4119            } else {
4120              reject();
4121            }
4122          },
4123          { once: true },
4124        );
4125  
4126        this._worker.addEventListener(
4127          'error',
4128          error => {
4129            reject(error);
4130          },
4131          { once: true },
4132        );
4133      });
4134  
4135      return this._ensureReadyPromise;
4136    }
4137  
4138    /**
4139     * Destroy the worker.
4140     */
4141     destroy() {
4142      (typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && logger.log('[Replay] Destroying compression worker');
4143      this._worker.terminate();
4144    }
4145  
4146    /**
4147     * Post message to worker and wait for response before resolving promise.
4148     */
4149     postMessage(method, arg) {
4150      const id = this._getAndIncrementId();
4151  
4152      return new Promise((resolve, reject) => {
4153        const listener = ({ data }) => {
4154          const response = data ;
4155          if (response.method !== method) {
4156            return;
4157          }
4158  
4159          // There can be multiple listeners for a single method, the id ensures
4160          // that the response matches the caller.
4161          if (response.id !== id) {
4162            return;
4163          }
4164  
4165          // At this point, we'll always want to remove listener regardless of result status
4166          this._worker.removeEventListener('message', listener);
4167  
4168          if (!response.success) {
4169            // TODO: Do some error handling, not sure what
4170            (typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && logger.error('[Replay]', response.response);
4171  
4172            reject(new Error('Error in compression worker'));
4173            return;
4174          }
4175  
4176          resolve(response.response );
4177        };
4178  
4179        // Note: we can't use `once` option because it's possible it needs to
4180        // listen to multiple messages
4181        this._worker.addEventListener('message', listener);
4182        this._worker.postMessage({ id, method, arg });
4183      });
4184    }
4185  
4186    /** Get the current ID and increment it for the next call. */
4187     _getAndIncrementId() {
4188      return this._id++;
4189    }
4190  }
4191  
4192  /**
4193   * Event buffer that uses a web worker to compress events.
4194   * Exported only for testing.
4195   */
4196  class EventBufferCompressionWorker  {
4197  
4198     __init() {this._totalSize = 0;}
4199  
4200     constructor(worker) {EventBufferCompressionWorker.prototype.__init.call(this);
4201      this._worker = new WorkerHandler(worker);
4202      this._earliestTimestamp = null;
4203    }
4204  
4205    /** @inheritdoc */
4206     get hasEvents() {
4207      return !!this._earliestTimestamp;
4208    }
4209  
4210    /** @inheritdoc */
4211     get type() {
4212      return 'worker';
4213    }
4214  
4215    /**
4216     * Ensure the worker is ready (or not).
4217     * This will either resolve when the worker is ready, or reject if an error occured.
4218     */
4219     ensureReady() {
4220      return this._worker.ensureReady();
4221    }
4222  
4223    /**
4224     * Destroy the event buffer.
4225     */
4226     destroy() {
4227      this._worker.destroy();
4228    }
4229  
4230    /**
4231     * Add an event to the event buffer.
4232     *
4233     * Returns true if event was successfuly received and processed by worker.
4234     */
4235     addEvent(event) {
4236      const timestamp = timestampToMs(event.timestamp);
4237      if (!this._earliestTimestamp || timestamp < this._earliestTimestamp) {
4238        this._earliestTimestamp = timestamp;
4239      }
4240  
4241      const data = JSON.stringify(event);
4242      this._totalSize += data.length;
4243  
4244      if (this._totalSize > REPLAY_MAX_EVENT_BUFFER_SIZE) {
4245        return Promise.reject(new EventBufferSizeExceededError());
4246      }
4247  
4248      return this._sendEventToWorker(data);
4249    }
4250  
4251    /**
4252     * Finish the event buffer and return the compressed data.
4253     */
4254     finish() {
4255      return this._finishRequest();
4256    }
4257  
4258    /** @inheritdoc */
4259     clear() {
4260      this._earliestTimestamp = null;
4261      this._totalSize = 0;
4262      // We do not wait on this, as we assume the order of messages is consistent for the worker
4263      void this._worker.postMessage('clear');
4264    }
4265  
4266    /** @inheritdoc */
4267     getEarliestTimestamp() {
4268      return this._earliestTimestamp;
4269    }
4270  
4271    /**
4272     * Send the event to the worker.
4273     */
4274     _sendEventToWorker(data) {
4275      return this._worker.postMessage('addEvent', data);
4276    }
4277  
4278    /**
4279     * Finish the request and return the compressed data from the worker.
4280     */
4281     async _finishRequest() {
4282      const response = await this._worker.postMessage('finish');
4283  
4284      this._earliestTimestamp = null;
4285      this._totalSize = 0;
4286  
4287      return response;
4288    }
4289  }
4290  
4291  /**
4292   * This proxy will try to use the compression worker, and fall back to use the simple buffer if an error occurs there.
4293   * This can happen e.g. if the worker cannot be loaded.
4294   * Exported only for testing.
4295   */
4296  class EventBufferProxy  {
4297  
4298     constructor(worker) {
4299      this._fallback = new EventBufferArray();
4300      this._compression = new EventBufferCompressionWorker(worker);
4301      this._used = this._fallback;
4302  
4303      this._ensureWorkerIsLoadedPromise = this._ensureWorkerIsLoaded();
4304    }
4305  
4306    /** @inheritdoc */
4307     get type() {
4308      return this._used.type;
4309    }
4310  
4311    /** @inheritDoc */
4312     get hasEvents() {
4313      return this._used.hasEvents;
4314    }
4315  
4316    /** @inheritDoc */
4317     destroy() {
4318      this._fallback.destroy();
4319      this._compression.destroy();
4320    }
4321  
4322    /** @inheritdoc */
4323     clear() {
4324      return this._used.clear();
4325    }
4326  
4327    /** @inheritdoc */
4328     getEarliestTimestamp() {
4329      return this._used.getEarliestTimestamp();
4330    }
4331  
4332    /**
4333     * Add an event to the event buffer.
4334     *
4335     * Returns true if event was successfully added.
4336     */
4337     addEvent(event) {
4338      return this._used.addEvent(event);
4339    }
4340  
4341    /** @inheritDoc */
4342     async finish() {
4343      // Ensure the worker is loaded, so the sent event is compressed
4344      await this.ensureWorkerIsLoaded();
4345  
4346      return this._used.finish();
4347    }
4348  
4349    /** Ensure the worker has loaded. */
4350     ensureWorkerIsLoaded() {
4351      return this._ensureWorkerIsLoadedPromise;
4352    }
4353  
4354    /** Actually check if the worker has been loaded. */
4355     async _ensureWorkerIsLoaded() {
4356      try {
4357        await this._compression.ensureReady();
4358      } catch (error) {
4359        // If the worker fails to load, we fall back to the simple buffer.
4360        // Nothing more to do from our side here
4361        (typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && logger.log('[Replay] Failed to load the compression worker, falling back to simple buffer');
4362        return;
4363      }
4364  
4365      // Now we need to switch over the array buffer to the compression worker
4366      await this._switchToCompressionWorker();
4367    }
4368  
4369    /** Switch the used buffer to the compression worker. */
4370     async _switchToCompressionWorker() {
4371      const { events } = this._fallback;
4372  
4373      const addEventPromises = [];
4374      for (const event of events) {
4375        addEventPromises.push(this._compression.addEvent(event));
4376      }
4377  
4378      // We switch over to the new buffer immediately - any further events will be added
4379      // after the previously buffered ones
4380      this._used = this._compression;
4381  
4382      // Wait for original events to be re-added before resolving
4383      try {
4384        await Promise.all(addEventPromises);
4385      } catch (error) {
4386        (typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && logger.warn('[Replay] Failed to add events when switching buffers.', error);
4387      }
4388    }
4389  }
4390  
4391  /**
4392   * Create an event buffer for replays.
4393   */
4394  function createEventBuffer({ useCompression }) {
4395    // eslint-disable-next-line no-restricted-globals
4396    if (useCompression && window.Worker) {
4397      try {
4398        const workerUrl = e();
4399  
4400        (typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && logger.log('[Replay] Using compression worker');
4401        const worker = new Worker(workerUrl);
4402        return new EventBufferProxy(worker);
4403      } catch (error) {
4404        (typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && logger.log('[Replay] Failed to create compression worker');
4405        // Fall back to use simple event buffer array
4406      }
4407    }
4408  
4409    (typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && logger.log('[Replay] Using simple buffer');
4410    return new EventBufferArray();
4411  }
4412  
4413  /** If sessionStorage is available. */
4414  function hasSessionStorage() {
4415    return 'sessionStorage' in WINDOW && !!WINDOW.sessionStorage;
4416  }
4417  
4418  /**
4419   * Removes the session from Session Storage and unsets session in replay instance
4420   */
4421  function clearSession(replay) {
4422    deleteSession();
4423    replay.session = undefined;
4424  }
4425  
4426  /**
4427   * Deletes a session from storage
4428   */
4429  function deleteSession() {
4430    if (!hasSessionStorage()) {
4431      return;
4432    }
4433  
4434    try {
4435      WINDOW.sessionStorage.removeItem(REPLAY_SESSION_KEY);
4436    } catch (e) {
4437      // Ignore potential SecurityError exceptions
4438    }
4439  }
4440  
4441  /**
4442   * Given an initial timestamp and an expiry duration, checks to see if current
4443   * time should be considered as expired.
4444   */
4445  function isExpired(
4446    initialTime,
4447    expiry,
4448    targetTime = +new Date(),
4449  ) {
4450    // Always expired if < 0
4451    if (initialTime === null || expiry === undefined || expiry < 0) {
4452      return true;
4453    }
4454  
4455    // Never expires if == 0
4456    if (expiry === 0) {
4457      return false;
4458    }
4459  
4460    return initialTime + expiry <= targetTime;
4461  }
4462  
4463  /**
4464   * Checks to see if session is expired
4465   */
4466  function isSessionExpired(session, timeouts, targetTime = +new Date()) {
4467    return (
4468      // First, check that maximum session length has not been exceeded
4469      isExpired(session.started, timeouts.maxSessionLife, targetTime) ||
4470      // check that the idle timeout has not been exceeded (i.e. user has
4471      // performed an action within the last `sessionIdleExpire` ms)
4472      isExpired(session.lastActivity, timeouts.sessionIdleExpire, targetTime)
4473    );
4474  }
4475  
4476  /**
4477   * Given a sample rate, returns true if replay should be sampled.
4478   *
4479   * 1.0 = 100% sampling
4480   * 0.0 = 0% sampling
4481   */
4482  function isSampled(sampleRate) {
4483    if (sampleRate === undefined) {
4484      return false;
4485    }
4486  
4487    // Math.random() returns a number in range of 0 to 1 (inclusive of 0, but not 1)
4488    return Math.random() < sampleRate;
4489  }
4490  
4491  /**
4492   * Save a session to session storage.
4493   */
4494  function saveSession(session) {
4495    if (!hasSessionStorage()) {
4496      return;
4497    }
4498  
4499    try {
4500      WINDOW.sessionStorage.setItem(REPLAY_SESSION_KEY, JSON.stringify(session));
4501    } catch (e) {
4502      // Ignore potential SecurityError exceptions
4503    }
4504  }
4505  
4506  /**
4507   * Get a session with defaults & applied sampling.
4508   */
4509  function makeSession(session) {
4510    const now = Date.now();
4511    const id = session.id || uuid4();
4512    // Note that this means we cannot set a started/lastActivity of `0`, but this should not be relevant outside of tests.
4513    const started = session.started || now;
4514    const lastActivity = session.lastActivity || now;
4515    const segmentId = session.segmentId || 0;
4516    const sampled = session.sampled;
4517  
4518    return {
4519      id,
4520      started,
4521      lastActivity,
4522      segmentId,
4523      sampled,
4524      shouldRefresh: true,
4525    };
4526  }
4527  
4528  /**
4529   * Get the sampled status for a session based on sample rates & current sampled status.
4530   */
4531  function getSessionSampleType(sessionSampleRate, allowBuffering) {
4532    return isSampled(sessionSampleRate) ? 'session' : allowBuffering ? 'buffer' : false;
4533  }
4534  
4535  /**
4536   * Create a new session, which in its current implementation is a Sentry event
4537   * that all replays will be saved to as attachments. Currently, we only expect
4538   * one of these Sentry events per "replay session".
4539   */
4540  function createSession({ sessionSampleRate, allowBuffering, stickySession = false }) {
4541    const sampled = getSessionSampleType(sessionSampleRate, allowBuffering);
4542    const session = makeSession({
4543      sampled,
4544    });
4545  
4546    (typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && logger.log(`[Replay] Creating new session: ${session.id}`);
4547  
4548    if (stickySession) {
4549      saveSession(session);
4550    }
4551  
4552    return session;
4553  }
4554  
4555  /**
4556   * Fetches a session from storage
4557   */
4558  function fetchSession() {
4559    if (!hasSessionStorage()) {
4560      return null;
4561    }
4562  
4563    try {
4564      // This can throw if cookies are disabled
4565      const sessionStringFromStorage = WINDOW.sessionStorage.getItem(REPLAY_SESSION_KEY);
4566  
4567      if (!sessionStringFromStorage) {
4568        return null;
4569      }
4570  
4571      const sessionObj = JSON.parse(sessionStringFromStorage) ;
4572  
4573      return makeSession(sessionObj);
4574    } catch (e) {
4575      return null;
4576    }
4577  }
4578  
4579  /**
4580   * Get or create a session
4581   */
4582  function getSession({
4583    timeouts,
4584    currentSession,
4585    stickySession,
4586    sessionSampleRate,
4587    allowBuffering,
4588  }) {
4589    // If session exists and is passed, use it instead of always hitting session storage
4590    const session = currentSession || (stickySession && fetchSession());
4591  
4592    if (session) {
4593      // If there is a session, check if it is valid (e.g. "last activity" time
4594      // should be within the "session idle time", and "session started" time is
4595      // within "max session time").
4596      const isExpired = isSessionExpired(session, timeouts);
4597  
4598      if (!isExpired || (allowBuffering && session.shouldRefresh)) {
4599        return { type: 'saved', session };
4600      } else if (!session.shouldRefresh) {
4601        // This is the case if we have an error session that is completed
4602        // (=triggered an error). Session will continue as session-based replay,
4603        // and when this session is expired, it will not be renewed until user
4604        // reloads.
4605        const discardedSession = makeSession({ sampled: false });
4606        return { type: 'new', session: discardedSession };
4607      } else {
4608        (typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && logger.log('[Replay] Session has expired');
4609      }
4610      // Otherwise continue to create a new session
4611    }
4612  
4613    const newSession = createSession({
4614      stickySession,
4615      sessionSampleRate,
4616      allowBuffering,
4617    });
4618  
4619    return { type: 'new', session: newSession };
4620  }
4621  
4622  function isCustomEvent(event) {
4623    return event.type === EventType.Custom;
4624  }
4625  
4626  /**
4627   * Add an event to the event buffer.
4628   * `isCheckout` is true if this is either the very first event, or an event triggered by `checkoutEveryNms`.
4629   */
4630  async function addEvent(
4631    replay,
4632    event,
4633    isCheckout,
4634  ) {
4635    if (!replay.eventBuffer) {
4636      // This implies that `_isEnabled` is false
4637      return null;
4638    }
4639  
4640    if (replay.isPaused()) {
4641      // Do not add to event buffer when recording is paused
4642      return null;
4643    }
4644  
4645    const timestampInMs = timestampToMs(event.timestamp);
4646  
4647    // Throw out events that happen more than 5 minutes ago. This can happen if
4648    // page has been left open and idle for a long period of time and user
4649    // comes back to trigger a new session. The performance entries rely on
4650    // `performance.timeOrigin`, which is when the page first opened.
4651    if (timestampInMs + replay.timeouts.sessionIdlePause < Date.now()) {
4652      return null;
4653    }
4654  
4655    try {
4656      if (isCheckout) {
4657        replay.eventBuffer.clear();
4658      }
4659  
4660      const replayOptions = replay.getOptions();
4661  
4662      const eventAfterPossibleCallback =
4663        typeof replayOptions.beforeAddRecordingEvent === 'function' && isCustomEvent(event)
4664          ? replayOptions.beforeAddRecordingEvent(event)
4665          : event;
4666  
4667      if (!eventAfterPossibleCallback) {
4668        return;
4669      }
4670  
4671      return await replay.eventBuffer.addEvent(eventAfterPossibleCallback);
4672    } catch (error) {
4673      const reason = error && error instanceof EventBufferSizeExceededError ? 'addEventSizeExceeded' : 'addEvent';
4674  
4675      (typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && logger.error(error);
4676      await replay.stop(reason);
4677  
4678      const client = getCurrentHub().getClient();
4679  
4680      if (client) {
4681        client.recordDroppedEvent('internal_sdk_error', 'replay');
4682      }
4683    }
4684  }
4685  
4686  /** If the event is an error event */
4687  function isErrorEvent(event) {
4688    return !event.type;
4689  }
4690  
4691  /** If the event is a transaction event */
4692  function isTransactionEvent(event) {
4693    return event.type === 'transaction';
4694  }
4695  
4696  /** If the event is an replay event */
4697  function isReplayEvent(event) {
4698    return event.type === 'replay_event';
4699  }
4700  
4701  /**
4702   * Returns a listener to be added to `client.on('afterSendErrorEvent, listener)`.
4703   */
4704  function handleAfterSendEvent(replay) {
4705    // Custom transports may still be returning `Promise<void>`, which means we cannot expect the status code to be available there
4706    // TODO (v8): remove this check as it will no longer be necessary
4707    const enforceStatusCode = isBaseTransportSend();
4708  
4709    return (event, sendResponse) => {
4710      if (!isErrorEvent(event) && !isTransactionEvent(event)) {
4711        return;
4712      }
4713  
4714      const statusCode = sendResponse && sendResponse.statusCode;
4715  
4716      // We only want to do stuff on successful error sending, otherwise you get error replays without errors attached
4717      // If not using the base transport, we allow `undefined` response (as a custom transport may not implement this correctly yet)
4718      // If we do use the base transport, we skip if we encountered an non-OK status code
4719      if (enforceStatusCode && (!statusCode || statusCode < 200 || statusCode >= 300)) {
4720        return;
4721      }
4722  
4723      // Collect traceIds in _context regardless of `recordingMode`
4724      // In error mode, _context gets cleared on every checkout
4725      if (isTransactionEvent(event) && event.contexts && event.contexts.trace && event.contexts.trace.trace_id) {
4726        replay.getContext().traceIds.add(event.contexts.trace.trace_id );
4727        return;
4728      }
4729  
4730      // Everything below is just for error events
4731      if (!isErrorEvent(event)) {
4732        return;
4733      }
4734  
4735      // Add error to list of errorIds of replay. This is ok to do even if not
4736      // sampled because context will get reset at next checkout.
4737      // XXX: There is also a race condition where it's possible to capture an
4738      // error to Sentry before Replay SDK has loaded, but response returns after
4739      // it was loaded, and this gets called.
4740      if (event.event_id) {
4741        replay.getContext().errorIds.add(event.event_id);
4742      }
4743  
4744      // If error event is tagged with replay id it means it was sampled (when in buffer mode)
4745      // Need to be very careful that this does not cause an infinite loop
4746      if (replay.recordingMode === 'buffer' && event.tags && event.tags.replayId) {
4747        setTimeout(() => {
4748          // Capture current event buffer as new replay
4749          void replay.sendBufferedReplayOrFlush();
4750        });
4751      }
4752    };
4753  }
4754  
4755  function isBaseTransportSend() {
4756    const client = getCurrentHub().getClient();
4757    if (!client) {
4758      return false;
4759    }
4760  
4761    const transport = client.getTransport();
4762    if (!transport) {
4763      return false;
4764    }
4765  
4766    return (
4767      (transport.send ).__sentry__baseTransport__ || false
4768    );
4769  }
4770  
4771  /**
4772   * Returns true if we think the given event is an error originating inside of rrweb.
4773   */
4774  function isRrwebError(event, hint) {
4775    if (event.type || !event.exception || !event.exception.values || !event.exception.values.length) {
4776      return false;
4777    }
4778  
4779    // @ts-ignore this may be set by rrweb when it finds errors
4780    if (hint.originalException && hint.originalException.__rrweb__) {
4781      return true;
4782    }
4783  
4784    // Check if any exception originates from rrweb
4785    return event.exception.values.some(exception => {
4786      if (!exception.stacktrace || !exception.stacktrace.frames || !exception.stacktrace.frames.length) {
4787        return false;
4788      }
4789  
4790      return exception.stacktrace.frames.some(frame => frame.filename && frame.filename.includes('/rrweb/src/'));
4791    });
4792  }
4793  
4794  /**
4795   * Determine if event should be sampled (only applies in buffer mode).
4796   * When an event is captured by `hanldleGlobalEvent`, when in buffer mode
4797   * we determine if we want to sample the error or not.
4798   */
4799  function shouldSampleForBufferEvent(replay, event) {
4800    if (replay.recordingMode !== 'buffer') {
4801      return false;
4802    }
4803  
4804    // ignore this error because otherwise we could loop indefinitely with
4805    // trying to capture replay and failing
4806    if (event.message === UNABLE_TO_SEND_REPLAY) {
4807      return false;
4808    }
4809  
4810    // Require the event to be an error event & to have an exception
4811    if (!event.exception || event.type) {
4812      return false;
4813    }
4814  
4815    return isSampled(replay.getOptions().errorSampleRate);
4816  }
4817  
4818  /**
4819   * Returns a listener to be added to `addGlobalEventProcessor(listener)`.
4820   */
4821  function handleGlobalEventListener(
4822    replay,
4823    includeAfterSendEventHandling = false,
4824  ) {
4825    const afterSendHandler = includeAfterSendEventHandling ? handleAfterSendEvent(replay) : undefined;
4826  
4827    return (event, hint) => {
4828      if (isReplayEvent(event)) {
4829        // Replays have separate set of breadcrumbs, do not include breadcrumbs
4830        // from core SDK
4831        delete event.breadcrumbs;
4832        return event;
4833      }
4834  
4835      // We only want to handle errors & transactions, nothing else
4836      if (!isErrorEvent(event) && !isTransactionEvent(event)) {
4837        return event;
4838      }
4839  
4840      // Unless `captureExceptions` is enabled, we want to ignore errors coming from rrweb
4841      // As there can be a bunch of stuff going wrong in internals there, that we don't want to bubble up to users
4842      if (isRrwebError(event, hint) && !replay.getOptions()._experiments.captureExceptions) {
4843        (typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && logger.log('[Replay] Ignoring error from rrweb internals', event);
4844        return null;
4845      }
4846  
4847      // When in buffer mode, we decide to sample here.
4848      // Later, in `handleAfterSendEvent`, if the replayId is set, we know that we sampled
4849      // And convert the buffer session to a full session
4850      const isErrorEventSampled = shouldSampleForBufferEvent(replay, event);
4851  
4852      // Tag errors if it has been sampled in buffer mode, or if it is session mode
4853      // Only tag transactions if in session mode
4854      const shouldTagReplayId = isErrorEventSampled || replay.recordingMode === 'session';
4855  
4856      if (shouldTagReplayId) {
4857        event.tags = { ...event.tags, replayId: replay.getSessionId() };
4858      }
4859  
4860      // In cases where a custom client is used that does not support the new hooks (yet),
4861      // we manually call this hook method here
4862      if (afterSendHandler) {
4863        // Pretend the error had a 200 response so we always capture it
4864        afterSendHandler(event, { statusCode: 200 });
4865      }
4866  
4867      return event;
4868    };
4869  }
4870  
4871  /**
4872   * Create a "span" for each performance entry.
4873   */
4874  function createPerformanceSpans(
4875    replay,
4876    entries,
4877  ) {
4878    return entries.map(({ type, start, end, name, data }) => {
4879      const response = replay.throttledAddEvent({
4880        type: EventType.Custom,
4881        timestamp: start,
4882        data: {
4883          tag: 'performanceSpan',
4884          payload: {
4885            op: type,
4886            description: name,
4887            startTimestamp: start,
4888            endTimestamp: end,
4889            data,
4890          },
4891        },
4892      });
4893  
4894      // If response is a string, it means its either THROTTLED or SKIPPED
4895      return typeof response === 'string' ? Promise.resolve(null) : response;
4896    });
4897  }
4898  
4899  function handleHistory(handlerData) {
4900    const { from, to } = handlerData;
4901  
4902    const now = Date.now() / 1000;
4903  
4904    return {
4905      type: 'navigation.push',
4906      start: now,
4907      end: now,
4908      name: to,
4909      data: {
4910        previous: from,
4911      },
4912    };
4913  }
4914  
4915  /**
4916   * Returns a listener to be added to `addInstrumentationHandler('history', listener)`.
4917   */
4918  function handleHistorySpanListener(replay) {
4919    return (handlerData) => {
4920      if (!replay.isEnabled()) {
4921        return;
4922      }
4923  
4924      const result = handleHistory(handlerData);
4925  
4926      if (result === null) {
4927        return;
4928      }
4929  
4930      // Need to collect visited URLs
4931      replay.getContext().urls.push(result.name);
4932      replay.triggerUserActivity();
4933  
4934      replay.addUpdate(() => {
4935        createPerformanceSpans(replay, [result]);
4936        // Returning false to flush
4937        return false;
4938      });
4939    };
4940  }
4941  
4942  /**
4943   * Check whether a given request URL should be filtered out. This is so we
4944   * don't log Sentry ingest requests.
4945   */
4946  function shouldFilterRequest(replay, url) {
4947    // If we enabled the `traceInternals` experiment, we want to trace everything
4948    if ((typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && replay.getOptions()._experiments.traceInternals) {
4949      return false;
4950    }
4951  
4952    return _isSentryRequest(url);
4953  }
4954  
4955  /**
4956   * Checks wether a given URL belongs to the configured Sentry DSN.
4957   */
4958  function _isSentryRequest(url) {
4959    const client = getCurrentHub().getClient();
4960    const dsn = client && client.getDsn();
4961    return dsn ? url.includes(dsn.host) : false;
4962  }
4963  
4964  /** Add a performance entry breadcrumb */
4965  function addNetworkBreadcrumb(
4966    replay,
4967    result,
4968  ) {
4969    if (!replay.isEnabled()) {
4970      return;
4971    }
4972  
4973    if (result === null) {
4974      return;
4975    }
4976  
4977    if (shouldFilterRequest(replay, result.name)) {
4978      return;
4979    }
4980  
4981    replay.addUpdate(() => {
4982      createPerformanceSpans(replay, [result]);
4983      // Returning true will cause `addUpdate` to not flush
4984      // We do not want network requests to cause a flush. This will prevent
4985      // recurring/polling requests from keeping the replay session alive.
4986      return true;
4987    });
4988  }
4989  
4990  /** only exported for tests */
4991  function handleFetch(handlerData) {
4992    const { startTimestamp, endTimestamp, fetchData, response } = handlerData;
4993  
4994    if (!endTimestamp) {
4995      return null;
4996    }
4997  
4998    // This is only used as a fallback, so we know the body sizes are never set here
4999    const { method, url } = fetchData;
5000  
5001    return {
5002      type: 'resource.fetch',
5003      start: startTimestamp / 1000,
5004      end: endTimestamp / 1000,
5005      name: url,
5006      data: {
5007        method,
5008        statusCode: response ? (response ).status : undefined,
5009      },
5010    };
5011  }
5012  
5013  /**
5014   * Returns a listener to be added to `addInstrumentationHandler('fetch', listener)`.
5015   */
5016  function handleFetchSpanListener(replay) {
5017    return (handlerData) => {
5018      if (!replay.isEnabled()) {
5019        return;
5020      }
5021  
5022      const result = handleFetch(handlerData);
5023  
5024      addNetworkBreadcrumb(replay, result);
5025    };
5026  }
5027  
5028  /** only exported for tests */
5029  function handleXhr(handlerData) {
5030    const { startTimestamp, endTimestamp, xhr } = handlerData;
5031  
5032    const sentryXhrData = xhr[SENTRY_XHR_DATA_KEY];
5033  
5034    if (!startTimestamp || !endTimestamp || !sentryXhrData) {
5035      return null;
5036    }
5037  
5038    // This is only used as a fallback, so we know the body sizes are never set here
5039    const { method, url, status_code: statusCode } = sentryXhrData;
5040  
5041    if (url === undefined) {
5042      return null;
5043    }
5044  
5045    return {
5046      type: 'resource.xhr',
5047      name: url,
5048      start: startTimestamp / 1000,
5049      end: endTimestamp / 1000,
5050      data: {
5051        method,
5052        statusCode,
5053      },
5054    };
5055  }
5056  
5057  /**
5058   * Returns a listener to be added to `addInstrumentationHandler('xhr', listener)`.
5059   */
5060  function handleXhrSpanListener(replay) {
5061    return (handlerData) => {
5062      if (!replay.isEnabled()) {
5063        return;
5064      }
5065  
5066      const result = handleXhr(handlerData);
5067  
5068      addNetworkBreadcrumb(replay, result);
5069    };
5070  }
5071  
5072  const OBJ = 10;
5073  const OBJ_KEY = 11;
5074  const OBJ_KEY_STR = 12;
5075  const OBJ_VAL = 13;
5076  const OBJ_VAL_STR = 14;
5077  const OBJ_VAL_COMPLETED = 15;
5078  
5079  const ARR = 20;
5080  const ARR_VAL = 21;
5081  const ARR_VAL_STR = 22;
5082  const ARR_VAL_COMPLETED = 23;
5083  
5084  const ALLOWED_PRIMITIVES = ['true', 'false', 'null'];
5085  
5086  /**
5087   * Complete an incomplete JSON string.
5088   * This will ensure that the last element always has a `"~~"` to indicate it was truncated.
5089   * For example, `[1,2,` will be completed to `[1,2,"~~"]`
5090   * and `{"aa":"b` will be completed to `{"aa":"b~~"}`
5091   */
5092  function completeJson(incompleteJson, stack) {
5093    if (!stack.length) {
5094      return incompleteJson;
5095    }
5096  
5097    let json = incompleteJson;
5098  
5099    // Most checks are only needed for the last step in the stack
5100    const lastPos = stack.length - 1;
5101    const lastStep = stack[lastPos];
5102  
5103    json = _fixLastStep(json, lastStep);
5104  
5105    // Complete remaining steps - just add closing brackets
5106    for (let i = lastPos; i >= 0; i--) {
5107      const step = stack[i];
5108  
5109      switch (step) {
5110        case OBJ:
5111          json = `${json}}`;
5112          break;
5113        case ARR:
5114          json = `${json}]`;
5115          break;
5116      }
5117    }
5118  
5119    return json;
5120  }
5121  
5122  function _fixLastStep(json, lastStep) {
5123    switch (lastStep) {
5124      // Object cases
5125      case OBJ:
5126        return `${json}"~~":"~~"`;
5127      case OBJ_KEY:
5128        return `${json}:"~~"`;
5129      case OBJ_KEY_STR:
5130        return `${json}~~":"~~"`;
5131      case OBJ_VAL:
5132        return _maybeFixIncompleteObjValue(json);
5133      case OBJ_VAL_STR:
5134        return `${json}~~"`;
5135      case OBJ_VAL_COMPLETED:
5136        return `${json},"~~":"~~"`;
5137  
5138      // Array cases
5139      case ARR:
5140        return `${json}"~~"`;
5141      case ARR_VAL:
5142        return _maybeFixIncompleteArrValue(json);
5143      case ARR_VAL_STR:
5144        return `${json}~~"`;
5145      case ARR_VAL_COMPLETED:
5146        return `${json},"~~"`;
5147    }
5148  
5149    return json;
5150  }
5151  
5152  function _maybeFixIncompleteArrValue(json) {
5153    const pos = _findLastArrayDelimiter(json);
5154  
5155    if (pos > -1) {
5156      const part = json.slice(pos + 1);
5157  
5158      if (ALLOWED_PRIMITIVES.includes(part.trim())) {
5159        return `${json},"~~"`;
5160      }
5161  
5162      // Everything else is replaced with `"~~"`
5163      return `${json.slice(0, pos + 1)}"~~"`;
5164    }
5165  
5166    // fallback, this shouldn't happen, to be save
5167    return json;
5168  }
5169  
5170  function _findLastArrayDelimiter(json) {
5171    for (let i = json.length - 1; i >= 0; i--) {
5172      const char = json[i];
5173  
5174      if (char === ',' || char === '[') {
5175        return i;
5176      }
5177    }
5178  
5179    return -1;
5180  }
5181  
5182  function _maybeFixIncompleteObjValue(json) {
5183    const startPos = json.lastIndexOf(':');
5184  
5185    const part = json.slice(startPos + 1);
5186  
5187    if (ALLOWED_PRIMITIVES.includes(part.trim())) {
5188      return `${json},"~~":"~~"`;
5189    }
5190  
5191    // Everything else is replaced with `"~~"`
5192    // This also means we do not have incomplete numbers, e.g `[1` is replaced with `["~~"]`
5193    return `${json.slice(0, startPos + 1)}"~~"`;
5194  }
5195  
5196  /**
5197   * Evaluate an (incomplete) JSON string.
5198   */
5199  function evaluateJson(json) {
5200    const stack = [];
5201  
5202    for (let pos = 0; pos < json.length; pos++) {
5203      _evaluateJsonPos(stack, json, pos);
5204    }
5205  
5206    return stack;
5207  }
5208  
5209  function _evaluateJsonPos(stack, json, pos) {
5210    const curStep = stack[stack.length - 1];
5211  
5212    const char = json[pos];
5213  
5214    const whitespaceRegex = /\s/;
5215  
5216    if (whitespaceRegex.test(char)) {
5217      return;
5218    }
5219  
5220    if (char === '"' && !_isEscaped(json, pos)) {
5221      _handleQuote(stack, curStep);
5222      return;
5223    }
5224  
5225    switch (char) {
5226      case '{':
5227        _handleObj(stack, curStep);
5228        break;
5229      case '[':
5230        _handleArr(stack, curStep);
5231        break;
5232      case ':':
5233        _handleColon(stack, curStep);
5234        break;
5235      case ',':
5236        _handleComma(stack, curStep);
5237        break;
5238      case '}':
5239        _handleObjClose(stack, curStep);
5240        break;
5241      case ']':
5242        _handleArrClose(stack, curStep);
5243        break;
5244    }
5245  }
5246  
5247  function _handleQuote(stack, curStep) {
5248    // End of obj value
5249    if (curStep === OBJ_VAL_STR) {
5250      stack.pop();
5251      stack.push(OBJ_VAL_COMPLETED);
5252      return;
5253    }
5254  
5255    // End of arr value
5256    if (curStep === ARR_VAL_STR) {
5257      stack.pop();
5258      stack.push(ARR_VAL_COMPLETED);
5259      return;
5260    }
5261  
5262    // Start of obj value
5263    if (curStep === OBJ_VAL) {
5264      stack.push(OBJ_VAL_STR);
5265      return;
5266    }
5267  
5268    // Start of arr value
5269    if (curStep === ARR_VAL) {
5270      stack.push(ARR_VAL_STR);
5271      return;
5272    }
5273  
5274    // Start of obj key
5275    if (curStep === OBJ) {
5276      stack.push(OBJ_KEY_STR);
5277      return;
5278    }
5279  
5280    // End of obj key
5281    if (curStep === OBJ_KEY_STR) {
5282      stack.pop();
5283      stack.push(OBJ_KEY);
5284      return;
5285    }
5286  }
5287  
5288  function _handleObj(stack, curStep) {
5289    // Initial object
5290    if (!curStep) {
5291      stack.push(OBJ);
5292      return;
5293    }
5294  
5295    // New object as obj value
5296    if (curStep === OBJ_VAL) {
5297      stack.push(OBJ);
5298      return;
5299    }
5300  
5301    // New object as array element
5302    if (curStep === ARR_VAL) {
5303      stack.push(OBJ);
5304    }
5305  
5306    // New object as first array element
5307    if (curStep === ARR) {
5308      stack.push(OBJ);
5309      return;
5310    }
5311  }
5312  
5313  function _handleArr(stack, curStep) {
5314    // Initial array
5315    if (!curStep) {
5316      stack.push(ARR);
5317      stack.push(ARR_VAL);
5318      return;
5319    }
5320  
5321    // New array as obj value
5322    if (curStep === OBJ_VAL) {
5323      stack.push(ARR);
5324      stack.push(ARR_VAL);
5325      return;
5326    }
5327  
5328    // New array as array element
5329    if (curStep === ARR_VAL) {
5330      stack.push(ARR);
5331      stack.push(ARR_VAL);
5332    }
5333  
5334    // New array as first array element
5335    if (curStep === ARR) {
5336      stack.push(ARR);
5337      stack.push(ARR_VAL);
5338      return;
5339    }
5340  }
5341  
5342  function _handleColon(stack, curStep) {
5343    if (curStep === OBJ_KEY) {
5344      stack.pop();
5345      stack.push(OBJ_VAL);
5346    }
5347  }
5348  
5349  function _handleComma(stack, curStep) {
5350    // Comma after obj value
5351    if (curStep === OBJ_VAL) {
5352      stack.pop();
5353      return;
5354    }
5355    if (curStep === OBJ_VAL_COMPLETED) {
5356      // Pop OBJ_VAL_COMPLETED & OBJ_VAL
5357      stack.pop();
5358      stack.pop();
5359      return;
5360    }
5361  
5362    // Comma after arr value
5363    if (curStep === ARR_VAL) {
5364      // do nothing - basically we'd pop ARR_VAL but add it right back
5365      return;
5366    }
5367  
5368    if (curStep === ARR_VAL_COMPLETED) {
5369      // Pop ARR_VAL_COMPLETED
5370      stack.pop();
5371  
5372      // basically we'd pop ARR_VAL but add it right back
5373      return;
5374    }
5375  }
5376  
5377  function _handleObjClose(stack, curStep) {
5378    // Empty object {}
5379    if (curStep === OBJ) {
5380      stack.pop();
5381    }
5382  
5383    // Object with element
5384    if (curStep === OBJ_VAL) {
5385      // Pop OBJ_VAL, OBJ
5386      stack.pop();
5387      stack.pop();
5388    }
5389  
5390    // Obj with element
5391    if (curStep === OBJ_VAL_COMPLETED) {
5392      // Pop OBJ_VAL_COMPLETED, OBJ_VAL, OBJ
5393      stack.pop();
5394      stack.pop();
5395      stack.pop();
5396    }
5397  
5398    // if was obj value, complete it
5399    if (stack[stack.length - 1] === OBJ_VAL) {
5400      stack.push(OBJ_VAL_COMPLETED);
5401    }
5402  
5403    // if was arr value, complete it
5404    if (stack[stack.length - 1] === ARR_VAL) {
5405      stack.push(ARR_VAL_COMPLETED);
5406    }
5407  }
5408  
5409  function _handleArrClose(stack, curStep) {
5410    // Empty array []
5411    if (curStep === ARR) {
5412      stack.pop();
5413    }
5414  
5415    // Array with element
5416    if (curStep === ARR_VAL) {
5417      // Pop ARR_VAL, ARR
5418      stack.pop();
5419      stack.pop();
5420    }
5421  
5422    // Array with element
5423    if (curStep === ARR_VAL_COMPLETED) {
5424      // Pop ARR_VAL_COMPLETED, ARR_VAL, ARR
5425      stack.pop();
5426      stack.pop();
5427      stack.pop();
5428    }
5429  
5430    // if was obj value, complete it
5431    if (stack[stack.length - 1] === OBJ_VAL) {
5432      stack.push(OBJ_VAL_COMPLETED);
5433    }
5434  
5435    // if was arr value, complete it
5436    if (stack[stack.length - 1] === ARR_VAL) {
5437      stack.push(ARR_VAL_COMPLETED);
5438    }
5439  }
5440  
5441  function _isEscaped(str, pos) {
5442    const previousChar = str[pos - 1];
5443  
5444    return previousChar === '\\' && !_isEscaped(str, pos - 1);
5445  }
5446  
5447  /* eslint-disable max-lines */
5448  
5449  /**
5450   * Takes an incomplete JSON string, and returns a hopefully valid JSON string.
5451   * Note that this _can_ fail, so you should check the return value is valid JSON.
5452   */
5453  function fixJson(incompleteJson) {
5454    const stack = evaluateJson(incompleteJson);
5455  
5456    return completeJson(incompleteJson, stack);
5457  }
5458  
5459  /** Get the size of a body. */
5460  function getBodySize(
5461    body,
5462    textEncoder,
5463  ) {
5464    if (!body) {
5465      return undefined;
5466    }
5467  
5468    try {
5469      if (typeof body === 'string') {
5470        return textEncoder.encode(body).length;
5471      }
5472  
5473      if (body instanceof URLSearchParams) {
5474        return textEncoder.encode(body.toString()).length;
5475      }
5476  
5477      if (body instanceof FormData) {
5478        const formDataStr = _serializeFormData(body);
5479        return textEncoder.encode(formDataStr).length;
5480      }
5481  
5482      if (body instanceof Blob) {
5483        return body.size;
5484      }
5485  
5486      if (body instanceof ArrayBuffer) {
5487        return body.byteLength;
5488      }
5489  
5490      // Currently unhandled types: ArrayBufferView, ReadableStream
5491    } catch (e) {
5492      // just return undefined
5493    }
5494  
5495    return undefined;
5496  }
5497  
5498  /** Convert a Content-Length header to number/undefined.  */
5499  function parseContentLengthHeader(header) {
5500    if (!header) {
5501      return undefined;
5502    }
5503  
5504    const size = parseInt(header, 10);
5505    return isNaN(size) ? undefined : size;
5506  }
5507  
5508  /** Get the string representation of a body. */
5509  function getBodyString(body) {
5510    if (typeof body === 'string') {
5511      return body;
5512    }
5513  
5514    if (body instanceof URLSearchParams) {
5515      return body.toString();
5516    }
5517  
5518    if (body instanceof FormData) {
5519      return _serializeFormData(body);
5520    }
5521  
5522    return undefined;
5523  }
5524  
5525  /** Convert ReplayNetworkRequestData to a PerformanceEntry. */
5526  function makeNetworkReplayBreadcrumb(
5527    type,
5528    data,
5529  ) {
5530    if (!data) {
5531      return null;
5532    }
5533  
5534    const { startTimestamp, endTimestamp, url, method, statusCode, request, response } = data;
5535  
5536    const result = {
5537      type,
5538      start: startTimestamp / 1000,
5539      end: endTimestamp / 1000,
5540      name: url,
5541      data: dropUndefinedKeys({
5542        method,
5543        statusCode,
5544        request,
5545        response,
5546      }),
5547    };
5548  
5549    return result;
5550  }
5551  
5552  /** Build the request or response part of a replay network breadcrumb that was skipped. */
5553  function buildSkippedNetworkRequestOrResponse(bodySize) {
5554    return {
5555      headers: {},
5556      size: bodySize,
5557      _meta: {
5558        warnings: ['URL_SKIPPED'],
5559      },
5560    };
5561  }
5562  
5563  /** Build the request or response part of a replay network breadcrumb. */
5564  function buildNetworkRequestOrResponse(
5565    headers,
5566    bodySize,
5567    body,
5568  ) {
5569    if (!bodySize && Object.keys(headers).length === 0) {
5570      return undefined;
5571    }
5572  
5573    if (!bodySize) {
5574      return {
5575        headers,
5576      };
5577    }
5578  
5579    if (!body) {
5580      return {
5581        headers,
5582        size: bodySize,
5583      };
5584    }
5585  
5586    const info = {
5587      headers,
5588      size: bodySize,
5589    };
5590  
5591    const { body: normalizedBody, warnings } = normalizeNetworkBody(body);
5592    info.body = normalizedBody;
5593    if (warnings.length > 0) {
5594      info._meta = {
5595        warnings,
5596      };
5597    }
5598  
5599    return info;
5600  }
5601  
5602  /** Filter a set of headers */
5603  function getAllowedHeaders(headers, allowedHeaders) {
5604    return Object.keys(headers).reduce((filteredHeaders, key) => {
5605      const normalizedKey = key.toLowerCase();
5606      // Avoid putting empty strings into the headers
5607      if (allowedHeaders.includes(normalizedKey) && headers[key]) {
5608        filteredHeaders[normalizedKey] = headers[key];
5609      }
5610      return filteredHeaders;
5611    }, {});
5612  }
5613  
5614  function _serializeFormData(formData) {
5615    // This is a bit simplified, but gives us a decent estimate
5616    // This converts e.g. { name: 'Anne Smith', age: 13 } to 'name=Anne+Smith&age=13'
5617    // @ts-ignore passing FormData to URLSearchParams actually works
5618    return new URLSearchParams(formData).toString();
5619  }
5620  
5621  function normalizeNetworkBody(body)
5622  
5623   {
5624    if (!body || typeof body !== 'string') {
5625      return {
5626        body,
5627        warnings: [],
5628      };
5629    }
5630  
5631    const exceedsSizeLimit = body.length > NETWORK_BODY_MAX_SIZE;
5632  
5633    if (_strIsProbablyJson(body)) {
5634      try {
5635        const json = exceedsSizeLimit ? fixJson(body.slice(0, NETWORK_BODY_MAX_SIZE)) : body;
5636        const normalizedBody = JSON.parse(json);
5637        return {
5638          body: normalizedBody,
5639          warnings: exceedsSizeLimit ? ['JSON_TRUNCATED'] : [],
5640        };
5641      } catch (e3) {
5642        return {
5643          body: exceedsSizeLimit ? `${body.slice(0, NETWORK_BODY_MAX_SIZE)}…` : body,
5644          warnings: exceedsSizeLimit ? ['INVALID_JSON', 'TEXT_TRUNCATED'] : ['INVALID_JSON'],
5645        };
5646      }
5647    }
5648  
5649    return {
5650      body: exceedsSizeLimit ? `${body.slice(0, NETWORK_BODY_MAX_SIZE)}…` : body,
5651      warnings: exceedsSizeLimit ? ['TEXT_TRUNCATED'] : [],
5652    };
5653  }
5654  
5655  function _strIsProbablyJson(str) {
5656    const first = str[0];
5657    const last = str[str.length - 1];
5658  
5659    // Simple check: If this does not start & end with {} or [], it's not JSON
5660    return (first === '[' && last === ']') || (first === '{' && last === '}');
5661  }
5662  
5663  /** Match an URL against a list of strings/Regex. */
5664  function urlMatches(url, urls) {
5665    const fullUrl = getFullUrl(url);
5666  
5667    return stringMatchesSomePattern(fullUrl, urls);
5668  }
5669  
5670  /** exported for tests */
5671  function getFullUrl(url, baseURI = WINDOW.document.baseURI) {
5672    // Short circuit for common cases:
5673    if (url.startsWith('http://') || url.startsWith('https://') || url.startsWith(WINDOW.location.origin)) {
5674      return url;
5675    }
5676    const fixedUrl = new URL(url, baseURI);
5677  
5678    // If these do not match, we are not dealing with a relative URL, so just return it
5679    if (fixedUrl.origin !== new URL(baseURI).origin) {
5680      return url;
5681    }
5682  
5683    const fullUrl = fixedUrl.href;
5684  
5685    // Remove trailing slashes, if they don't match the original URL
5686    if (!url.endsWith('/') && fullUrl.endsWith('/')) {
5687      return fullUrl.slice(0, -1);
5688    }
5689  
5690    return fullUrl;
5691  }
5692  
5693  /**
5694   * Capture a fetch breadcrumb to a replay.
5695   * This adds additional data (where approriate).
5696   */
5697  async function captureFetchBreadcrumbToReplay(
5698    breadcrumb,
5699    hint,
5700    options
5701  
5702  ,
5703  ) {
5704    try {
5705      const data = await _prepareFetchData(breadcrumb, hint, options);
5706  
5707      // Create a replay performance entry from this breadcrumb
5708      const result = makeNetworkReplayBreadcrumb('resource.fetch', data);
5709      addNetworkBreadcrumb(options.replay, result);
5710    } catch (error) {
5711      (typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && logger.error('[Replay] Failed to capture fetch breadcrumb', error);
5712    }
5713  }
5714  
5715  /**
5716   * Enrich a breadcrumb with additional data.
5717   * This has to be sync & mutate the given breadcrumb,
5718   * as the breadcrumb is afterwards consumed by other handlers.
5719   */
5720  function enrichFetchBreadcrumb(
5721    breadcrumb,
5722    hint,
5723    options,
5724  ) {
5725    const { input, response } = hint;
5726  
5727    const body = _getFetchRequestArgBody(input);
5728    const reqSize = getBodySize(body, options.textEncoder);
5729  
5730    const resSize = response ? parseContentLengthHeader(response.headers.get('content-length')) : undefined;
5731  
5732    if (reqSize !== undefined) {
5733      breadcrumb.data.request_body_size = reqSize;
5734    }
5735    if (resSize !== undefined) {
5736      breadcrumb.data.response_body_size = resSize;
5737    }
5738  }
5739  
5740  async function _prepareFetchData(
5741    breadcrumb,
5742    hint,
5743    options
5744  
5745  ,
5746  ) {
5747    const { startTimestamp, endTimestamp } = hint;
5748  
5749    const {
5750      url,
5751      method,
5752      status_code: statusCode = 0,
5753      request_body_size: requestBodySize,
5754      response_body_size: responseBodySize,
5755    } = breadcrumb.data;
5756  
5757    const captureDetails = urlMatches(url, options.networkDetailAllowUrls);
5758  
5759    const request = captureDetails
5760      ? _getRequestInfo(options, hint.input, requestBodySize)
5761      : buildSkippedNetworkRequestOrResponse(requestBodySize);
5762    const response = await _getResponseInfo(captureDetails, options, hint.response, responseBodySize);
5763  
5764    return {
5765      startTimestamp,
5766      endTimestamp,
5767      url,
5768      method,
5769      statusCode,
5770      request,
5771      response,
5772    };
5773  }
5774  
5775  function _getRequestInfo(
5776    { networkCaptureBodies, networkRequestHeaders },
5777    input,
5778    requestBodySize,
5779  ) {
5780    const headers = getRequestHeaders(input, networkRequestHeaders);
5781  
5782    if (!networkCaptureBodies) {
5783      return buildNetworkRequestOrResponse(headers, requestBodySize, undefined);
5784    }
5785  
5786    // We only want to transmit string or string-like bodies
5787    const requestBody = _getFetchRequestArgBody(input);
5788    const bodyStr = getBodyString(requestBody);
5789    return buildNetworkRequestOrResponse(headers, requestBodySize, bodyStr);
5790  }
5791  
5792  async function _getResponseInfo(
5793    captureDetails,
5794    {
5795      networkCaptureBodies,
5796      textEncoder,
5797      networkResponseHeaders,
5798    }
5799  
5800  ,
5801    response,
5802    responseBodySize,
5803  ) {
5804    if (!captureDetails && responseBodySize !== undefined) {
5805      return buildSkippedNetworkRequestOrResponse(responseBodySize);
5806    }
5807  
5808    const headers = getAllHeaders(response.headers, networkResponseHeaders);
5809  
5810    if (!networkCaptureBodies && responseBodySize !== undefined) {
5811      return buildNetworkRequestOrResponse(headers, responseBodySize, undefined);
5812    }
5813  
5814    // Only clone the response if we need to
5815    try {
5816      // We have to clone this, as the body can only be read once
5817      const res = response.clone();
5818      const bodyText = await _parseFetchBody(res);
5819  
5820      const size =
5821        bodyText && bodyText.length && responseBodySize === undefined
5822          ? getBodySize(bodyText, textEncoder)
5823          : responseBodySize;
5824  
5825      if (!captureDetails) {
5826        return buildSkippedNetworkRequestOrResponse(size);
5827      }
5828  
5829      if (networkCaptureBodies) {
5830        return buildNetworkRequestOrResponse(headers, size, bodyText);
5831      }
5832  
5833      return buildNetworkRequestOrResponse(headers, size, undefined);
5834    } catch (e) {
5835      // fallback
5836      return buildNetworkRequestOrResponse(headers, responseBodySize, undefined);
5837    }
5838  }
5839  
5840  async function _parseFetchBody(response) {
5841    try {
5842      return await response.text();
5843    } catch (e2) {
5844      return undefined;
5845    }
5846  }
5847  
5848  function _getFetchRequestArgBody(fetchArgs = []) {
5849    // We only support getting the body from the fetch options
5850    if (fetchArgs.length !== 2 || typeof fetchArgs[1] !== 'object') {
5851      return undefined;
5852    }
5853  
5854    return (fetchArgs[1] ).body;
5855  }
5856  
5857  function getAllHeaders(headers, allowedHeaders) {
5858    const allHeaders = {};
5859  
5860    allowedHeaders.forEach(header => {
5861      if (headers.get(header)) {
5862        allHeaders[header] = headers.get(header) ;
5863      }
5864    });
5865  
5866    return allHeaders;
5867  }
5868  
5869  function getRequestHeaders(fetchArgs, allowedHeaders) {
5870    if (fetchArgs.length === 1 && typeof fetchArgs[0] !== 'string') {
5871      return getHeadersFromOptions(fetchArgs[0] , allowedHeaders);
5872    }
5873  
5874    if (fetchArgs.length === 2) {
5875      return getHeadersFromOptions(fetchArgs[1] , allowedHeaders);
5876    }
5877  
5878    return {};
5879  }
5880  
5881  function getHeadersFromOptions(
5882    input,
5883    allowedHeaders,
5884  ) {
5885    if (!input) {
5886      return {};
5887    }
5888  
5889    const headers = input.headers;
5890  
5891    if (!headers) {
5892      return {};
5893    }
5894  
5895    if (headers instanceof Headers) {
5896      return getAllHeaders(headers, allowedHeaders);
5897    }
5898  
5899    // We do not support this, as it is not really documented (anymore?)
5900    if (Array.isArray(headers)) {
5901      return {};
5902    }
5903  
5904    return getAllowedHeaders(headers, allowedHeaders);
5905  }
5906  
5907  /**
5908   * Capture an XHR breadcrumb to a replay.
5909   * This adds additional data (where approriate).
5910   */
5911  async function captureXhrBreadcrumbToReplay(
5912    breadcrumb,
5913    hint,
5914    options,
5915  ) {
5916    try {
5917      const data = _prepareXhrData(breadcrumb, hint, options);
5918  
5919      // Create a replay performance entry from this breadcrumb
5920      const result = makeNetworkReplayBreadcrumb('resource.xhr', data);
5921      addNetworkBreadcrumb(options.replay, result);
5922    } catch (error) {
5923      (typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && logger.error('[Replay] Failed to capture fetch breadcrumb', error);
5924    }
5925  }
5926  
5927  /**
5928   * Enrich a breadcrumb with additional data.
5929   * This has to be sync & mutate the given breadcrumb,
5930   * as the breadcrumb is afterwards consumed by other handlers.
5931   */
5932  function enrichXhrBreadcrumb(
5933    breadcrumb,
5934    hint,
5935    options,
5936  ) {
5937    const { xhr, input } = hint;
5938  
5939    const reqSize = getBodySize(input, options.textEncoder);
5940    const resSize = xhr.getResponseHeader('content-length')
5941      ? parseContentLengthHeader(xhr.getResponseHeader('content-length'))
5942      : getBodySize(xhr.response, options.textEncoder);
5943  
5944    if (reqSize !== undefined) {
5945      breadcrumb.data.request_body_size = reqSize;
5946    }
5947    if (resSize !== undefined) {
5948      breadcrumb.data.response_body_size = resSize;
5949    }
5950  }
5951  
5952  function _prepareXhrData(
5953    breadcrumb,
5954    hint,
5955    options,
5956  ) {
5957    const { startTimestamp, endTimestamp, input, xhr } = hint;
5958  
5959    const {
5960      url,
5961      method,
5962      status_code: statusCode = 0,
5963      request_body_size: requestBodySize,
5964      response_body_size: responseBodySize,
5965    } = breadcrumb.data;
5966  
5967    if (!url) {
5968      return null;
5969    }
5970  
5971    if (!urlMatches(url, options.networkDetailAllowUrls)) {
5972      const request = buildSkippedNetworkRequestOrResponse(requestBodySize);
5973      const response = buildSkippedNetworkRequestOrResponse(responseBodySize);
5974      return {
5975        startTimestamp,
5976        endTimestamp,
5977        url,
5978        method,
5979        statusCode,
5980        request,
5981        response,
5982      };
5983    }
5984  
5985    const xhrInfo = xhr[SENTRY_XHR_DATA_KEY];
5986    const networkRequestHeaders = xhrInfo
5987      ? getAllowedHeaders(xhrInfo.request_headers, options.networkRequestHeaders)
5988      : {};
5989    const networkResponseHeaders = getAllowedHeaders(getResponseHeaders(xhr), options.networkResponseHeaders);
5990  
5991    const request = buildNetworkRequestOrResponse(
5992      networkRequestHeaders,
5993      requestBodySize,
5994      options.networkCaptureBodies ? getBodyString(input) : undefined,
5995    );
5996    const response = buildNetworkRequestOrResponse(
5997      networkResponseHeaders,
5998      responseBodySize,
5999      options.networkCaptureBodies ? hint.xhr.responseText : undefined,
6000    );
6001  
6002    return {
6003      startTimestamp,
6004      endTimestamp,
6005      url,
6006      method,
6007      statusCode,
6008      request,
6009      response,
6010    };
6011  }
6012  
6013  function getResponseHeaders(xhr) {
6014    const headers = xhr.getAllResponseHeaders();
6015  
6016    if (!headers) {
6017      return {};
6018    }
6019  
6020    return headers.split('\r\n').reduce((acc, line) => {
6021      const [key, value] = line.split(': ');
6022      acc[key.toLowerCase()] = value;
6023      return acc;
6024    }, {});
6025  }
6026  
6027  /**
6028   * This method does two things:
6029   * - It enriches the regular XHR/fetch breadcrumbs with request/response size data
6030   * - It captures the XHR/fetch breadcrumbs to the replay
6031   *   (enriching it with further data that is _not_ added to the regular breadcrumbs)
6032   */
6033  function handleNetworkBreadcrumbs(replay) {
6034    const client = getCurrentHub().getClient();
6035  
6036    try {
6037      const textEncoder = new TextEncoder();
6038  
6039      const { networkDetailAllowUrls, networkCaptureBodies, networkRequestHeaders, networkResponseHeaders } =
6040        replay.getOptions();
6041  
6042      const options = {
6043        replay,
6044        textEncoder,
6045        networkDetailAllowUrls,
6046        networkCaptureBodies,
6047        networkRequestHeaders,
6048        networkResponseHeaders,
6049      };
6050  
6051      if (client && client.on) {
6052        client.on('beforeAddBreadcrumb', (breadcrumb, hint) => beforeAddNetworkBreadcrumb(options, breadcrumb, hint));
6053      } else {
6054        // Fallback behavior
6055        addInstrumentationHandler('fetch', handleFetchSpanListener(replay));
6056        addInstrumentationHandler('xhr', handleXhrSpanListener(replay));
6057      }
6058    } catch (e2) {
6059      // Do nothing
6060    }
6061  }
6062  
6063  /** just exported for tests */
6064  function beforeAddNetworkBreadcrumb(
6065    options,
6066    breadcrumb,
6067    hint,
6068  ) {
6069    if (!breadcrumb.data) {
6070      return;
6071    }
6072  
6073    try {
6074      if (_isXhrBreadcrumb(breadcrumb) && _isXhrHint(hint)) {
6075        // This has to be sync, as we need to ensure the breadcrumb is enriched in the same tick
6076        // Because the hook runs synchronously, and the breadcrumb is afterwards passed on
6077        // So any async mutations to it will not be reflected in the final breadcrumb
6078        enrichXhrBreadcrumb(breadcrumb, hint, options);
6079  
6080        void captureXhrBreadcrumbToReplay(breadcrumb, hint, options);
6081      }
6082  
6083      if (_isFetchBreadcrumb(breadcrumb) && _isFetchHint(hint)) {
6084        // This has to be sync, as we need to ensure the breadcrumb is enriched in the same tick
6085        // Because the hook runs synchronously, and the breadcrumb is afterwards passed on
6086        // So any async mutations to it will not be reflected in the final breadcrumb
6087        enrichFetchBreadcrumb(breadcrumb, hint, options);
6088  
6089        void captureFetchBreadcrumbToReplay(breadcrumb, hint, options);
6090      }
6091    } catch (e) {
6092      (typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && logger.warn('Error when enriching network breadcrumb');
6093    }
6094  }
6095  
6096  function _isXhrBreadcrumb(breadcrumb) {
6097    return breadcrumb.category === 'xhr';
6098  }
6099  
6100  function _isFetchBreadcrumb(breadcrumb) {
6101    return breadcrumb.category === 'fetch';
6102  }
6103  
6104  function _isXhrHint(hint) {
6105    return hint && hint.xhr;
6106  }
6107  
6108  function _isFetchHint(hint) {
6109    return hint && hint.response;
6110  }
6111  
6112  let _LAST_BREADCRUMB = null;
6113  
6114  function isBreadcrumbWithCategory(breadcrumb) {
6115    return !!breadcrumb.category;
6116  }
6117  
6118  const handleScopeListener =
6119    (replay) =>
6120    (scope) => {
6121      if (!replay.isEnabled()) {
6122        return;
6123      }
6124  
6125      const result = handleScope(scope);
6126  
6127      if (!result) {
6128        return;
6129      }
6130  
6131      addBreadcrumbEvent(replay, result);
6132    };
6133  
6134  /**
6135   * An event handler to handle scope changes.
6136   */
6137  function handleScope(scope) {
6138    // TODO (v8): Remove this guard. This was put in place because we introduced
6139    // Scope.getLastBreadcrumb mid-v7 which caused incompatibilities with older SDKs.
6140    // For now, we'll just return null if the method doesn't exist but we should eventually
6141    // get rid of this guard.
6142    const newBreadcrumb = scope.getLastBreadcrumb && scope.getLastBreadcrumb();
6143  
6144    // Listener can be called when breadcrumbs have not changed, so we store the
6145    // reference to the last crumb and only return a crumb if it has changed
6146    if (_LAST_BREADCRUMB === newBreadcrumb || !newBreadcrumb) {
6147      return null;
6148    }
6149  
6150    _LAST_BREADCRUMB = newBreadcrumb;
6151  
6152    if (
6153      !isBreadcrumbWithCategory(newBreadcrumb) ||
6154      ['fetch', 'xhr', 'sentry.event', 'sentry.transaction'].includes(newBreadcrumb.category) ||
6155      newBreadcrumb.category.startsWith('ui.')
6156    ) {
6157      return null;
6158    }
6159  
6160    if (newBreadcrumb.category === 'console') {
6161      return normalizeConsoleBreadcrumb(newBreadcrumb);
6162    }
6163  
6164    return createBreadcrumb(newBreadcrumb);
6165  }
6166  
6167  /** exported for tests only */
6168  function normalizeConsoleBreadcrumb(
6169    breadcrumb,
6170  ) {
6171    const args = breadcrumb.data && breadcrumb.data.arguments;
6172  
6173    if (!Array.isArray(args) || args.length === 0) {
6174      return createBreadcrumb(breadcrumb);
6175    }
6176  
6177    let isTruncated = false;
6178  
6179    // Avoid giant args captures
6180    const normalizedArgs = args.map(arg => {
6181      if (!arg) {
6182        return arg;
6183      }
6184      if (typeof arg === 'string') {
6185        if (arg.length > CONSOLE_ARG_MAX_SIZE) {
6186          isTruncated = true;
6187          return `${arg.slice(0, CONSOLE_ARG_MAX_SIZE)}…`;
6188        }
6189  
6190        return arg;
6191      }
6192      if (typeof arg === 'object') {
6193        try {
6194          const normalizedArg = normalize(arg, 7);
6195          const stringified = JSON.stringify(normalizedArg);
6196          if (stringified.length > CONSOLE_ARG_MAX_SIZE) {
6197            const fixedJson = fixJson(stringified.slice(0, CONSOLE_ARG_MAX_SIZE));
6198            const json = JSON.parse(fixedJson);
6199            // We only set this after JSON.parse() was successfull, so we know we didn't run into `catch`
6200            isTruncated = true;
6201            return json;
6202          }
6203          return normalizedArg;
6204        } catch (e) {
6205          // fall back to default
6206        }
6207      }
6208  
6209      return arg;
6210    });
6211  
6212    return createBreadcrumb({
6213      ...breadcrumb,
6214      data: {
6215        ...breadcrumb.data,
6216        arguments: normalizedArgs,
6217        ...(isTruncated ? { _meta: { warnings: ['CONSOLE_ARG_TRUNCATED'] } } : {}),
6218      },
6219    });
6220  }
6221  
6222  /**
6223   * Add global listeners that cannot be removed.
6224   */
6225  function addGlobalListeners(replay) {
6226    // Listeners from core SDK //
6227    const scope = getCurrentHub().getScope();
6228    const client = getCurrentHub().getClient();
6229  
6230    if (scope) {
6231      scope.addScopeListener(handleScopeListener(replay));
6232    }
6233    addInstrumentationHandler('dom', handleDomListener(replay));
6234    addInstrumentationHandler('history', handleHistorySpanListener(replay));
6235    handleNetworkBreadcrumbs(replay);
6236  
6237    // Tag all (non replay) events that get sent to Sentry with the current
6238    // replay ID so that we can reference them later in the UI
6239    addGlobalEventProcessor(handleGlobalEventListener(replay, !hasHooks(client)));
6240  
6241    // If a custom client has no hooks yet, we continue to use the "old" implementation
6242    if (hasHooks(client)) {
6243      client.on('afterSendEvent', handleAfterSendEvent(replay));
6244      client.on('createDsc', (dsc) => {
6245        const replayId = replay.getSessionId();
6246        // We do not want to set the DSC when in buffer mode, as that means the replay has not been sent (yet)
6247        if (replayId && replay.isEnabled() && replay.recordingMode === 'session') {
6248          dsc.replay_id = replayId;
6249        }
6250      });
6251  
6252      client.on('startTransaction', transaction => {
6253        replay.lastTransaction = transaction;
6254      });
6255  
6256      // We may be missing the initial startTransaction due to timing issues,
6257      // so we capture it on finish again.
6258      client.on('finishTransaction', transaction => {
6259        replay.lastTransaction = transaction;
6260      });
6261    }
6262  }
6263  
6264  // eslint-disable-next-line @typescript-eslint/no-explicit-any
6265  function hasHooks(client) {
6266    return !!(client && client.on);
6267  }
6268  
6269  /**
6270   * Create a "span" for the total amount of memory being used by JS objects
6271   * (including v8 internal objects).
6272   */
6273  async function addMemoryEntry(replay) {
6274    // window.performance.memory is a non-standard API and doesn't work on all browsers, so we try-catch this
6275    try {
6276      return Promise.all(
6277        createPerformanceSpans(replay, [
6278          // @ts-ignore memory doesn't exist on type Performance as the API is non-standard (we check that it exists above)
6279          createMemoryEntry(WINDOW.performance.memory),
6280        ]),
6281      );
6282    } catch (error) {
6283      // Do nothing
6284      return [];
6285    }
6286  }
6287  
6288  function createMemoryEntry(memoryEntry) {
6289    const { jsHeapSizeLimit, totalJSHeapSize, usedJSHeapSize } = memoryEntry;
6290    // we don't want to use `getAbsoluteTime` because it adds the event time to the
6291    // time origin, so we get the current timestamp instead
6292    const time = Date.now() / 1000;
6293    return {
6294      type: 'memory',
6295      name: 'memory',
6296      start: time,
6297      end: time,
6298      data: {
6299        memory: {
6300          jsHeapSizeLimit,
6301          totalJSHeapSize,
6302          usedJSHeapSize,
6303        },
6304      },
6305    };
6306  }
6307  
6308  // Map entryType -> function to normalize data for event
6309  // @ts-ignore TODO: entry type does not fit the create* functions entry type
6310  const ENTRY_TYPES
6311  
6312   = {
6313    // @ts-ignore TODO: entry type does not fit the create* functions entry type
6314    resource: createResourceEntry,
6315    paint: createPaintEntry,
6316    // @ts-ignore TODO: entry type does not fit the create* functions entry type
6317    navigation: createNavigationEntry,
6318    // @ts-ignore TODO: entry type does not fit the create* functions entry type
6319    ['largest-contentful-paint']: createLargestContentfulPaint,
6320  };
6321  
6322  /**
6323   * Create replay performance entries from the browser performance entries.
6324   */
6325  function createPerformanceEntries(
6326    entries,
6327  ) {
6328    return entries.map(createPerformanceEntry).filter(Boolean) ;
6329  }
6330  
6331  function createPerformanceEntry(entry) {
6332    if (ENTRY_TYPES[entry.entryType] === undefined) {
6333      return null;
6334    }
6335  
6336    return ENTRY_TYPES[entry.entryType](entry);
6337  }
6338  
6339  function getAbsoluteTime(time) {
6340    // browserPerformanceTimeOrigin can be undefined if `performance` or
6341    // `performance.now` doesn't exist, but this is already checked by this integration
6342    return ((browserPerformanceTimeOrigin || WINDOW.performance.timeOrigin) + time) / 1000;
6343  }
6344  
6345  function createPaintEntry(entry) {
6346    const { duration, entryType, name, startTime } = entry;
6347  
6348    const start = getAbsoluteTime(startTime);
6349    return {
6350      type: entryType,
6351      name,
6352      start,
6353      end: start + duration,
6354      data: undefined,
6355    };
6356  }
6357  
6358  function createNavigationEntry(entry) {
6359    const {
6360      entryType,
6361      name,
6362      decodedBodySize,
6363      duration,
6364      domComplete,
6365      encodedBodySize,
6366      domContentLoadedEventStart,
6367      domContentLoadedEventEnd,
6368      domInteractive,
6369      loadEventStart,
6370      loadEventEnd,
6371      redirectCount,
6372      startTime,
6373      transferSize,
6374      type,
6375    } = entry;
6376  
6377    // Ignore entries with no duration, they do not seem to be useful and cause dupes
6378    if (duration === 0) {
6379      return null;
6380    }
6381  
6382    return {
6383      type: `${entryType}.${type}`,
6384      start: getAbsoluteTime(startTime),
6385      end: getAbsoluteTime(domComplete),
6386      name,
6387      data: {
6388        size: transferSize,
6389        decodedBodySize,
6390        encodedBodySize,
6391        duration,
6392        domInteractive,
6393        domContentLoadedEventStart,
6394        domContentLoadedEventEnd,
6395        loadEventStart,
6396        loadEventEnd,
6397        domComplete,
6398        redirectCount,
6399      },
6400    };
6401  }
6402  
6403  function createResourceEntry(
6404    entry,
6405  ) {
6406    const {
6407      entryType,
6408      initiatorType,
6409      name,
6410      responseEnd,
6411      startTime,
6412      decodedBodySize,
6413      encodedBodySize,
6414      responseStatus,
6415      transferSize,
6416    } = entry;
6417  
6418    // Core SDK handles these
6419    if (['fetch', 'xmlhttprequest'].includes(initiatorType)) {
6420      return null;
6421    }
6422  
6423    return {
6424      type: `${entryType}.${initiatorType}`,
6425      start: getAbsoluteTime(startTime),
6426      end: getAbsoluteTime(responseEnd),
6427      name,
6428      data: {
6429        size: transferSize,
6430        statusCode: responseStatus,
6431        decodedBodySize,
6432        encodedBodySize,
6433      },
6434    };
6435  }
6436  
6437  function createLargestContentfulPaint(
6438    entry,
6439  ) {
6440    const { entryType, startTime, size } = entry;
6441  
6442    let startTimeOrNavigationActivation = 0;
6443  
6444    if (WINDOW.performance) {
6445      const navEntry = WINDOW.performance.getEntriesByType('navigation')[0]
6446  
6447  ;
6448  
6449      // See https://github.com/GoogleChrome/web-vitals/blob/9f11c4c6578fb4c5ee6fa4e32b9d1d756475f135/src/lib/getActivationStart.ts#L21
6450      startTimeOrNavigationActivation = (navEntry && navEntry.activationStart) || 0;
6451    }
6452  
6453    // value is in ms
6454    const value = Math.max(startTime - startTimeOrNavigationActivation, 0);
6455    // LCP doesn't have a "duration", it just happens at a single point in time.
6456    // But the UI expects both, so use end (in seconds) for both timestamps.
6457    const end = getAbsoluteTime(startTimeOrNavigationActivation) + value / 1000;
6458  
6459    return {
6460      type: entryType,
6461      name: entryType,
6462      start: end,
6463      end,
6464      data: {
6465        value, // LCP "duration" in ms
6466        size,
6467        // Not sure why this errors, Node should be correct (Argument of type 'Node' is not assignable to parameter of type 'INode')
6468        // eslint-disable-next-line @typescript-eslint/no-explicit-any
6469        nodeId: record.mirror.getId(entry.element ),
6470      },
6471    };
6472  }
6473  
6474  /**
6475   * Heavily simplified debounce function based on lodash.debounce.
6476   *
6477   * This function takes a callback function (@param fun) and delays its invocation
6478   * by @param wait milliseconds. Optionally, a maxWait can be specified in @param options,
6479   * which ensures that the callback is invoked at least once after the specified max. wait time.
6480   *
6481   * @param func the function whose invocation is to be debounced
6482   * @param wait the minimum time until the function is invoked after it was called once
6483   * @param options the options object, which can contain the `maxWait` property
6484   *
6485   * @returns the debounced version of the function, which needs to be called at least once to start the
6486   *          debouncing process. Subsequent calls will reset the debouncing timer and, in case @paramfunc
6487   *          was already invoked in the meantime, return @param func's return value.
6488   *          The debounced function has two additional properties:
6489   *          - `flush`: Invokes the debounced function immediately and returns its return value
6490   *          - `cancel`: Cancels the debouncing process and resets the debouncing timer
6491   */
6492  function debounce(func, wait, options) {
6493    let callbackReturnValue;
6494  
6495    let timerId;
6496    let maxTimerId;
6497  
6498    const maxWait = options && options.maxWait ? Math.max(options.maxWait, wait) : 0;
6499  
6500    function invokeFunc() {
6501      cancelTimers();
6502      callbackReturnValue = func();
6503      return callbackReturnValue;
6504    }
6505  
6506    function cancelTimers() {
6507      timerId !== undefined && clearTimeout(timerId);
6508      maxTimerId !== undefined && clearTimeout(maxTimerId);
6509      timerId = maxTimerId = undefined;
6510    }
6511  
6512    function flush() {
6513      if (timerId !== undefined || maxTimerId !== undefined) {
6514        return invokeFunc();
6515      }
6516      return callbackReturnValue;
6517    }
6518  
6519    function debounced() {
6520      if (timerId) {
6521        clearTimeout(timerId);
6522      }
6523      timerId = setTimeout(invokeFunc, wait);
6524  
6525      if (maxWait && maxTimerId === undefined) {
6526        maxTimerId = setTimeout(invokeFunc, maxWait);
6527      }
6528  
6529      return callbackReturnValue;
6530    }
6531  
6532    debounced.cancel = cancelTimers;
6533    debounced.flush = flush;
6534    return debounced;
6535  }
6536  
6537  /**
6538   * Handler for recording events.
6539   *
6540   * Adds to event buffer, and has varying flushing behaviors if the event was a checkout.
6541   */
6542  function getHandleRecordingEmit(replay) {
6543    let hadFirstEvent = false;
6544  
6545    return (event, _isCheckout) => {
6546      // If this is false, it means session is expired, create and a new session and wait for checkout
6547      if (!replay.checkAndHandleExpiredSession()) {
6548        (typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && logger.warn('[Replay] Received replay event after session expired.');
6549  
6550        return;
6551      }
6552  
6553      // `_isCheckout` is only set when the checkout is due to `checkoutEveryNms`
6554      // We also want to treat the first event as a checkout, so we handle this specifically here
6555      const isCheckout = _isCheckout || !hadFirstEvent;
6556      hadFirstEvent = true;
6557  
6558      // The handler returns `true` if we do not want to trigger debounced flush, `false` if we want to debounce flush.
6559      replay.addUpdate(() => {
6560        // The session is always started immediately on pageload/init, but for
6561        // error-only replays, it should reflect the most recent checkout
6562        // when an error occurs. Clear any state that happens before this current
6563        // checkout. This needs to happen before `addEvent()` which updates state
6564        // dependent on this reset.
6565        if (replay.recordingMode === 'buffer' && isCheckout) {
6566          replay.setInitialState();
6567        }
6568  
6569        // We need to clear existing events on a checkout, otherwise they are
6570        // incremental event updates and should be appended
6571        void addEvent(replay, event, isCheckout);
6572  
6573        // Different behavior for full snapshots (type=2), ignore other event types
6574        // See https://github.com/rrweb-io/rrweb/blob/d8f9290ca496712aa1e7d472549480c4e7876594/packages/rrweb/src/types.ts#L16
6575        if (!isCheckout) {
6576          return false;
6577        }
6578  
6579        // Additionally, create a meta event that will capture certain SDK settings.
6580        // In order to handle buffer mode, this needs to either be done when we
6581        // receive checkout events or at flush time.
6582        //
6583        // `isCheckout` is always true, but want to be explicit that it should
6584        // only be added for checkouts
6585        void addSettingsEvent(replay, isCheckout);
6586  
6587        // If there is a previousSessionId after a full snapshot occurs, then
6588        // the replay session was started due to session expiration. The new session
6589        // is started before triggering a new checkout and contains the id
6590        // of the previous session. Do not immediately flush in this case
6591        // to avoid capturing only the checkout and instead the replay will
6592        // be captured if they perform any follow-up actions.
6593        if (replay.session && replay.session.previousSessionId) {
6594          return true;
6595        }
6596  
6597        // When in buffer mode, make sure we adjust the session started date to the current earliest event of the buffer
6598        // this should usually be the timestamp of the checkout event, but to be safe...
6599        if (replay.recordingMode === 'buffer' && replay.session && replay.eventBuffer) {
6600          const earliestEvent = replay.eventBuffer.getEarliestTimestamp();
6601          if (earliestEvent) {
6602            replay.session.started = earliestEvent;
6603  
6604            if (replay.getOptions().stickySession) {
6605              saveSession(replay.session);
6606            }
6607          }
6608        }
6609  
6610        if (replay.recordingMode === 'session') {
6611          // If the full snapshot is due to an initial load, we will not have
6612          // a previous session ID. In this case, we want to buffer events
6613          // for a set amount of time before flushing. This can help avoid
6614          // capturing replays of users that immediately close the window.
6615          void replay.flush();
6616        }
6617  
6618        return true;
6619      });
6620    };
6621  }
6622  
6623  /**
6624   * Exported for tests
6625   */
6626  function createOptionsEvent(replay) {
6627    const options = replay.getOptions();
6628    return {
6629      type: EventType.Custom,
6630      timestamp: Date.now(),
6631      data: {
6632        tag: 'options',
6633        payload: {
6634          sessionSampleRate: options.sessionSampleRate,
6635          errorSampleRate: options.errorSampleRate,
6636          useCompressionOption: options.useCompression,
6637          blockAllMedia: options.blockAllMedia,
6638          maskAllText: options.maskAllText,
6639          maskAllInputs: options.maskAllInputs,
6640          useCompression: replay.eventBuffer ? replay.eventBuffer.type === 'worker' : false,
6641          networkDetailHasUrls: options.networkDetailAllowUrls.length > 0,
6642          networkCaptureBodies: options.networkCaptureBodies,
6643          networkRequestHasHeaders: options.networkRequestHeaders.length > 0,
6644          networkResponseHasHeaders: options.networkResponseHeaders.length > 0,
6645        },
6646      },
6647    };
6648  }
6649  
6650  /**
6651   * Add a "meta" event that contains a simplified view on current configuration
6652   * options. This should only be included on the first segment of a recording.
6653   */
6654  function addSettingsEvent(replay, isCheckout) {
6655    // Only need to add this event when sending the first segment
6656    if (!isCheckout || !replay.session || replay.session.segmentId !== 0) {
6657      return Promise.resolve(null);
6658    }
6659  
6660    return addEvent(replay, createOptionsEvent(replay), false);
6661  }
6662  
6663  /**
6664   * Create a replay envelope ready to be sent.
6665   * This includes both the replay event, as well as the recording data.
6666   */
6667  function createReplayEnvelope(
6668    replayEvent,
6669    recordingData,
6670    dsn,
6671    tunnel,
6672  ) {
6673    return createEnvelope(
6674      createEventEnvelopeHeaders(replayEvent, getSdkMetadataForEnvelopeHeader(replayEvent), tunnel, dsn),
6675      [
6676        [{ type: 'replay_event' }, replayEvent],
6677        [
6678          {
6679            type: 'replay_recording',
6680            // If string then we need to encode to UTF8, otherwise will have
6681            // wrong size. TextEncoder has similar browser support to
6682            // MutationObserver, although it does not accept IE11.
6683            length:
6684              typeof recordingData === 'string' ? new TextEncoder().encode(recordingData).length : recordingData.length,
6685          },
6686          recordingData,
6687        ],
6688      ],
6689    );
6690  }
6691  
6692  /**
6693   * Prepare the recording data ready to be sent.
6694   */
6695  function prepareRecordingData({
6696    recordingData,
6697    headers,
6698  }
6699  
6700  ) {
6701    let payloadWithSequence;
6702  
6703    // XXX: newline is needed to separate sequence id from events
6704    const replayHeaders = `${JSON.stringify(headers)}
6705  `;
6706  
6707    if (typeof recordingData === 'string') {
6708      payloadWithSequence = `${replayHeaders}${recordingData}`;
6709    } else {
6710      const enc = new TextEncoder();
6711      // XXX: newline is needed to separate sequence id from events
6712      const sequence = enc.encode(replayHeaders);
6713      // Merge the two Uint8Arrays
6714      payloadWithSequence = new Uint8Array(sequence.length + recordingData.length);
6715      payloadWithSequence.set(sequence);
6716      payloadWithSequence.set(recordingData, sequence.length);
6717    }
6718  
6719    return payloadWithSequence;
6720  }
6721  
6722  /**
6723   * Prepare a replay event & enrich it with the SDK metadata.
6724   */
6725  async function prepareReplayEvent({
6726    client,
6727    scope,
6728    replayId: event_id,
6729    event,
6730  }
6731  
6732  ) {
6733    const integrations =
6734      typeof client._integrations === 'object' && client._integrations !== null && !Array.isArray(client._integrations)
6735        ? Object.keys(client._integrations)
6736        : undefined;
6737    const preparedEvent = (await prepareEvent(
6738      client.getOptions(),
6739      event,
6740      { event_id, integrations },
6741      scope,
6742    )) ;
6743  
6744    // If e.g. a global event processor returned null
6745    if (!preparedEvent) {
6746      return null;
6747    }
6748  
6749    // This normally happens in browser client "_prepareEvent"
6750    // but since we do not use this private method from the client, but rather the plain import
6751    // we need to do this manually.
6752    preparedEvent.platform = preparedEvent.platform || 'javascript';
6753  
6754    // extract the SDK name because `client._prepareEvent` doesn't add it to the event
6755    const metadata = client.getSdkMetadata && client.getSdkMetadata();
6756    const { name, version } = (metadata && metadata.sdk) || {};
6757  
6758    preparedEvent.sdk = {
6759      ...preparedEvent.sdk,
6760      name: name || 'sentry.javascript.unknown',
6761      version: version || '0.0.0',
6762    };
6763  
6764    return preparedEvent;
6765  }
6766  
6767  /**
6768   * Send replay attachment using `fetch()`
6769   */
6770  async function sendReplayRequest({
6771    recordingData,
6772    replayId,
6773    segmentId: segment_id,
6774    eventContext,
6775    timestamp,
6776    session,
6777  }) {
6778    const preparedRecordingData = prepareRecordingData({
6779      recordingData,
6780      headers: {
6781        segment_id,
6782      },
6783    });
6784  
6785    const { urls, errorIds, traceIds, initialTimestamp } = eventContext;
6786  
6787    const hub = getCurrentHub();
6788    const client = hub.getClient();
6789    const scope = hub.getScope();
6790    const transport = client && client.getTransport();
6791    const dsn = client && client.getDsn();
6792  
6793    if (!client || !transport || !dsn || !session.sampled) {
6794      return;
6795    }
6796  
6797    const baseEvent = {
6798      type: REPLAY_EVENT_NAME,
6799      replay_start_timestamp: initialTimestamp / 1000,
6800      timestamp: timestamp / 1000,
6801      error_ids: errorIds,
6802      trace_ids: traceIds,
6803      urls,
6804      replay_id: replayId,
6805      segment_id,
6806      replay_type: session.sampled,
6807    };
6808  
6809    const replayEvent = await prepareReplayEvent({ scope, client, replayId, event: baseEvent });
6810  
6811    if (!replayEvent) {
6812      // Taken from baseclient's `_processEvent` method, where this is handled for errors/transactions
6813      client.recordDroppedEvent('event_processor', 'replay', baseEvent);
6814      (typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && logger.log('An event processor returned `null`, will not send event.');
6815      return;
6816    }
6817  
6818    /*
6819    For reference, the fully built event looks something like this:
6820    {
6821        "type": "replay_event",
6822        "timestamp": 1670837008.634,
6823        "error_ids": [
6824            "errorId"
6825        ],
6826        "trace_ids": [
6827            "traceId"
6828        ],
6829        "urls": [
6830            "https://example.com"
6831        ],
6832        "replay_id": "eventId",
6833        "segment_id": 3,
6834        "replay_type": "error",
6835        "platform": "javascript",
6836        "event_id": "eventId",
6837        "environment": "production",
6838        "sdk": {
6839            "integrations": [
6840                "BrowserTracing",
6841                "Replay"
6842            ],
6843            "name": "sentry.javascript.browser",
6844            "version": "7.25.0"
6845        },
6846        "sdkProcessingMetadata": {},
6847        "contexts": {
6848        },
6849    }
6850    */
6851  
6852    const envelope = createReplayEnvelope(replayEvent, preparedRecordingData, dsn, client.getOptions().tunnel);
6853  
6854    let response;
6855  
6856    try {
6857      response = await transport.send(envelope);
6858    } catch (err) {
6859      const error = new Error(UNABLE_TO_SEND_REPLAY);
6860  
6861      try {
6862        // In case browsers don't allow this property to be writable
6863        // @ts-ignore This needs lib es2022 and newer
6864        error.cause = err;
6865      } catch (e) {
6866        // nothing to do
6867      }
6868      throw error;
6869    }
6870  
6871    // TODO (v8): we can remove this guard once transport.send's type signature doesn't include void anymore
6872    if (!response) {
6873      return response;
6874    }
6875  
6876    // If the status code is invalid, we want to immediately stop & not retry
6877    if (typeof response.statusCode === 'number' && (response.statusCode < 200 || response.statusCode >= 300)) {
6878      throw new TransportStatusCodeError(response.statusCode);
6879    }
6880  
6881    return response;
6882  }
6883  
6884  /**
6885   * This error indicates that the transport returned an invalid status code.
6886   */
6887  class TransportStatusCodeError extends Error {
6888     constructor(statusCode) {
6889      super(`Transport returned status code ${statusCode}`);
6890    }
6891  }
6892  
6893  /**
6894   * Finalize and send the current replay event to Sentry
6895   */
6896  async function sendReplay(
6897    replayData,
6898    retryConfig = {
6899      count: 0,
6900      interval: RETRY_BASE_INTERVAL,
6901    },
6902  ) {
6903    const { recordingData, options } = replayData;
6904  
6905    // short circuit if there's no events to upload (this shouldn't happen as _runFlush makes this check)
6906    if (!recordingData.length) {
6907      return;
6908    }
6909  
6910    try {
6911      await sendReplayRequest(replayData);
6912      return true;
6913    } catch (err) {
6914      if (err instanceof TransportStatusCodeError) {
6915        throw err;
6916      }
6917  
6918      // Capture error for every failed replay
6919      setContext('Replays', {
6920        _retryCount: retryConfig.count,
6921      });
6922  
6923      if ((typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && options._experiments && options._experiments.captureExceptions) {
6924        captureException(err);
6925      }
6926  
6927      // If an error happened here, it's likely that uploading the attachment
6928      // failed, we'll can retry with the same events payload
6929      if (retryConfig.count >= RETRY_MAX_COUNT) {
6930        const error = new Error(`${UNABLE_TO_SEND_REPLAY} - max retries exceeded`);
6931  
6932        try {
6933          // In case browsers don't allow this property to be writable
6934          // @ts-ignore This needs lib es2022 and newer
6935          error.cause = err;
6936        } catch (e) {
6937          // nothing to do
6938        }
6939  
6940        throw error;
6941      }
6942  
6943      // will retry in intervals of 5, 10, 30
6944      retryConfig.interval *= ++retryConfig.count;
6945  
6946      return new Promise((resolve, reject) => {
6947        setTimeout(async () => {
6948          try {
6949            await sendReplay(replayData, retryConfig);
6950            resolve(true);
6951          } catch (err) {
6952            reject(err);
6953          }
6954        }, retryConfig.interval);
6955      });
6956    }
6957  }
6958  
6959  const THROTTLED = '__THROTTLED';
6960  const SKIPPED = '__SKIPPED';
6961  
6962  /**
6963   * Create a throttled function off a given function.
6964   * When calling the throttled function, it will call the original function only
6965   * if it hasn't been called more than `maxCount` times in the last `durationSeconds`.
6966   *
6967   * Returns `THROTTLED` if throttled for the first time, after that `SKIPPED`,
6968   * or else the return value of the original function.
6969   */
6970  // eslint-disable-next-line @typescript-eslint/no-explicit-any
6971  function throttle(
6972    fn,
6973    maxCount,
6974    durationSeconds,
6975  ) {
6976    const counter = new Map();
6977  
6978    const _cleanup = (now) => {
6979      const threshold = now - durationSeconds;
6980      counter.forEach((_value, key) => {
6981        if (key < threshold) {
6982          counter.delete(key);
6983        }
6984      });
6985    };
6986  
6987    const _getTotalCount = () => {
6988      return [...counter.values()].reduce((a, b) => a + b, 0);
6989    };
6990  
6991    let isThrottled = false;
6992  
6993    return (...rest) => {
6994      // Date in second-precision, which we use as basis for the throttling
6995      const now = Math.floor(Date.now() / 1000);
6996  
6997      // First, make sure to delete any old entries
6998      _cleanup(now);
6999  
7000      // If already over limit, do nothing
7001      if (_getTotalCount() >= maxCount) {
7002        const wasThrottled = isThrottled;
7003        isThrottled = true;
7004        return wasThrottled ? SKIPPED : THROTTLED;
7005      }
7006  
7007      isThrottled = false;
7008      const count = counter.get(now) || 0;
7009      counter.set(now, count + 1);
7010  
7011      return fn(...rest);
7012    };
7013  }
7014  
7015  /* eslint-disable max-lines */ // TODO: We might want to split this file up
7016  
7017  /**
7018   * The main replay container class, which holds all the state and methods for recording and sending replays.
7019   */
7020  class ReplayContainer  {
7021     __init() {this.eventBuffer = null;}
7022  
7023    /**
7024     * List of PerformanceEntry from PerformanceObserver
7025     */
7026     __init2() {this.performanceEvents = [];}
7027  
7028    /**
7029     * Recording can happen in one of three modes:
7030     *   - session: Record the whole session, sending it continuously
7031     *   - buffer: Always keep the last 60s of recording, requires:
7032     *     - having replaysOnErrorSampleRate > 0 to capture replay when an error occurs
7033     *     - or calling `flush()` to send the replay
7034     */
7035     __init3() {this.recordingMode = 'session';}
7036  
7037    /**
7038     * The current or last active transcation.
7039     * This is only available when performance is enabled.
7040     */
7041  
7042    /**
7043     * These are here so we can overwrite them in tests etc.
7044     * @hidden
7045     */
7046      __init4() {this.timeouts = {
7047      sessionIdlePause: SESSION_IDLE_PAUSE_DURATION,
7048      sessionIdleExpire: SESSION_IDLE_EXPIRE_DURATION,
7049      maxSessionLife: MAX_SESSION_LIFE,
7050    }; }
7051  
7052    /**
7053     * Options to pass to `rrweb.record()`
7054     */
7055  
7056     __init5() {this._performanceObserver = null;}
7057  
7058     __init6() {this._flushLock = null;}
7059  
7060    /**
7061     * Timestamp of the last user activity. This lives across sessions.
7062     */
7063     __init7() {this._lastActivity = Date.now();}
7064  
7065    /**
7066     * Is the integration currently active?
7067     */
7068     __init8() {this._isEnabled = false;}
7069  
7070    /**
7071     * Paused is a state where:
7072     * - DOM Recording is not listening at all
7073     * - Nothing will be added to event buffer (e.g. core SDK events)
7074     */
7075     __init9() {this._isPaused = false;}
7076  
7077    /**
7078     * Have we attached listeners to the core SDK?
7079     * Note we have to track this as there is no way to remove instrumentation handlers.
7080     */
7081     __init10() {this._hasInitializedCoreListeners = false;}
7082  
7083    /**
7084     * Function to stop recording
7085     */
7086     __init11() {this._stopRecording = null;}
7087  
7088     __init12() {this._context = {
7089      errorIds: new Set(),
7090      traceIds: new Set(),
7091      urls: [],
7092      initialTimestamp: Date.now(),
7093      initialUrl: '',
7094    };}
7095  
7096     constructor({
7097      options,
7098      recordingOptions,
7099    }
7100  
7101  ) {ReplayContainer.prototype.__init.call(this);ReplayContainer.prototype.__init2.call(this);ReplayContainer.prototype.__init3.call(this);ReplayContainer.prototype.__init4.call(this);ReplayContainer.prototype.__init5.call(this);ReplayContainer.prototype.__init6.call(this);ReplayContainer.prototype.__init7.call(this);ReplayContainer.prototype.__init8.call(this);ReplayContainer.prototype.__init9.call(this);ReplayContainer.prototype.__init10.call(this);ReplayContainer.prototype.__init11.call(this);ReplayContainer.prototype.__init12.call(this);ReplayContainer.prototype.__init13.call(this);ReplayContainer.prototype.__init14.call(this);ReplayContainer.prototype.__init15.call(this);ReplayContainer.prototype.__init16.call(this);ReplayContainer.prototype.__init17.call(this);ReplayContainer.prototype.__init18.call(this);
7102      this._recordingOptions = recordingOptions;
7103      this._options = options;
7104  
7105      this._debouncedFlush = debounce(() => this._flush(), this._options.flushMinDelay, {
7106        maxWait: this._options.flushMaxDelay,
7107      });
7108  
7109      this._throttledAddEvent = throttle(
7110        (event, isCheckout) => addEvent(this, event, isCheckout),
7111        // Max 300 events...
7112        300,
7113        // ... per 5s
7114        5,
7115      );
7116  
7117      const { slowClickTimeout, slowClickIgnoreSelectors } = this.getOptions();
7118  
7119      const slowClickConfig = slowClickTimeout
7120        ? {
7121            threshold: Math.min(SLOW_CLICK_THRESHOLD, slowClickTimeout),
7122            timeout: slowClickTimeout,
7123            scrollTimeout: SLOW_CLICK_SCROLL_TIMEOUT,
7124            ignoreSelector: slowClickIgnoreSelectors ? slowClickIgnoreSelectors.join(',') : '',
7125            multiClickTimeout: MULTI_CLICK_TIMEOUT,
7126          }
7127        : undefined;
7128  
7129      if (slowClickConfig) {
7130        this.clickDetector = new ClickDetector(this, slowClickConfig);
7131      }
7132    }
7133  
7134    /** Get the event context. */
7135     getContext() {
7136      return this._context;
7137    }
7138  
7139    /** If recording is currently enabled. */
7140     isEnabled() {
7141      return this._isEnabled;
7142    }
7143  
7144    /** If recording is currently paused. */
7145     isPaused() {
7146      return this._isPaused;
7147    }
7148  
7149    /** Get the replay integration options. */
7150     getOptions() {
7151      return this._options;
7152    }
7153  
7154    /**
7155     * Initializes the plugin based on sampling configuration. Should not be
7156     * called outside of constructor.
7157     */
7158     initializeSampling() {
7159      const { errorSampleRate, sessionSampleRate } = this._options;
7160  
7161      // If neither sample rate is > 0, then do nothing - user will need to call one of
7162      // `start()` or `startBuffering` themselves.
7163      if (errorSampleRate <= 0 && sessionSampleRate <= 0) {
7164        return;
7165      }
7166  
7167      // Otherwise if there is _any_ sample rate set, try to load an existing
7168      // session, or create a new one.
7169      const isSessionSampled = this._loadAndCheckSession();
7170  
7171      if (!isSessionSampled) {
7172        // This should only occur if `errorSampleRate` is 0 and was unsampled for
7173        // session-based replay. In this case there is nothing to do.
7174        return;
7175      }
7176  
7177      if (!this.session) {
7178        // This should not happen, something wrong has occurred
7179        this._handleException(new Error('Unable to initialize and create session'));
7180        return;
7181      }
7182  
7183      if (this.session.sampled && this.session.sampled !== 'session') {
7184        // If not sampled as session-based, then recording mode will be `buffer`
7185        // Note that we don't explicitly check if `sampled === 'buffer'` because we
7186        // could have sessions from Session storage that are still `error` from
7187        // prior SDK version.
7188        this.recordingMode = 'buffer';
7189      }
7190  
7191      this._initializeRecording();
7192    }
7193  
7194    /**
7195     * Start a replay regardless of sampling rate. Calling this will always
7196     * create a new session. Will throw an error if replay is already in progress.
7197     *
7198     * Creates or loads a session, attaches listeners to varying events (DOM,
7199     * _performanceObserver, Recording, Sentry SDK, etc)
7200     */
7201     start() {
7202      if (this._isEnabled && this.recordingMode === 'session') {
7203        throw new Error('Replay recording is already in progress');
7204      }
7205  
7206      if (this._isEnabled && this.recordingMode === 'buffer') {
7207        throw new Error('Replay buffering is in progress, call `flush()` to save the replay');
7208      }
7209  
7210      const previousSessionId = this.session && this.session.id;
7211  
7212      const { session } = getSession({
7213        timeouts: this.timeouts,
7214        stickySession: Boolean(this._options.stickySession),
7215        currentSession: this.session,
7216        // This is intentional: create a new session-based replay when calling `start()`
7217        sessionSampleRate: 1,
7218        allowBuffering: false,
7219      });
7220  
7221      session.previousSessionId = previousSessionId;
7222      this.session = session;
7223  
7224      this._initializeRecording();
7225    }
7226  
7227    /**
7228     * Start replay buffering. Buffers until `flush()` is called or, if
7229     * `replaysOnErrorSampleRate` > 0, an error occurs.
7230     */
7231     startBuffering() {
7232      if (this._isEnabled) {
7233        throw new Error('Replay recording is already in progress');
7234      }
7235  
7236      const previousSessionId = this.session && this.session.id;
7237  
7238      const { session } = getSession({
7239        timeouts: this.timeouts,
7240        stickySession: Boolean(this._options.stickySession),
7241        currentSession: this.session,
7242        sessionSampleRate: 0,
7243        allowBuffering: true,
7244      });
7245  
7246      session.previousSessionId = previousSessionId;
7247      this.session = session;
7248  
7249      this.recordingMode = 'buffer';
7250      this._initializeRecording();
7251    }
7252  
7253    /**
7254     * Start recording.
7255     *
7256     * Note that this will cause a new DOM checkout
7257     */
7258     startRecording() {
7259      try {
7260        this._stopRecording = record({
7261          ...this._recordingOptions,
7262          // When running in error sampling mode, we need to overwrite `checkoutEveryNms`
7263          // Without this, it would record forever, until an error happens, which we don't want
7264          // instead, we'll always keep the last 60 seconds of replay before an error happened
7265          ...(this.recordingMode === 'buffer' && { checkoutEveryNms: BUFFER_CHECKOUT_TIME }),
7266          emit: getHandleRecordingEmit(this),
7267          onMutation: this._onMutationHandler,
7268        });
7269      } catch (err) {
7270        this._handleException(err);
7271      }
7272    }
7273  
7274    /**
7275     * Stops the recording, if it was running.
7276     *
7277     * Returns true if it was previously stopped, or is now stopped,
7278     * otherwise false.
7279     */
7280     stopRecording() {
7281      try {
7282        if (this._stopRecording) {
7283          this._stopRecording();
7284          this._stopRecording = undefined;
7285        }
7286  
7287        return true;
7288      } catch (err) {
7289        this._handleException(err);
7290        return false;
7291      }
7292    }
7293  
7294    /**
7295     * Currently, this needs to be manually called (e.g. for tests). Sentry SDK
7296     * does not support a teardown
7297     */
7298     async stop(reason) {
7299      if (!this._isEnabled) {
7300        return;
7301      }
7302  
7303      try {
7304        if ((typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__)) {
7305          const msg = `[Replay] Stopping Replay${reason ? ` triggered by ${reason}` : ''}`;
7306  
7307          // When `traceInternals` is enabled, we want to log this to the console
7308          // Else, use the regular debug output
7309          // eslint-disable-next-line
7310          const log = this.getOptions()._experiments.traceInternals ? console.warn : logger.log;
7311          log(msg);
7312        }
7313  
7314        // We can't move `_isEnabled` after awaiting a flush, otherwise we can
7315        // enter into an infinite loop when `stop()` is called while flushing.
7316        this._isEnabled = false;
7317        this._removeListeners();
7318        this.stopRecording();
7319  
7320        this._debouncedFlush.cancel();
7321        // See comment above re: `_isEnabled`, we "force" a flush, ignoring the
7322        // `_isEnabled` state of the plugin since it was disabled above.
7323        if (this.recordingMode === 'session') {
7324          await this._flush({ force: true });
7325        }
7326  
7327        // After flush, destroy event buffer
7328        this.eventBuffer && this.eventBuffer.destroy();
7329        this.eventBuffer = null;
7330  
7331        // Clear session from session storage, note this means if a new session
7332        // is started after, it will not have `previousSessionId`
7333        clearSession(this);
7334      } catch (err) {
7335        this._handleException(err);
7336      }
7337    }
7338  
7339    /**
7340     * Pause some replay functionality. See comments for `_isPaused`.
7341     * This differs from stop as this only stops DOM recording, it is
7342     * not as thorough of a shutdown as `stop()`.
7343     */
7344     pause() {
7345      this._isPaused = true;
7346      this.stopRecording();
7347    }
7348  
7349    /**
7350     * Resumes recording, see notes for `pause().
7351     *
7352     * Note that calling `startRecording()` here will cause a
7353     * new DOM checkout.`
7354     */
7355     resume() {
7356      if (!this._loadAndCheckSession()) {
7357        return;
7358      }
7359  
7360      this._isPaused = false;
7361      this.startRecording();
7362    }
7363  
7364    /**
7365     * If not in "session" recording mode, flush event buffer which will create a new replay.
7366     * Unless `continueRecording` is false, the replay will continue to record and
7367     * behave as a "session"-based replay.
7368     *
7369     * Otherwise, queue up a flush.
7370     */
7371     async sendBufferedReplayOrFlush({ continueRecording = true } = {}) {
7372      if (this.recordingMode === 'session') {
7373        return this.flushImmediate();
7374      }
7375  
7376      const activityTime = Date.now();
7377  
7378      // Allow flush to complete before resuming as a session recording, otherwise
7379      // the checkout from `startRecording` may be included in the payload.
7380      // Prefer to keep the error replay as a separate (and smaller) segment
7381      // than the session replay.
7382      await this.flushImmediate();
7383  
7384      const hasStoppedRecording = this.stopRecording();
7385  
7386      if (!continueRecording || !hasStoppedRecording) {
7387        return;
7388      }
7389  
7390      // Re-start recording, but in "session" recording mode
7391  
7392      // Reset all "capture on error" configuration before
7393      // starting a new recording
7394      this.recordingMode = 'session';
7395  
7396      // Once this session ends, we do not want to refresh it
7397      if (this.session) {
7398        this.session.shouldRefresh = false;
7399  
7400        // It's possible that the session lifespan is > max session lifespan
7401        // because we have been buffering beyond max session lifespan (we ignore
7402        // expiration given that `shouldRefresh` is true). Since we flip
7403        // `shouldRefresh`, the session could be considered expired due to
7404        // lifespan, which is not what we want. Update session start date to be
7405        // the current timestamp, so that session is not considered to be
7406        // expired. This means that max replay duration can be MAX_SESSION_LIFE +
7407        // (length of buffer), which we are ok with.
7408        this._updateUserActivity(activityTime);
7409        this._updateSessionActivity(activityTime);
7410        this.session.started = activityTime;
7411        this._maybeSaveSession();
7412      }
7413  
7414      this.startRecording();
7415    }
7416  
7417    /**
7418     * We want to batch uploads of replay events. Save events only if
7419     * `<flushMinDelay>` milliseconds have elapsed since the last event
7420     * *OR* if `<flushMaxDelay>` milliseconds have elapsed.
7421     *
7422     * Accepts a callback to perform side-effects and returns true to stop batch
7423     * processing and hand back control to caller.
7424     */
7425     addUpdate(cb) {
7426      // We need to always run `cb` (e.g. in the case of `this.recordingMode == 'buffer'`)
7427      const cbResult = cb();
7428  
7429      // If this option is turned on then we will only want to call `flush`
7430      // explicitly
7431      if (this.recordingMode === 'buffer') {
7432        return;
7433      }
7434  
7435      // If callback is true, we do not want to continue with flushing -- the
7436      // caller will need to handle it.
7437      if (cbResult === true) {
7438        return;
7439      }
7440  
7441      // addUpdate is called quite frequently - use _debouncedFlush so that it
7442      // respects the flush delays and does not flush immediately
7443      this._debouncedFlush();
7444    }
7445  
7446    /**
7447     * Updates the user activity timestamp and resumes recording. This should be
7448     * called in an event handler for a user action that we consider as the user
7449     * being "active" (e.g. a mouse click).
7450     */
7451     triggerUserActivity() {
7452      this._updateUserActivity();
7453  
7454      // This case means that recording was once stopped due to inactivity.
7455      // Ensure that recording is resumed.
7456      if (!this._stopRecording) {
7457        // Create a new session, otherwise when the user action is flushed, it
7458        // will get rejected due to an expired session.
7459        if (!this._loadAndCheckSession()) {
7460          return;
7461        }
7462  
7463        // Note: This will cause a new DOM checkout
7464        this.resume();
7465        return;
7466      }
7467  
7468      // Otherwise... recording was never suspended, continue as normalish
7469      this.checkAndHandleExpiredSession();
7470  
7471      this._updateSessionActivity();
7472    }
7473  
7474    /**
7475     * Updates the user activity timestamp *without* resuming
7476     * recording. Some user events (e.g. keydown) can be create
7477     * low-value replays that only contain the keypress as a
7478     * breadcrumb. Instead this would require other events to
7479     * create a new replay after a session has expired.
7480     */
7481     updateUserActivity() {
7482      this._updateUserActivity();
7483      this._updateSessionActivity();
7484    }
7485  
7486    /**
7487     * Only flush if `this.recordingMode === 'session'`
7488     */
7489     conditionalFlush() {
7490      if (this.recordingMode === 'buffer') {
7491        return Promise.resolve();
7492      }
7493  
7494      return this.flushImmediate();
7495    }
7496  
7497    /**
7498     * Flush using debounce flush
7499     */
7500     flush() {
7501      return this._debouncedFlush() ;
7502    }
7503  
7504    /**
7505     * Always flush via `_debouncedFlush` so that we do not have flushes triggered
7506     * from calling both `flush` and `_debouncedFlush`. Otherwise, there could be
7507     * cases of mulitple flushes happening closely together.
7508     */
7509     flushImmediate() {
7510      this._debouncedFlush();
7511      // `.flush` is provided by the debounced function, analogously to lodash.debounce
7512      return this._debouncedFlush.flush() ;
7513    }
7514  
7515    /**
7516     * Cancels queued up flushes.
7517     */
7518     cancelFlush() {
7519      this._debouncedFlush.cancel();
7520    }
7521  
7522    /** Get the current sesion (=replay) ID */
7523     getSessionId() {
7524      return this.session && this.session.id;
7525    }
7526  
7527    /**
7528     * Checks if recording should be stopped due to user inactivity. Otherwise
7529     * check if session is expired and create a new session if so. Triggers a new
7530     * full snapshot on new session.
7531     *
7532     * Returns true if session is not expired, false otherwise.
7533     * @hidden
7534     */
7535     checkAndHandleExpiredSession() {
7536      const oldSessionId = this.getSessionId();
7537  
7538      // Prevent starting a new session if the last user activity is older than
7539      // SESSION_IDLE_PAUSE_DURATION. Otherwise non-user activity can trigger a new
7540      // session+recording. This creates noisy replays that do not have much
7541      // content in them.
7542      if (
7543        this._lastActivity &&
7544        isExpired(this._lastActivity, this.timeouts.sessionIdlePause) &&
7545        this.session &&
7546        this.session.sampled === 'session'
7547      ) {
7548        // Pause recording only for session-based replays. Otherwise, resuming
7549        // will create a new replay and will conflict with users who only choose
7550        // to record error-based replays only. (e.g. the resumed replay will not
7551        // contain a reference to an error)
7552        this.pause();
7553        return;
7554      }
7555  
7556      // --- There is recent user activity --- //
7557      // This will create a new session if expired, based on expiry length
7558      if (!this._loadAndCheckSession()) {
7559        return;
7560      }
7561  
7562      // Session was expired if session ids do not match
7563      const expired = oldSessionId !== this.getSessionId();
7564  
7565      if (!expired) {
7566        return true;
7567      }
7568  
7569      // Session is expired, trigger a full snapshot (which will create a new session)
7570      this._triggerFullSnapshot();
7571  
7572      return false;
7573    }
7574  
7575    /**
7576     * Capture some initial state that can change throughout the lifespan of the
7577     * replay. This is required because otherwise they would be captured at the
7578     * first flush.
7579     */
7580     setInitialState() {
7581      const urlPath = `${WINDOW.location.pathname}${WINDOW.location.hash}${WINDOW.location.search}`;
7582      const url = `${WINDOW.location.origin}${urlPath}`;
7583  
7584      this.performanceEvents = [];
7585  
7586      // Reset _context as well
7587      this._clearContext();
7588  
7589      this._context.initialUrl = url;
7590      this._context.initialTimestamp = Date.now();
7591      this._context.urls.push(url);
7592    }
7593  
7594    /**
7595     * Add a breadcrumb event, that may be throttled.
7596     * If it was throttled, we add a custom breadcrumb to indicate that.
7597     */
7598     throttledAddEvent(
7599      event,
7600      isCheckout,
7601    ) {
7602      const res = this._throttledAddEvent(event, isCheckout);
7603  
7604      // If this is THROTTLED, it means we have throttled the event for the first time
7605      // In this case, we want to add a breadcrumb indicating that something was skipped
7606      if (res === THROTTLED) {
7607        const breadcrumb = createBreadcrumb({
7608          category: 'replay.throttled',
7609        });
7610  
7611        this.addUpdate(() => {
7612          void addEvent(this, {
7613            type: EventType.Custom,
7614            timestamp: breadcrumb.timestamp || 0,
7615            data: {
7616              tag: 'breadcrumb',
7617              payload: breadcrumb,
7618              metric: true,
7619            },
7620          });
7621        });
7622      }
7623  
7624      return res;
7625    }
7626  
7627    /**
7628     * This will get the parametrized route name of the current page.
7629     * This is only available if performance is enabled, and if an instrumented router is used.
7630     */
7631     getCurrentRoute() {
7632      const lastTransaction = this.lastTransaction || getCurrentHub().getScope().getTransaction();
7633      if (!lastTransaction || !['route', 'custom'].includes(lastTransaction.metadata.source)) {
7634        return undefined;
7635      }
7636  
7637      return lastTransaction.name;
7638    }
7639  
7640    /**
7641     * Initialize and start all listeners to varying events (DOM,
7642     * Performance Observer, Recording, Sentry SDK, etc)
7643     */
7644     _initializeRecording() {
7645      this.setInitialState();
7646  
7647      // this method is generally called on page load or manually - in both cases
7648      // we should treat it as an activity
7649      this._updateSessionActivity();
7650  
7651      this.eventBuffer = createEventBuffer({
7652        useCompression: this._options.useCompression,
7653      });
7654  
7655      this._removeListeners();
7656      this._addListeners();
7657  
7658      // Need to set as enabled before we start recording, as `record()` can trigger a flush with a new checkout
7659      this._isEnabled = true;
7660  
7661      this.startRecording();
7662    }
7663  
7664    /** A wrapper to conditionally capture exceptions. */
7665     _handleException(error) {
7666      (typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && logger.error('[Replay]', error);
7667  
7668      if ((typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && this._options._experiments && this._options._experiments.captureExceptions) {
7669        captureException(error);
7670      }
7671    }
7672  
7673    /**
7674     * Loads (or refreshes) the current session.
7675     * Returns false if session is not recorded.
7676     */
7677     _loadAndCheckSession() {
7678      const { type, session } = getSession({
7679        timeouts: this.timeouts,
7680        stickySession: Boolean(this._options.stickySession),
7681        currentSession: this.session,
7682        sessionSampleRate: this._options.sessionSampleRate,
7683        allowBuffering: this._options.errorSampleRate > 0 || this.recordingMode === 'buffer',
7684      });
7685  
7686      // If session was newly created (i.e. was not loaded from storage), then
7687      // enable flag to create the root replay
7688      if (type === 'new') {
7689        this.setInitialState();
7690      }
7691  
7692      const currentSessionId = this.getSessionId();
7693      if (session.id !== currentSessionId) {
7694        session.previousSessionId = currentSessionId;
7695      }
7696  
7697      this.session = session;
7698  
7699      if (!this.session.sampled) {
7700        void this.stop('session unsampled');
7701        return false;
7702      }
7703  
7704      return true;
7705    }
7706  
7707    /**
7708     * Adds listeners to record events for the replay
7709     */
7710     _addListeners() {
7711      try {
7712        WINDOW.document.addEventListener('visibilitychange', this._handleVisibilityChange);
7713        WINDOW.addEventListener('blur', this._handleWindowBlur);
7714        WINDOW.addEventListener('focus', this._handleWindowFocus);
7715        WINDOW.addEventListener('keydown', this._handleKeyboardEvent);
7716  
7717        if (this.clickDetector) {
7718          this.clickDetector.addListeners();
7719        }
7720  
7721        // There is no way to remove these listeners, so ensure they are only added once
7722        if (!this._hasInitializedCoreListeners) {
7723          addGlobalListeners(this);
7724  
7725          this._hasInitializedCoreListeners = true;
7726        }
7727      } catch (err) {
7728        this._handleException(err);
7729      }
7730  
7731      // PerformanceObserver //
7732      if (!('PerformanceObserver' in WINDOW)) {
7733        return;
7734      }
7735  
7736      this._performanceObserver = setupPerformanceObserver(this);
7737    }
7738  
7739    /**
7740     * Cleans up listeners that were created in `_addListeners`
7741     */
7742     _removeListeners() {
7743      try {
7744        WINDOW.document.removeEventListener('visibilitychange', this._handleVisibilityChange);
7745  
7746        WINDOW.removeEventListener('blur', this._handleWindowBlur);
7747        WINDOW.removeEventListener('focus', this._handleWindowFocus);
7748        WINDOW.removeEventListener('keydown', this._handleKeyboardEvent);
7749  
7750        if (this.clickDetector) {
7751          this.clickDetector.removeListeners();
7752        }
7753  
7754        if (this._performanceObserver) {
7755          this._performanceObserver.disconnect();
7756          this._performanceObserver = null;
7757        }
7758      } catch (err) {
7759        this._handleException(err);
7760      }
7761    }
7762  
7763    /**
7764     * Handle when visibility of the page content changes. Opening a new tab will
7765     * cause the state to change to hidden because of content of current page will
7766     * be hidden. Likewise, moving a different window to cover the contents of the
7767     * page will also trigger a change to a hidden state.
7768     */
7769     __init13() {this._handleVisibilityChange = () => {
7770      if (WINDOW.document.visibilityState === 'visible') {
7771        this._doChangeToForegroundTasks();
7772      } else {
7773        this._doChangeToBackgroundTasks();
7774      }
7775    };}
7776  
7777    /**
7778     * Handle when page is blurred
7779     */
7780     __init14() {this._handleWindowBlur = () => {
7781      const breadcrumb = createBreadcrumb({
7782        category: 'ui.blur',
7783      });
7784  
7785      // Do not count blur as a user action -- it's part of the process of them
7786      // leaving the page
7787      this._doChangeToBackgroundTasks(breadcrumb);
7788    };}
7789  
7790    /**
7791     * Handle when page is focused
7792     */
7793     __init15() {this._handleWindowFocus = () => {
7794      const breadcrumb = createBreadcrumb({
7795        category: 'ui.focus',
7796      });
7797  
7798      // Do not count focus as a user action -- instead wait until they focus and
7799      // interactive with page
7800      this._doChangeToForegroundTasks(breadcrumb);
7801    };}
7802  
7803    /** Ensure page remains active when a key is pressed. */
7804     __init16() {this._handleKeyboardEvent = (event) => {
7805      handleKeyboardEvent(this, event);
7806    };}
7807  
7808    /**
7809     * Tasks to run when we consider a page to be hidden (via blurring and/or visibility)
7810     */
7811     _doChangeToBackgroundTasks(breadcrumb) {
7812      if (!this.session) {
7813        return;
7814      }
7815  
7816      const expired = isSessionExpired(this.session, this.timeouts);
7817  
7818      if (breadcrumb && !expired) {
7819        this._createCustomBreadcrumb(breadcrumb);
7820      }
7821  
7822      // Send replay when the page/tab becomes hidden. There is no reason to send
7823      // replay if it becomes visible, since no actions we care about were done
7824      // while it was hidden
7825      void this.conditionalFlush();
7826    }
7827  
7828    /**
7829     * Tasks to run when we consider a page to be visible (via focus and/or visibility)
7830     */
7831     _doChangeToForegroundTasks(breadcrumb) {
7832      if (!this.session) {
7833        return;
7834      }
7835  
7836      const isSessionActive = this.checkAndHandleExpiredSession();
7837  
7838      if (!isSessionActive) {
7839        // If the user has come back to the page within SESSION_IDLE_PAUSE_DURATION
7840        // ms, we will re-use the existing session, otherwise create a new
7841        // session
7842        (typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && logger.log('[Replay] Document has become active, but session has expired');
7843        return;
7844      }
7845  
7846      if (breadcrumb) {
7847        this._createCustomBreadcrumb(breadcrumb);
7848      }
7849    }
7850  
7851    /**
7852     * Trigger rrweb to take a full snapshot which will cause this plugin to
7853     * create a new Replay event.
7854     */
7855     _triggerFullSnapshot(checkout = true) {
7856      try {
7857        (typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && logger.log('[Replay] Taking full rrweb snapshot');
7858        record.takeFullSnapshot(checkout);
7859      } catch (err) {
7860        this._handleException(err);
7861      }
7862    }
7863  
7864    /**
7865     * Update user activity (across session lifespans)
7866     */
7867     _updateUserActivity(_lastActivity = Date.now()) {
7868      this._lastActivity = _lastActivity;
7869    }
7870  
7871    /**
7872     * Updates the session's last activity timestamp
7873     */
7874     _updateSessionActivity(_lastActivity = Date.now()) {
7875      if (this.session) {
7876        this.session.lastActivity = _lastActivity;
7877        this._maybeSaveSession();
7878      }
7879    }
7880  
7881    /**
7882     * Helper to create (and buffer) a replay breadcrumb from a core SDK breadcrumb
7883     */
7884     _createCustomBreadcrumb(breadcrumb) {
7885      this.addUpdate(() => {
7886        void this.throttledAddEvent({
7887          type: EventType.Custom,
7888          timestamp: breadcrumb.timestamp || 0,
7889          data: {
7890            tag: 'breadcrumb',
7891            payload: breadcrumb,
7892          },
7893        });
7894      });
7895    }
7896  
7897    /**
7898     * Observed performance events are added to `this.performanceEvents`. These
7899     * are included in the replay event before it is finished and sent to Sentry.
7900     */
7901     _addPerformanceEntries() {
7902      // Copy and reset entries before processing
7903      const entries = [...this.performanceEvents];
7904      this.performanceEvents = [];
7905  
7906      return Promise.all(createPerformanceSpans(this, createPerformanceEntries(entries)));
7907    }
7908  
7909    /**
7910     * Clear _context
7911     */
7912     _clearContext() {
7913      // XXX: `initialTimestamp` and `initialUrl` do not get cleared
7914      this._context.errorIds.clear();
7915      this._context.traceIds.clear();
7916      this._context.urls = [];
7917    }
7918  
7919    /** Update the initial timestamp based on the buffer content. */
7920     _updateInitialTimestampFromEventBuffer() {
7921      const { session, eventBuffer } = this;
7922      if (!session || !eventBuffer) {
7923        return;
7924      }
7925  
7926      // we only ever update this on the initial segment
7927      if (session.segmentId) {
7928        return;
7929      }
7930  
7931      const earliestEvent = eventBuffer.getEarliestTimestamp();
7932      if (earliestEvent && earliestEvent < this._context.initialTimestamp) {
7933        this._context.initialTimestamp = earliestEvent;
7934      }
7935    }
7936  
7937    /**
7938     * Return and clear _context
7939     */
7940     _popEventContext() {
7941      const _context = {
7942        initialTimestamp: this._context.initialTimestamp,
7943        initialUrl: this._context.initialUrl,
7944        errorIds: Array.from(this._context.errorIds),
7945        traceIds: Array.from(this._context.traceIds),
7946        urls: this._context.urls,
7947      };
7948  
7949      this._clearContext();
7950  
7951      return _context;
7952    }
7953  
7954    /**
7955     * Flushes replay event buffer to Sentry.
7956     *
7957     * Performance events are only added right before flushing - this is
7958     * due to the buffered performance observer events.
7959     *
7960     * Should never be called directly, only by `flush`
7961     */
7962     async _runFlush() {
7963      if (!this.session || !this.eventBuffer) {
7964        (typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && logger.error('[Replay] No session or eventBuffer found to flush.');
7965        return;
7966      }
7967  
7968      await this._addPerformanceEntries();
7969  
7970      // Check eventBuffer again, as it could have been stopped in the meanwhile
7971      if (!this.eventBuffer || !this.eventBuffer.hasEvents) {
7972        return;
7973      }
7974  
7975      // Only attach memory event if eventBuffer is not empty
7976      await addMemoryEntry(this);
7977  
7978      // Check eventBuffer again, as it could have been stopped in the meanwhile
7979      if (!this.eventBuffer) {
7980        return;
7981      }
7982  
7983      try {
7984        // This uses the data from the eventBuffer, so we need to call this before `finish()
7985        this._updateInitialTimestampFromEventBuffer();
7986  
7987        // Note this empties the event buffer regardless of outcome of sending replay
7988        const recordingData = await this.eventBuffer.finish();
7989  
7990        // NOTE: Copy values from instance members, as it's possible they could
7991        // change before the flush finishes.
7992        const replayId = this.session.id;
7993        const eventContext = this._popEventContext();
7994        // Always increment segmentId regardless of outcome of sending replay
7995        const segmentId = this.session.segmentId++;
7996        this._maybeSaveSession();
7997  
7998        await sendReplay({
7999          replayId,
8000          recordingData,
8001          segmentId,
8002          eventContext,
8003          session: this.session,
8004          options: this.getOptions(),
8005          timestamp: Date.now(),
8006        });
8007      } catch (err) {
8008        this._handleException(err);
8009  
8010        // This means we retried 3 times and all of them failed,
8011        // or we ran into a problem we don't want to retry, like rate limiting.
8012        // In this case, we want to completely stop the replay - otherwise, we may get inconsistent segments
8013        void this.stop('sendReplay');
8014  
8015        const client = getCurrentHub().getClient();
8016  
8017        if (client) {
8018          client.recordDroppedEvent('send_error', 'replay');
8019        }
8020      }
8021    }
8022  
8023    /**
8024     * Flush recording data to Sentry. Creates a lock so that only a single flush
8025     * can be active at a time. Do not call this directly.
8026     */
8027     __init17() {this._flush = async ({
8028      force = false,
8029    }
8030  
8031   = {}) => {
8032      if (!this._isEnabled && !force) {
8033        // This can happen if e.g. the replay was stopped because of exceeding the retry limit
8034        return;
8035      }
8036  
8037      if (!this.checkAndHandleExpiredSession()) {
8038        (typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && logger.error('[Replay] Attempting to finish replay event after session expired.');
8039        return;
8040      }
8041  
8042      if (!this.session) {
8043        (typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && logger.error('[Replay] No session found to flush.');
8044        return;
8045      }
8046  
8047      // A flush is about to happen, cancel any queued flushes
8048      this._debouncedFlush.cancel();
8049  
8050      // this._flushLock acts as a lock so that future calls to `_flush()`
8051      // will be blocked until this promise resolves
8052      if (!this._flushLock) {
8053        this._flushLock = this._runFlush();
8054        await this._flushLock;
8055        this._flushLock = null;
8056        return;
8057      }
8058  
8059      // Wait for previous flush to finish, then call the debounced `_flush()`.
8060      // It's possible there are other flush requests queued and waiting for it
8061      // to resolve. We want to reduce all outstanding requests (as well as any
8062      // new flush requests that occur within a second of the locked flush
8063      // completing) into a single flush.
8064  
8065      try {
8066        await this._flushLock;
8067      } catch (err) {
8068        (typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && logger.error(err);
8069      } finally {
8070        this._debouncedFlush();
8071      }
8072    };}
8073  
8074    /** Save the session, if it is sticky */
8075     _maybeSaveSession() {
8076      if (this.session && this._options.stickySession) {
8077        saveSession(this.session);
8078      }
8079    }
8080  
8081    /** Handler for rrweb.record.onMutation */
8082     __init18() {this._onMutationHandler = (mutations) => {
8083      const count = mutations.length;
8084  
8085      const mutationLimit = this._options.mutationLimit;
8086      const mutationBreadcrumbLimit = this._options.mutationBreadcrumbLimit;
8087      const overMutationLimit = mutationLimit && count > mutationLimit;
8088  
8089      // Create a breadcrumb if a lot of mutations happen at the same time
8090      // We can show this in the UI as an information with potential performance improvements
8091      if (count > mutationBreadcrumbLimit || overMutationLimit) {
8092        const breadcrumb = createBreadcrumb({
8093          category: 'replay.mutations',
8094          data: {
8095            count,
8096            limit: overMutationLimit,
8097          },
8098        });
8099        this._createCustomBreadcrumb(breadcrumb);
8100      }
8101  
8102      // Stop replay if over the mutation limit
8103      if (overMutationLimit) {
8104        void this.stop('mutationLimit');
8105        return false;
8106      }
8107  
8108      // `true` means we use the regular mutation handling by rrweb
8109      return true;
8110    };}
8111  }
8112  
8113  function getOption(
8114    selectors,
8115    defaultSelectors,
8116    deprecatedClassOption,
8117    deprecatedSelectorOption,
8118  ) {
8119    const deprecatedSelectors = typeof deprecatedSelectorOption === 'string' ? deprecatedSelectorOption.split(',') : [];
8120  
8121    const allSelectors = [
8122      ...selectors,
8123      // @deprecated
8124      ...deprecatedSelectors,
8125  
8126      // sentry defaults
8127      ...defaultSelectors,
8128    ];
8129  
8130    // @deprecated
8131    if (typeof deprecatedClassOption !== 'undefined') {
8132      // NOTE: No support for RegExp
8133      if (typeof deprecatedClassOption === 'string') {
8134        allSelectors.push(`.${deprecatedClassOption}`);
8135      }
8136  
8137      // eslint-disable-next-line no-console
8138      console.warn(
8139        '[Replay] You are using a deprecated configuration item for privacy. Read the documentation on how to use the new privacy configuration.',
8140      );
8141    }
8142  
8143    return allSelectors.join(',');
8144  }
8145  
8146  /**
8147   * Returns privacy related configuration for use in rrweb
8148   */
8149  function getPrivacyOptions({
8150    mask,
8151    unmask,
8152    block,
8153    unblock,
8154    ignore,
8155  
8156    // eslint-disable-next-line deprecation/deprecation
8157    blockClass,
8158    // eslint-disable-next-line deprecation/deprecation
8159    blockSelector,
8160    // eslint-disable-next-line deprecation/deprecation
8161    maskTextClass,
8162    // eslint-disable-next-line deprecation/deprecation
8163    maskTextSelector,
8164    // eslint-disable-next-line deprecation/deprecation
8165    ignoreClass,
8166  }) {
8167    const defaultBlockedElements = ['base[href="/"]'];
8168  
8169    const maskSelector = getOption(mask, ['.sentry-mask', '[data-sentry-mask]'], maskTextClass, maskTextSelector);
8170    const unmaskSelector = getOption(unmask, ['.sentry-unmask', '[data-sentry-unmask]']);
8171  
8172    const options = {
8173      // We are making the decision to make text and input selectors the same
8174      maskTextSelector: maskSelector,
8175      unmaskTextSelector: unmaskSelector,
8176      maskInputSelector: maskSelector,
8177      unmaskInputSelector: unmaskSelector,
8178  
8179      blockSelector: getOption(
8180        block,
8181        ['.sentry-block', '[data-sentry-block]', ...defaultBlockedElements],
8182        blockClass,
8183        blockSelector,
8184      ),
8185      unblockSelector: getOption(unblock, ['.sentry-unblock', '[data-sentry-unblock]']),
8186      ignoreSelector: getOption(ignore, ['.sentry-ignore', '[data-sentry-ignore]', 'input[type="file"]'], ignoreClass),
8187    };
8188  
8189    if (blockClass instanceof RegExp) {
8190      options.blockClass = blockClass;
8191    }
8192  
8193    if (maskTextClass instanceof RegExp) {
8194      options.maskTextClass = maskTextClass;
8195    }
8196  
8197    return options;
8198  }
8199  
8200  /**
8201   * Returns true if we are in the browser.
8202   */
8203  function isBrowser() {
8204    // eslint-disable-next-line no-restricted-globals
8205    return typeof window !== 'undefined' && (!isNodeEnv() || isElectronNodeRenderer());
8206  }
8207  
8208  // Electron renderers with nodeIntegration enabled are detected as Node.js so we specifically test for them
8209  function isElectronNodeRenderer() {
8210    return typeof process !== 'undefined' && (process ).type === 'renderer';
8211  }
8212  
8213  const MEDIA_SELECTORS =
8214    'img,image,svg,video,object,picture,embed,map,audio,link[rel="icon"],link[rel="apple-touch-icon"]';
8215  
8216  const DEFAULT_NETWORK_HEADERS = ['content-length', 'content-type', 'accept'];
8217  
8218  let _initialized = false;
8219  
8220  /**
8221   * The main replay integration class, to be passed to `init({  integrations: [] })`.
8222   */
8223  class Replay  {
8224    /**
8225     * @inheritDoc
8226     */
8227     static __initStatic() {this.id = 'Replay';}
8228  
8229    /**
8230     * @inheritDoc
8231     */
8232     __init() {this.name = Replay.id;}
8233  
8234    /**
8235     * Options to pass to `rrweb.record()`
8236     */
8237  
8238    /**
8239     * Initial options passed to the replay integration, merged with default values.
8240     * Note: `sessionSampleRate` and `errorSampleRate` are not required here, as they
8241     * can only be finally set when setupOnce() is called.
8242     *
8243     * @private
8244     */
8245  
8246     constructor({
8247      flushMinDelay = DEFAULT_FLUSH_MIN_DELAY,
8248      flushMaxDelay = DEFAULT_FLUSH_MAX_DELAY,
8249      stickySession = true,
8250      useCompression = true,
8251      _experiments = {},
8252      sessionSampleRate,
8253      errorSampleRate,
8254      maskAllText = true,
8255      maskAllInputs = true,
8256      blockAllMedia = true,
8257  
8258      mutationBreadcrumbLimit = 750,
8259      mutationLimit = 10000,
8260  
8261      slowClickTimeout = 7000,
8262      slowClickIgnoreSelectors = [],
8263  
8264      networkDetailAllowUrls = [],
8265      networkCaptureBodies = true,
8266      networkRequestHeaders = [],
8267      networkResponseHeaders = [],
8268  
8269      mask = [],
8270      unmask = [],
8271      block = [],
8272      unblock = [],
8273      ignore = [],
8274      maskFn,
8275  
8276      beforeAddRecordingEvent,
8277  
8278      // eslint-disable-next-line deprecation/deprecation
8279      blockClass,
8280      // eslint-disable-next-line deprecation/deprecation
8281      blockSelector,
8282      // eslint-disable-next-line deprecation/deprecation
8283      maskInputOptions,
8284      // eslint-disable-next-line deprecation/deprecation
8285      maskTextClass,
8286      // eslint-disable-next-line deprecation/deprecation
8287      maskTextSelector,
8288      // eslint-disable-next-line deprecation/deprecation
8289      ignoreClass,
8290    } = {}) {Replay.prototype.__init.call(this);
8291      this._recordingOptions = {
8292        maskAllInputs,
8293        maskAllText,
8294        maskInputOptions: { ...(maskInputOptions || {}), password: true },
8295        maskTextFn: maskFn,
8296        maskInputFn: maskFn,
8297  
8298        ...getPrivacyOptions({
8299          mask,
8300          unmask,
8301          block,
8302          unblock,
8303          ignore,
8304          blockClass,
8305          blockSelector,
8306          maskTextClass,
8307          maskTextSelector,
8308          ignoreClass,
8309        }),
8310  
8311        // Our defaults
8312        slimDOMOptions: 'all',
8313        inlineStylesheet: true,
8314        // Disable inline images as it will increase segment/replay size
8315        inlineImages: false,
8316        // collect fonts, but be aware that `sentry.io` needs to be an allowed
8317        // origin for playback
8318        collectFonts: true,
8319      };
8320  
8321      this._initialOptions = {
8322        flushMinDelay,
8323        flushMaxDelay,
8324        stickySession,
8325        sessionSampleRate,
8326        errorSampleRate,
8327        useCompression,
8328        blockAllMedia,
8329        maskAllInputs,
8330        maskAllText,
8331        mutationBreadcrumbLimit,
8332        mutationLimit,
8333        slowClickTimeout,
8334        slowClickIgnoreSelectors,
8335        networkDetailAllowUrls,
8336        networkCaptureBodies,
8337        networkRequestHeaders: _getMergedNetworkHeaders(networkRequestHeaders),
8338        networkResponseHeaders: _getMergedNetworkHeaders(networkResponseHeaders),
8339        beforeAddRecordingEvent,
8340  
8341        _experiments,
8342      };
8343  
8344      if (typeof sessionSampleRate === 'number') {
8345        // eslint-disable-next-line
8346        console.warn(
8347          `[Replay] You are passing \`sessionSampleRate\` to the Replay integration.
8348  This option is deprecated and will be removed soon.
8349  Instead, configure \`replaysSessionSampleRate\` directly in the SDK init options, e.g.:
8350  Sentry.init({ replaysSessionSampleRate: ${sessionSampleRate} })`,
8351        );
8352  
8353        this._initialOptions.sessionSampleRate = sessionSampleRate;
8354      }
8355  
8356      if (typeof errorSampleRate === 'number') {
8357        // eslint-disable-next-line
8358        console.warn(
8359          `[Replay] You are passing \`errorSampleRate\` to the Replay integration.
8360  This option is deprecated and will be removed soon.
8361  Instead, configure \`replaysOnErrorSampleRate\` directly in the SDK init options, e.g.:
8362  Sentry.init({ replaysOnErrorSampleRate: ${errorSampleRate} })`,
8363        );
8364  
8365        this._initialOptions.errorSampleRate = errorSampleRate;
8366      }
8367  
8368      if (this._initialOptions.blockAllMedia) {
8369        // `blockAllMedia` is a more user friendly option to configure blocking
8370        // embedded media elements
8371        this._recordingOptions.blockSelector = !this._recordingOptions.blockSelector
8372          ? MEDIA_SELECTORS
8373          : `${this._recordingOptions.blockSelector},${MEDIA_SELECTORS}`;
8374      }
8375  
8376      if (this._isInitialized && isBrowser()) {
8377        throw new Error('Multiple Sentry Session Replay instances are not supported');
8378      }
8379  
8380      this._isInitialized = true;
8381    }
8382  
8383    /** If replay has already been initialized */
8384     get _isInitialized() {
8385      return _initialized;
8386    }
8387  
8388    /** Update _isInitialized */
8389     set _isInitialized(value) {
8390      _initialized = value;
8391    }
8392  
8393    /**
8394     * Setup and initialize replay container
8395     */
8396     setupOnce() {
8397      if (!isBrowser()) {
8398        return;
8399      }
8400  
8401      this._setup();
8402  
8403      // Once upon a time, we tried to create a transaction in `setupOnce` and it would
8404      // potentially create a transaction before some native SDK integrations have run
8405      // and applied their own global event processor. An example is:
8406      // https://github.com/getsentry/sentry-javascript/blob/b47ceafbdac7f8b99093ce6023726ad4687edc48/packages/browser/src/integrations/useragent.ts
8407      //
8408      // So we call `this._initialize()` in next event loop as a workaround to wait for other
8409      // global event processors to finish. This is no longer needed, but keeping it
8410      // here to avoid any future issues.
8411      setTimeout(() => this._initialize());
8412    }
8413  
8414    /**
8415     * Start a replay regardless of sampling rate. Calling this will always
8416     * create a new session. Will throw an error if replay is already in progress.
8417     *
8418     * Creates or loads a session, attaches listeners to varying events (DOM,
8419     * PerformanceObserver, Recording, Sentry SDK, etc)
8420     */
8421     start() {
8422      if (!this._replay) {
8423        return;
8424      }
8425  
8426      this._replay.start();
8427    }
8428  
8429    /**
8430     * Start replay buffering. Buffers until `flush()` is called or, if
8431     * `replaysOnErrorSampleRate` > 0, until an error occurs.
8432     */
8433     startBuffering() {
8434      if (!this._replay) {
8435        return;
8436      }
8437  
8438      this._replay.startBuffering();
8439    }
8440  
8441    /**
8442     * Currently, this needs to be manually called (e.g. for tests). Sentry SDK
8443     * does not support a teardown
8444     */
8445     stop() {
8446      if (!this._replay) {
8447        return Promise.resolve();
8448      }
8449  
8450      return this._replay.stop();
8451    }
8452  
8453    /**
8454     * If not in "session" recording mode, flush event buffer which will create a new replay.
8455     * Unless `continueRecording` is false, the replay will continue to record and
8456     * behave as a "session"-based replay.
8457     *
8458     * Otherwise, queue up a flush.
8459     */
8460     flush(options) {
8461      if (!this._replay || !this._replay.isEnabled()) {
8462        return Promise.resolve();
8463      }
8464  
8465      return this._replay.sendBufferedReplayOrFlush(options);
8466    }
8467  
8468    /**
8469     * Get the current session ID.
8470     */
8471     getReplayId() {
8472      if (!this._replay || !this._replay.isEnabled()) {
8473        return;
8474      }
8475  
8476      return this._replay.getSessionId();
8477    }
8478    /**
8479     * Initializes replay.
8480     */
8481     _initialize() {
8482      if (!this._replay) {
8483        return;
8484      }
8485  
8486      this._replay.initializeSampling();
8487    }
8488  
8489    /** Setup the integration. */
8490     _setup() {
8491      // Client is not available in constructor, so we need to wait until setupOnce
8492      const finalOptions = loadReplayOptionsFromClient(this._initialOptions);
8493  
8494      this._replay = new ReplayContainer({
8495        options: finalOptions,
8496        recordingOptions: this._recordingOptions,
8497      });
8498    }
8499  } Replay.__initStatic();
8500  
8501  /** Parse Replay-related options from SDK options */
8502  function loadReplayOptionsFromClient(initialOptions) {
8503    const client = getCurrentHub().getClient();
8504    const opt = client && (client.getOptions() );
8505  
8506    const finalOptions = { sessionSampleRate: 0, errorSampleRate: 0, ...dropUndefinedKeys(initialOptions) };
8507  
8508    if (!opt) {
8509      // eslint-disable-next-line no-console
8510      console.warn('SDK client is not available.');
8511      return finalOptions;
8512    }
8513  
8514    if (
8515      initialOptions.sessionSampleRate == null && // TODO remove once deprecated rates are removed
8516      initialOptions.errorSampleRate == null && // TODO remove once deprecated rates are removed
8517      opt.replaysSessionSampleRate == null &&
8518      opt.replaysOnErrorSampleRate == null
8519    ) {
8520      // eslint-disable-next-line no-console
8521      console.warn(
8522        'Replay is disabled because neither `replaysSessionSampleRate` nor `replaysOnErrorSampleRate` are set.',
8523      );
8524    }
8525  
8526    if (typeof opt.replaysSessionSampleRate === 'number') {
8527      finalOptions.sessionSampleRate = opt.replaysSessionSampleRate;
8528    }
8529  
8530    if (typeof opt.replaysOnErrorSampleRate === 'number') {
8531      finalOptions.errorSampleRate = opt.replaysOnErrorSampleRate;
8532    }
8533  
8534    return finalOptions;
8535  }
8536  
8537  function _getMergedNetworkHeaders(headers) {
8538    return [...DEFAULT_NETWORK_HEADERS, ...headers.map(header => header.toLowerCase())];
8539  }
8540  
8541  export { Replay };
8542  //# sourceMappingURL=index.js.map