var Sentry = (function (exports) {
  /** Console logging verbosity for the SDK. */
  var LogLevel;
  (function (LogLevel) {
      /** No logs will be generated. */
      LogLevel[LogLevel["None"] = 0] = "None";
      /** Only SDK internal errors will be logged. */
      LogLevel[LogLevel["Error"] = 1] = "Error";
      /** Information useful for debugging the SDK will be logged. */
      LogLevel[LogLevel["Debug"] = 2] = "Debug";
      /** All SDK actions will be logged. */
      LogLevel[LogLevel["Verbose"] = 3] = "Verbose";
  })(LogLevel || (LogLevel = {}));

  /** JSDoc */
  (function (Severity) {
      /** JSDoc */
      Severity["Fatal"] = "fatal";
      /** JSDoc */
      Severity["Error"] = "error";
      /** JSDoc */
      Severity["Warning"] = "warning";
      /** JSDoc */
      Severity["Log"] = "log";
      /** JSDoc */
      Severity["Info"] = "info";
      /** JSDoc */
      Severity["Debug"] = "debug";
      /** JSDoc */
      Severity["Critical"] = "critical";
  })(exports.Severity || (exports.Severity = {}));
  // tslint:disable:completed-docs
  // tslint:disable:no-unnecessary-qualifier no-namespace
  (function (Severity) {
      /**
       * Converts a string-based level into a {@link Severity}.
       *
       * @param level string representation of Severity
       * @returns Severity
       */
      function fromString(level) {
          switch (level) {
              case 'debug':
                  return Severity.Debug;
              case 'info':
                  return Severity.Info;
              case 'warn':
              case 'warning':
                  return Severity.Warning;
              case 'error':
                  return Severity.Error;
              case 'fatal':
                  return Severity.Fatal;
              case 'critical':
                  return Severity.Critical;
              case 'log':
              default:
                  return Severity.Log;
          }
      }
      Severity.fromString = fromString;
  })(exports.Severity || (exports.Severity = {}));

  /** The status of an Span. */
  var SpanStatus;
  (function (SpanStatus) {
      /** The operation completed successfully. */
      SpanStatus["Ok"] = "ok";
      /** Deadline expired before operation could complete. */
      SpanStatus["DeadlineExceeded"] = "deadline_exceeded";
      /** 401 Unauthorized (actually does mean unauthenticated according to RFC 7235) */
      SpanStatus["Unauthenticated"] = "unauthenticated";
      /** 403 Forbidden */
      SpanStatus["PermissionDenied"] = "permission_denied";
      /** 404 Not Found. Some requested entity (file or directory) was not found. */
      SpanStatus["NotFound"] = "not_found";
      /** 429 Too Many Requests */
      SpanStatus["ResourceExhausted"] = "resource_exhausted";
      /** Client specified an invalid argument. 4xx. */
      SpanStatus["InvalidArgument"] = "invalid_argument";
      /** 501 Not Implemented */
      SpanStatus["Unimplemented"] = "unimplemented";
      /** 503 Service Unavailable */
      SpanStatus["Unavailable"] = "unavailable";
      /** Other/generic 5xx. */
      SpanStatus["InternalError"] = "internal_error";
      /** Unknown. Any non-standard HTTP status code. */
      SpanStatus["UnknownError"] = "unknown_error";
      /** The operation was cancelled (typically by the user). */
      SpanStatus["Cancelled"] = "cancelled";
      /** Already exists (409) */
      SpanStatus["AlreadyExists"] = "already_exists";
      /** Operation was rejected because the system is not in a state required for the operation's */
      SpanStatus["FailedPrecondition"] = "failed_precondition";
      /** The operation was aborted, typically due to a concurrency issue. */
      SpanStatus["Aborted"] = "aborted";
      /** Operation was attempted past the valid range. */
      SpanStatus["OutOfRange"] = "out_of_range";
      /** Unrecoverable data loss or corruption */
      SpanStatus["DataLoss"] = "data_loss";
  })(SpanStatus || (SpanStatus = {}));
  // tslint:disable:no-unnecessary-qualifier no-namespace
  (function (SpanStatus) {
      /**
       * Converts a HTTP status code into a {@link SpanStatus}.
       *
       * @param httpStatus The HTTP response status code.
       * @returns The span status or {@link SpanStatus.UnknownError}.
       */
      // tslint:disable-next-line:completed-docs
      function fromHttpCode(httpStatus) {
          if (httpStatus < 400) {
              return SpanStatus.Ok;
          }
          if (httpStatus >= 400 && httpStatus < 500) {
              switch (httpStatus) {
                  case 401:
                      return SpanStatus.Unauthenticated;
                  case 403:
                      return SpanStatus.PermissionDenied;
                  case 404:
                      return SpanStatus.NotFound;
                  case 409:
                      return SpanStatus.AlreadyExists;
                  case 413:
                      return SpanStatus.FailedPrecondition;
                  case 429:
                      return SpanStatus.ResourceExhausted;
                  default:
                      return SpanStatus.InvalidArgument;
              }
          }
          if (httpStatus >= 500 && httpStatus < 600) {
              switch (httpStatus) {
                  case 501:
                      return SpanStatus.Unimplemented;
                  case 503:
                      return SpanStatus.Unavailable;
                  case 504:
                      return SpanStatus.DeadlineExceeded;
                  default:
                      return SpanStatus.InternalError;
              }
          }
          return SpanStatus.UnknownError;
      }
      SpanStatus.fromHttpCode = fromHttpCode;
  })(SpanStatus || (SpanStatus = {}));

  /** The status of an event. */
  (function (Status) {
      /** The status could not be determined. */
      Status["Unknown"] = "unknown";
      /** The event was skipped due to configuration or callbacks. */
      Status["Skipped"] = "skipped";
      /** The event was sent to Sentry successfully. */
      Status["Success"] = "success";
      /** The client is currently rate limited and will try again later. */
      Status["RateLimit"] = "rate_limit";
      /** The event could not be processed. */
      Status["Invalid"] = "invalid";
      /** A server-side error ocurred during submission. */
      Status["Failed"] = "failed";
  })(exports.Status || (exports.Status = {}));
  // tslint:disable:completed-docs
  // tslint:disable:no-unnecessary-qualifier no-namespace
  (function (Status) {
      /**
       * Converts a HTTP status code into a {@link Status}.
       *
       * @param code The HTTP response status code.
       * @returns The send status or {@link Status.Unknown}.
       */
      function fromHttpCode(code) {
          if (code >= 200 && code < 300) {
              return Status.Success;
          }
          if (code === 429) {
              return Status.RateLimit;
          }
          if (code >= 400 && code < 500) {
              return Status.Invalid;
          }
          if (code >= 500) {
              return Status.Failed;
          }
          return Status.Unknown;
      }
      Status.fromHttpCode = fromHttpCode;
  })(exports.Status || (exports.Status = {}));

  /**
   * Consumes the promise and logs the error when it rejects.
   * @param promise A promise to forget.
   */

  const setPrototypeOf = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array ? setProtoOf : mixinProperties); // tslint:disable-line:no-unbound-method
  /**
   * setPrototypeOf polyfill using __proto__
   */
  function setProtoOf(obj, proto) {
      // @ts-ignore
      obj.__proto__ = proto;
      return obj;
  }
  /**
   * setPrototypeOf polyfill using mixin
   */
  function mixinProperties(obj, proto) {
      for (const prop in proto) {
          if (!obj.hasOwnProperty(prop)) {
              // @ts-ignore
              obj[prop] = proto[prop];
          }
      }
      return obj;
  }

  /** An error emitted by Sentry SDKs and related utilities. */
  class SentryError extends Error {
      constructor(message) {
          super(message);
          this.message = message;
          // tslint:disable:no-unsafe-any
          this.name = new.target.prototype.constructor.name;
          setPrototypeOf(this, new.target.prototype);
      }
  }

  /**
   * Checks whether given value's type is one of a few Error or Error-like
   * {@link isError}.
   *
   * @param wat A value to be checked.
   * @returns A boolean representing the result.
   */
  function isError(wat) {
      switch (Object.prototype.toString.call(wat)) {
          case '[object Error]':
              return true;
          case '[object Exception]':
              return true;
          case '[object DOMException]':
              return true;
          default:
              return isInstanceOf(wat, Error);
      }
  }
  /**
   * Checks whether given value's type is ErrorEvent
   * {@link isErrorEvent}.
   *
   * @param wat A value to be checked.
   * @returns A boolean representing the result.
   */
  function isErrorEvent(wat) {
      return Object.prototype.toString.call(wat) === '[object ErrorEvent]';
  }
  /**
   * Checks whether given value's type is DOMError
   * {@link isDOMError}.
   *
   * @param wat A value to be checked.
   * @returns A boolean representing the result.
   */
  function isDOMError(wat) {
      return Object.prototype.toString.call(wat) === '[object DOMError]';
  }
  /**
   * Checks whether given value's type is DOMException
   * {@link isDOMException}.
   *
   * @param wat A value to be checked.
   * @returns A boolean representing the result.
   */
  function isDOMException(wat) {
      return Object.prototype.toString.call(wat) === '[object DOMException]';
  }
  /**
   * Checks whether given value's type is a string
   * {@link isString}.
   *
   * @param wat A value to be checked.
   * @returns A boolean representing the result.
   */
  function isString(wat) {
      return Object.prototype.toString.call(wat) === '[object String]';
  }
  /**
   * Checks whether given value's is a primitive (undefined, null, number, boolean, string)
   * {@link isPrimitive}.
   *
   * @param wat A value to be checked.
   * @returns A boolean representing the result.
   */
  function isPrimitive(wat) {
      return wat === null || (typeof wat !== 'object' && typeof wat !== 'function');
  }
  /**
   * Checks whether given value's type is an object literal
   * {@link isPlainObject}.
   *
   * @param wat A value to be checked.
   * @returns A boolean representing the result.
   */
  function isPlainObject(wat) {
      return Object.prototype.toString.call(wat) === '[object Object]';
  }
  /**
   * Checks whether given value's type is an Event instance
   * {@link isEvent}.
   *
   * @param wat A value to be checked.
   * @returns A boolean representing the result.
   */
  function isEvent(wat) {
      // tslint:disable-next-line:strict-type-predicates
      return typeof Event !== 'undefined' && isInstanceOf(wat, Event);
  }
  /**
   * Checks whether given value's type is an Element instance
   * {@link isElement}.
   *
   * @param wat A value to be checked.
   * @returns A boolean representing the result.
   */
  function isElement(wat) {
      // tslint:disable-next-line:strict-type-predicates
      return typeof Element !== 'undefined' && isInstanceOf(wat, Element);
  }
  /**
   * Checks whether given value's type is an regexp
   * {@link isRegExp}.
   *
   * @param wat A value to be checked.
   * @returns A boolean representing the result.
   */
  function isRegExp(wat) {
      return Object.prototype.toString.call(wat) === '[object RegExp]';
  }
  /**
   * Checks whether given value has a then function.
   * @param wat A value to be checked.
   */
  function isThenable(wat) {
      // tslint:disable:no-unsafe-any
      return Boolean(wat && wat.then && typeof wat.then === 'function');
      // tslint:enable:no-unsafe-any
  }
  /**
   * Checks whether given value's type is a SyntheticEvent
   * {@link isSyntheticEvent}.
   *
   * @param wat A value to be checked.
   * @returns A boolean representing the result.
   */
  function isSyntheticEvent(wat) {
      // tslint:disable-next-line:no-unsafe-any
      return isPlainObject(wat) && 'nativeEvent' in wat && 'preventDefault' in wat && 'stopPropagation' in wat;
  }
  /**
   * Checks whether given value's type is an instance of provided constructor.
   * {@link isInstanceOf}.
   *
   * @param wat A value to be checked.
   * @param base A constructor to be used in a check.
   * @returns A boolean representing the result.
   */
  function isInstanceOf(wat, base) {
      try {
          // tslint:disable-next-line:no-unsafe-any
          return wat instanceof base;
      }
      catch (_e) {
          return false;
      }
  }

  /**
   * Truncates given string to the maximum characters count
   *
   * @param str An object that contains serializable values
   * @param max Maximum number of characters in truncated string
   * @returns string Encoded
   */
  function truncate(str, max = 0) {
      // tslint:disable-next-line:strict-type-predicates
      if (typeof str !== 'string' || max === 0) {
          return str;
      }
      return str.length <= max ? str : `${str.substr(0, max)}...`;
  }
  /**
   * Join values in array
   * @param input array of values to be joined together
   * @param delimiter string to be placed in-between values
   * @returns Joined values
   */
  function safeJoin(input, delimiter) {
      if (!Array.isArray(input)) {
          return '';
      }
      const output = [];
      // tslint:disable-next-line:prefer-for-of
      for (let i = 0; i < input.length; i++) {
          const value = input[i];
          try {
              output.push(String(value));
          }
          catch (e) {
              output.push('[value cannot be serialized]');
          }
      }
      return output.join(delimiter);
  }
  /**
   * Checks if the value matches a regex or includes the string
   * @param value The string value to be checked against
   * @param pattern Either a regex or a string that must be contained in value
   */
  function isMatchingPattern(value, pattern) {
      if (isRegExp(pattern)) {
          return pattern.test(value);
      }
      if (typeof pattern === 'string') {
          return value.indexOf(pattern) !== -1;
      }
      return false;
  }

  /**
   * Requires a module which is protected _against bundler minification.
   *
   * @param request The module path to resolve
   */
  function dynamicRequire(mod, request) {
      // tslint:disable-next-line: no-unsafe-any
      return mod.require(request);
  }
  /**
   * Checks whether we're in the Node.js or Browser environment
   *
   * @returns Answer to given question
   */
  function isNodeEnv() {
      // tslint:disable:strict-type-predicates
      return Object.prototype.toString.call(typeof process !== 'undefined' ? process : 0) === '[object process]';
  }
  const fallbackGlobalObject = {};
  /**
   * Safely get global scope object
   *
   * @returns Global scope object
   */
  function getGlobalObject() {
      return (isNodeEnv()
          ? global
          : typeof window !== 'undefined'
              ? window
              : typeof self !== 'undefined'
                  ? self
                  : fallbackGlobalObject);
  }
  /**
   * UUID4 generator
   *
   * @returns string Generated UUID4.
   */
  function uuid4() {
      const global = getGlobalObject();
      const crypto = global.crypto || global.msCrypto;
      if (!(crypto === void 0) && crypto.getRandomValues) {
          // Use window.crypto API if available
          const arr = new Uint16Array(8);
          crypto.getRandomValues(arr);
          // set 4 in byte 7
          // tslint:disable-next-line:no-bitwise
          arr[3] = (arr[3] & 0xfff) | 0x4000;
          // set 2 most significant bits of byte 9 to '10'
          // tslint:disable-next-line:no-bitwise
          arr[4] = (arr[4] & 0x3fff) | 0x8000;
          const pad = (num) => {
              let v = num.toString(16);
              while (v.length < 4) {
                  v = `0${v}`;
              }
              return v;
          };
          return (pad(arr[0]) + pad(arr[1]) + pad(arr[2]) + pad(arr[3]) + pad(arr[4]) + pad(arr[5]) + pad(arr[6]) + pad(arr[7]));
      }
      // http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript/2117523#2117523
      return 'xxxxxxxxxxxx4xxxyxxxxxxxxxxxxxxx'.replace(/[xy]/g, c => {
          // tslint:disable-next-line:no-bitwise
          const r = (Math.random() * 16) | 0;
          // tslint:disable-next-line:no-bitwise
          const v = c === 'x' ? r : (r & 0x3) | 0x8;
          return v.toString(16);
      });
  }
  /**
   * Parses string form of URL into an object
   * // borrowed from https://tools.ietf.org/html/rfc3986#appendix-B
   * // intentionally using regex and not <a/> href parsing trick because React Native and other
   * // environments where DOM might not be available
   * @returns parsed URL object
   */
  function parseUrl(url) {
      if (!url) {
          return {};
      }
      const match = url.match(/^(([^:\/?#]+):)?(\/\/([^\/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?$/);
      if (!match) {
          return {};
      }
      // coerce to undefined values to empty string so we don't get 'undefined'
      const query = match[6] || '';
      const fragment = match[8] || '';
      return {
          host: match[4],
          path: match[5],
          protocol: match[2],
          relative: match[5] + query + fragment,
      };
  }
  /**
   * Extracts either message or type+value from an event that can be used for user-facing logs
   * @returns event's description
   */
  function getEventDescription(event) {
      if (event.message) {
          return event.message;
      }
      if (event.exception && event.exception.values && event.exception.values[0]) {
          const exception = event.exception.values[0];
          if (exception.type && exception.value) {
              return `${exception.type}: ${exception.value}`;
          }
          return exception.type || exception.value || event.event_id || '<unknown>';
      }
      return event.event_id || '<unknown>';
  }
  /** JSDoc */
  function consoleSandbox(callback) {
      const global = getGlobalObject();
      const levels = ['debug', 'info', 'warn', 'error', 'log', 'assert'];
      if (!('console' in global)) {
          return callback();
      }
      const originalConsole = global.console;
      const wrappedLevels = {};
      // Restore all wrapped console methods
      levels.forEach(level => {
          if (level in global.console && originalConsole[level].__sentry_original__) {
              wrappedLevels[level] = originalConsole[level];
              originalConsole[level] = originalConsole[level].__sentry_original__;
          }
      });
      // Perform callback manipulations
      const result = callback();
      // Revert restoration to wrapped state
      Object.keys(wrappedLevels).forEach(level => {
          originalConsole[level] = wrappedLevels[level];
      });
      return result;
  }
  /**
   * Adds exception values, type and value to an synthetic Exception.
   * @param event The event to modify.
   * @param value Value of the exception.
   * @param type Type of the exception.
   * @hidden
   */
  function addExceptionTypeValue(event, value, type) {
      event.exception = event.exception || {};
      event.exception.values = event.exception.values || [];
      event.exception.values[0] = event.exception.values[0] || {};
      event.exception.values[0].value = event.exception.values[0].value || value || '';
      event.exception.values[0].type = event.exception.values[0].type || type || 'Error';
  }
  /**
   * Adds exception mechanism to a given event.
   * @param event The event to modify.
   * @param mechanism Mechanism of the mechanism.
   * @hidden
   */
  function addExceptionMechanism(event, mechanism = {}) {
      // TODO: Use real type with `keyof Mechanism` thingy and maybe make it better?
      try {
          // @ts-ignore
          // tslint:disable:no-non-null-assertion
          event.exception.values[0].mechanism = event.exception.values[0].mechanism || {};
          Object.keys(mechanism).forEach(key => {
              // @ts-ignore
              event.exception.values[0].mechanism[key] = mechanism[key];
          });
      }
      catch (_oO) {
          // no-empty
      }
  }
  /**
   * A safe form of location.href
   */
  function getLocationHref() {
      try {
          return document.location.href;
      }
      catch (oO) {
          return '';
      }
  }
  /**
   * Given a child DOM element, returns a query-selector statement describing that
   * and its ancestors
   * e.g. [HTMLElement] => body > div > input#foo.btn[name=baz]
   * @returns generated DOM path
   */
  function htmlTreeAsString(elem) {
      // try/catch both:
      // - accessing event.target (see getsentry/raven-js#838, #768)
      // - `htmlTreeAsString` because it's complex, and just accessing the DOM incorrectly
      // - can throw an exception in some circumstances.
      try {
          let currentElem = elem;
          const MAX_TRAVERSE_HEIGHT = 5;
          const MAX_OUTPUT_LEN = 80;
          const out = [];
          let height = 0;
          let len = 0;
          const separator = ' > ';
          const sepLength = separator.length;
          let nextStr;
          while (currentElem && height++ < MAX_TRAVERSE_HEIGHT) {
              nextStr = _htmlElementAsString(currentElem);
              // bail out if
              // - nextStr is the 'html' element
              // - the length of the string that would be created exceeds MAX_OUTPUT_LEN
              //   (ignore this limit if we are on the first iteration)
              if (nextStr === 'html' || (height > 1 && len + out.length * sepLength + nextStr.length >= MAX_OUTPUT_LEN)) {
                  break;
              }
              out.push(nextStr);
              len += nextStr.length;
              currentElem = currentElem.parentNode;
          }
          return out.reverse().join(separator);
      }
      catch (_oO) {
          return '<unknown>';
      }
  }
  /**
   * Returns a simple, query-selector representation of a DOM element
   * e.g. [HTMLElement] => input#foo.btn[name=baz]
   * @returns generated DOM path
   */
  function _htmlElementAsString(el) {
      const elem = el;
      const out = [];
      let className;
      let classes;
      let key;
      let attr;
      let i;
      if (!elem || !elem.tagName) {
          return '';
      }
      out.push(elem.tagName.toLowerCase());
      if (elem.id) {
          out.push(`#${elem.id}`);
      }
      className = elem.className;
      if (className && isString(className)) {
          classes = className.split(/\s+/);
          for (i = 0; i < classes.length; i++) {
              out.push(`.${classes[i]}`);
          }
      }
      const attrWhitelist = ['type', 'name', 'title', 'alt'];
      for (i = 0; i < attrWhitelist.length; i++) {
          key = attrWhitelist[i];
          attr = elem.getAttribute(key);
          if (attr) {
              out.push(`[${key}="${attr}"]`);
          }
      }
      return out.join('');
  }
  /**
   * Returns a timestamp in seconds with milliseconds precision.
   */
  function timestampWithMs() {
      return Date.now() / 1000;
  }
  const defaultRetryAfter = 60 * 1000; // 60 seconds
  /**
   * Extracts Retry-After value from the request header or returns default value
   * @param now current unix timestamp
   * @param header string representation of 'Retry-After' header
   */
  function parseRetryAfterHeader(now, header) {
      if (!header) {
          return defaultRetryAfter;
      }
      const headerDelay = parseInt(`${header}`, 10);
      if (!isNaN(headerDelay)) {
          return headerDelay * 1000;
      }
      const headerDate = Date.parse(`${header}`);
      if (!isNaN(headerDate)) {
          return headerDate - now;
      }
      return defaultRetryAfter;
  }
  const defaultFunctionName = '<anonymous>';
  /**
   * Safely extract function name from itself
   */
  function getFunctionName(fn) {
      try {
          if (!fn || typeof fn !== 'function') {
              return defaultFunctionName;
          }
          return fn.name || defaultFunctionName;
      }
      catch (e) {
          // Just accessing custom props in some Selenium environments
          // can cause a "Permission denied" exception (see raven-js#495).
          return defaultFunctionName;
      }
  }

  // TODO: Implement different loggers for different environments
  const global$1 = getGlobalObject();
  /** Prefix for logging strings */
  const PREFIX = 'Sentry Logger ';
  /** JSDoc */
  class Logger {
      /** JSDoc */
      constructor() {
          this._enabled = false;
      }
      /** JSDoc */
      disable() {
          this._enabled = false;
      }
      /** JSDoc */
      enable() {
          this._enabled = true;
      }
      /** JSDoc */
      log(...args) {
          if (!this._enabled) {
              return;
          }
          consoleSandbox(() => {
              global$1.console.log(`${PREFIX}[Log]: ${args.join(' ')}`); // tslint:disable-line:no-console
          });
      }
      /** JSDoc */
      warn(...args) {
          if (!this._enabled) {
              return;
          }
          consoleSandbox(() => {
              global$1.console.warn(`${PREFIX}[Warn]: ${args.join(' ')}`); // tslint:disable-line:no-console
          });
      }
      /** JSDoc */
      error(...args) {
          if (!this._enabled) {
              return;
          }
          consoleSandbox(() => {
              global$1.console.error(`${PREFIX}[Error]: ${args.join(' ')}`); // tslint:disable-line:no-console
          });
      }
  }
  // Ensure we only have a single logger instance, even if multiple versions of @sentry/utils are being used
  global$1.__SENTRY__ = global$1.__SENTRY__ || {};
  const logger = global$1.__SENTRY__.logger || (global$1.__SENTRY__.logger = new Logger());

  // tslint:disable:no-unsafe-any
  /**
   * Memo class used for decycle json objects. Uses WeakSet if available otherwise array.
   */
  class Memo {
      constructor() {
          // tslint:disable-next-line
          this._hasWeakSet = typeof WeakSet === 'function';
          this._inner = this._hasWeakSet ? new WeakSet() : [];
      }
      /**
       * Sets obj to remember.
       * @param obj Object to remember
       */
      memoize(obj) {
          if (this._hasWeakSet) {
              if (this._inner.has(obj)) {
                  return true;
              }
              this._inner.add(obj);
              return false;
          }
          // tslint:disable-next-line:prefer-for-of
          for (let i = 0; i < this._inner.length; i++) {
              const value = this._inner[i];
              if (value === obj) {
                  return true;
              }
          }
          this._inner.push(obj);
          return false;
      }
      /**
       * Removes object from internal storage.
       * @param obj Object to forget
       */
      unmemoize(obj) {
          if (this._hasWeakSet) {
              this._inner.delete(obj);
          }
          else {
              for (let i = 0; i < this._inner.length; i++) {
                  if (this._inner[i] === obj) {
                      this._inner.splice(i, 1);
                      break;
                  }
              }
          }
      }
  }

  /**
   * Wrap a given object method with a higher-order function
   *
   * @param source An object that contains a method to be wrapped.
   * @param name A name of method to be wrapped.
   * @param replacement A function that should be used to wrap a given method.
   * @returns void
   */
  function fill(source, name, replacement) {
      if (!(name in source)) {
          return;
      }
      const original = source[name];
      const wrapped = replacement(original);
      // Make sure it's a function first, as we need to attach an empty prototype for `defineProperties` to work
      // otherwise it'll throw "TypeError: Object.defineProperties called on non-object"
      // tslint:disable-next-line:strict-type-predicates
      if (typeof wrapped === 'function') {
          try {
              wrapped.prototype = wrapped.prototype || {};
              Object.defineProperties(wrapped, {
                  __sentry_original__: {
                      enumerable: false,
                      value: original,
                  },
              });
          }
          catch (_Oo) {
              // This can throw if multiple fill happens on a global object like XMLHttpRequest
              // Fixes https://github.com/getsentry/sentry-javascript/issues/2043
          }
      }
      source[name] = wrapped;
  }
  /**
   * Encodes given object into url-friendly format
   *
   * @param object An object that contains serializable values
   * @returns string Encoded
   */
  function urlEncode(object) {
      return Object.keys(object)
          .map(
      // tslint:disable-next-line:no-unsafe-any
      key => `${encodeURIComponent(key)}=${encodeURIComponent(object[key])}`)
          .join('&');
  }
  /**
   * Transforms any object into an object literal with all it's attributes
   * attached to it.
   *
   * @param value Initial source that we have to transform in order to be usable by the serializer
   */
  function getWalkSource(value) {
      if (isError(value)) {
          const error = value;
          const err = {
              message: error.message,
              name: error.name,
              stack: error.stack,
          };
          for (const i in error) {
              if (Object.prototype.hasOwnProperty.call(error, i)) {
                  err[i] = error[i];
              }
          }
          return err;
      }
      if (isEvent(value)) {
          const event = value;
          const source = {};
          source.type = event.type;
          // Accessing event.target can throw (see getsentry/raven-js#838, #768)
          try {
              source.target = isElement(event.target)
                  ? htmlTreeAsString(event.target)
                  : Object.prototype.toString.call(event.target);
          }
          catch (_oO) {
              source.target = '<unknown>';
          }
          try {
              source.currentTarget = isElement(event.currentTarget)
                  ? htmlTreeAsString(event.currentTarget)
                  : Object.prototype.toString.call(event.currentTarget);
          }
          catch (_oO) {
              source.currentTarget = '<unknown>';
          }
          // tslint:disable-next-line:strict-type-predicates
          if (typeof CustomEvent !== 'undefined' && isInstanceOf(value, CustomEvent)) {
              source.detail = event.detail;
          }
          for (const i in event) {
              if (Object.prototype.hasOwnProperty.call(event, i)) {
                  source[i] = event;
              }
          }
          return source;
      }
      return value;
  }
  /** Calculates bytes size of input string */
  function utf8Length(value) {
      // tslint:disable-next-line:no-bitwise
      return ~-encodeURI(value).split(/%..|./).length;
  }
  /** Calculates bytes size of input object */
  function jsonSize(value) {
      return utf8Length(JSON.stringify(value));
  }
  /** JSDoc */
  function normalizeToSize(object, 
  // Default Node.js REPL depth
  depth = 3, 
  // 100kB, as 200kB is max payload size, so half sounds reasonable
  maxSize = 100 * 1024) {
      const serialized = normalize(object, depth);
      if (jsonSize(serialized) > maxSize) {
          return normalizeToSize(object, depth - 1, maxSize);
      }
      return serialized;
  }
  /** Transforms any input value into a string form, either primitive value or a type of the input */
  function serializeValue(value) {
      const type = Object.prototype.toString.call(value);
      // Node.js REPL notation
      if (typeof value === 'string') {
          return value;
      }
      if (type === '[object Object]') {
          return '[Object]';
      }
      if (type === '[object Array]') {
          return '[Array]';
      }
      const normalized = normalizeValue(value);
      return isPrimitive(normalized) ? normalized : type;
  }
  /**
   * normalizeValue()
   *
   * Takes unserializable input and make it serializable friendly
   *
   * - translates undefined/NaN values to "[undefined]"/"[NaN]" respectively,
   * - serializes Error objects
   * - filter global objects
   */
  // tslint:disable-next-line:cyclomatic-complexity
  function normalizeValue(value, key) {
      if (key === 'domain' && value && typeof value === 'object' && value._events) {
          return '[Domain]';
      }
      if (key === 'domainEmitter') {
          return '[DomainEmitter]';
      }
      if (typeof global !== 'undefined' && value === global) {
          return '[Global]';
      }
      if (typeof window !== 'undefined' && value === window) {
          return '[Window]';
      }
      if (typeof document !== 'undefined' && value === document) {
          return '[Document]';
      }
      // React's SyntheticEvent thingy
      if (isSyntheticEvent(value)) {
          return '[SyntheticEvent]';
      }
      // tslint:disable-next-line:no-tautology-expression
      if (typeof value === 'number' && value !== value) {
          return '[NaN]';
      }
      if (value === void 0) {
          return '[undefined]';
      }
      if (typeof value === 'function') {
          return `[Function: ${getFunctionName(value)}]`;
      }
      return value;
  }
  /**
   * Walks an object to perform a normalization on it
   *
   * @param key of object that's walked in current iteration
   * @param value object to be walked
   * @param depth Optional number indicating how deep should walking be performed
   * @param memo Optional Memo class handling decycling
   */
  function walk(key, value, depth = +Infinity, memo = new Memo()) {
      // If we reach the maximum depth, serialize whatever has left
      if (depth === 0) {
          return serializeValue(value);
      }
      // If value implements `toJSON` method, call it and return early
      // tslint:disable:no-unsafe-any
      if (value !== null && value !== undefined && typeof value.toJSON === 'function') {
          return value.toJSON();
      }
      // tslint:enable:no-unsafe-any
      // If normalized value is a primitive, there are no branches left to walk, so we can just bail out, as theres no point in going down that branch any further
      const normalized = normalizeValue(value, key);
      if (isPrimitive(normalized)) {
          return normalized;
      }
      // Create source that we will use for next itterations, either objectified error object (Error type with extracted keys:value pairs) or the input itself
      const source = getWalkSource(value);
      // Create an accumulator that will act as a parent for all future itterations of that branch
      const acc = Array.isArray(value) ? [] : {};
      // If we already walked that branch, bail out, as it's circular reference
      if (memo.memoize(value)) {
          return '[Circular ~]';
      }
      // Walk all keys of the source
      for (const innerKey in source) {
          // Avoid iterating over fields in the prototype if they've somehow been exposed to enumeration.
          if (!Object.prototype.hasOwnProperty.call(source, innerKey)) {
              continue;
          }
          // Recursively walk through all the child nodes
          acc[innerKey] = walk(innerKey, source[innerKey], depth - 1, memo);
      }
      // Once walked through all the branches, remove the parent from memo storage
      memo.unmemoize(value);
      // Return accumulated values
      return acc;
  }
  /**
   * normalize()
   *
   * - Creates a copy to prevent original input mutation
   * - Skip non-enumerablers
   * - Calls `toJSON` if implemented
   * - Removes circular references
   * - Translates non-serializeable values (undefined/NaN/Functions) to serializable format
   * - Translates known global objects/Classes to a string representations
   * - Takes care of Error objects serialization
   * - Optionally limit depth of final output
   */
  function normalize(input, depth) {
      try {
          // tslint:disable-next-line:no-unsafe-any
          return JSON.parse(JSON.stringify(input, (key, value) => walk(key, value, depth)));
      }
      catch (_oO) {
          return '**non-serializable**';
      }
  }
  /**
   * Given any captured exception, extract its keys and create a sorted
   * and truncated list that will be used inside the event message.
   * eg. `Non-error exception captured with keys: foo, bar, baz`
   */
  function extractExceptionKeysForMessage(exception, maxLength = 40) {
      // tslint:disable:strict-type-predicates
      const keys = Object.keys(getWalkSource(exception));
      keys.sort();
      if (!keys.length) {
          return '[object has no keys]';
      }
      if (keys[0].length >= maxLength) {
          return truncate(keys[0], maxLength);
      }
      for (let includedKeys = keys.length; includedKeys > 0; includedKeys--) {
          const serialized = keys.slice(0, includedKeys).join(', ');
          if (serialized.length > maxLength) {
              continue;
          }
          if (includedKeys === keys.length) {
              return serialized;
          }
          return truncate(serialized, maxLength);
      }
      return '';
  }

  // Slightly modified (no IE8 support, ES6) and transcribed to TypeScript

  /** SyncPromise internal states */
  var States;
  (function (States) {
      /** Pending */
      States["PENDING"] = "PENDING";
      /** Resolved / OK */
      States["RESOLVED"] = "RESOLVED";
      /** Rejected / Error */
      States["REJECTED"] = "REJECTED";
  })(States || (States = {}));
  /**
   * Thenable class that behaves like a Promise and follows it's interface
   * but is not async internally
   */
  class SyncPromise {
      constructor(executor) {
          this._state = States.PENDING;
          this._handlers = [];
          /** JSDoc */
          this._resolve = (value) => {
              this._setResult(States.RESOLVED, value);
          };
          /** JSDoc */
          this._reject = (reason) => {
              this._setResult(States.REJECTED, reason);
          };
          /** JSDoc */
          this._setResult = (state, value) => {
              if (this._state !== States.PENDING) {
                  return;
              }
              if (isThenable(value)) {
                  value.then(this._resolve, this._reject);
                  return;
              }
              this._state = state;
              this._value = value;
              this._executeHandlers();
          };
          // TODO: FIXME
          /** JSDoc */
          this._attachHandler = (handler) => {
              this._handlers = this._handlers.concat(handler);
              this._executeHandlers();
          };
          /** JSDoc */
          this._executeHandlers = () => {
              if (this._state === States.PENDING) {
                  return;
              }
              if (this._state === States.REJECTED) {
                  this._handlers.forEach(handler => {
                      if (handler.onrejected) {
                          handler.onrejected(this._value);
                      }
                  });
              }
              else {
                  this._handlers.forEach(handler => {
                      if (handler.onfulfilled) {
                          // tslint:disable-next-line:no-unsafe-any
                          handler.onfulfilled(this._value);
                      }
                  });
              }
              this._handlers = [];
          };
          try {
              executor(this._resolve, this._reject);
          }
          catch (e) {
              this._reject(e);
          }
      }
      /** JSDoc */
      toString() {
          return '[object SyncPromise]';
      }
      /** JSDoc */
      static resolve(value) {
          return new SyncPromise(resolve => {
              resolve(value);
          });
      }
      /** JSDoc */
      static reject(reason) {
          return new SyncPromise((_, reject) => {
              reject(reason);
          });
      }
      /** JSDoc */
      static all(collection) {
          return new SyncPromise((resolve, reject) => {
              if (!Array.isArray(collection)) {
                  reject(new TypeError(`Promise.all requires an array as input.`));
                  return;
              }
              if (collection.length === 0) {
                  resolve([]);
                  return;
              }
              let counter = collection.length;
              const resolvedCollection = [];
              collection.forEach((item, index) => {
                  SyncPromise.resolve(item)
                      .then(value => {
                      resolvedCollection[index] = value;
                      counter -= 1;
                      if (counter !== 0) {
                          return;
                      }
                      resolve(resolvedCollection);
                  })
                      .then(null, reject);
              });
          });
      }
      /** JSDoc */
      then(onfulfilled, onrejected) {
          return new SyncPromise((resolve, reject) => {
              this._attachHandler({
                  onfulfilled: result => {
                      if (!onfulfilled) {
                          // TODO: ¯\_(ツ)_/¯
                          // TODO: FIXME
                          resolve(result);
                          return;
                      }
                      try {
                          resolve(onfulfilled(result));
                          return;
                      }
                      catch (e) {
                          reject(e);
                          return;
                      }
                  },
                  onrejected: reason => {
                      if (!onrejected) {
                          reject(reason);
                          return;
                      }
                      try {
                          resolve(onrejected(reason));
                          return;
                      }
                      catch (e) {
                          reject(e);
                          return;
                      }
                  },
              });
          });
      }
      /** JSDoc */
      catch(onrejected) {
          return this.then(val => val, onrejected);
      }
      /** JSDoc */
      finally(onfinally) {
          return new SyncPromise((resolve, reject) => {
              let val;
              let isRejected;
              return this.then(value => {
                  isRejected = false;
                  val = value;
                  if (onfinally) {
                      onfinally();
                  }
              }, reason => {
                  isRejected = true;
                  val = reason;
                  if (onfinally) {
                      onfinally();
                  }
              }).then(() => {
                  if (isRejected) {
                      reject(val);
                      return;
                  }
                  // tslint:disable-next-line:no-unsafe-any
                  resolve(val);
              });
          });
      }
  }

  /** A simple queue that holds promises. */
  class PromiseBuffer {
      constructor(_limit) {
          this._limit = _limit;
          /** Internal set of queued Promises */
          this._buffer = [];
      }
      /**
       * Says if the buffer is ready to take more requests
       */
      isReady() {
          return this._limit === undefined || this.length() < this._limit;
      }
      /**
       * Add a promise to the queue.
       *
       * @param task Can be any PromiseLike<T>
       * @returns The original promise.
       */
      add(task) {
          if (!this.isReady()) {
              return SyncPromise.reject(new SentryError('Not adding Promise due to buffer limit reached.'));
          }
          if (this._buffer.indexOf(task) === -1) {
              this._buffer.push(task);
          }
          task
              .then(() => this.remove(task))
              .then(null, () => this.remove(task).then(null, () => {
              // We have to add this catch here otherwise we have an unhandledPromiseRejection
              // because it's a new Promise chain.
          }));
          return task;
      }
      /**
       * Remove a promise to the queue.
       *
       * @param task Can be any PromiseLike<T>
       * @returns Removed promise.
       */
      remove(task) {
          const removedTask = this._buffer.splice(this._buffer.indexOf(task), 1)[0];
          return removedTask;
      }
      /**
       * This function returns the number of unresolved promises in the queue.
       */
      length() {
          return this._buffer.length;
      }
      /**
       * This will drain the whole queue, returns true if queue is empty or drained.
       * If timeout is provided and the queue takes longer to drain, the promise still resolves but with false.
       *
       * @param timeout Number in ms to wait until it resolves with false.
       */
      drain(timeout) {
          return new SyncPromise(resolve => {
              const capturedSetTimeout = setTimeout(() => {
                  if (timeout && timeout > 0) {
                      resolve(false);
                  }
              }, timeout);
              SyncPromise.all(this._buffer)
                  .then(() => {
                  clearTimeout(capturedSetTimeout);
                  resolve(true);
              })
                  .then(null, () => {
                  resolve(true);
              });
          });
      }
  }

  /**
   * Tells whether current environment supports Fetch API
   * {@link supportsFetch}.
   *
   * @returns Answer to the given question.
   */
  function supportsFetch() {
      if (!('fetch' in getGlobalObject())) {
          return false;
      }
      try {
          // tslint:disable-next-line:no-unused-expression
          new Headers();
          // tslint:disable-next-line:no-unused-expression
          new Request('');
          // tslint:disable-next-line:no-unused-expression
          new Response();
          return true;
      }
      catch (e) {
          return false;
      }
  }
  /**
   * isNativeFetch checks if the given function is a native implementation of fetch()
   */
  function isNativeFetch(func) {
      return func && /^function fetch\(\)\s+\{\s+\[native code\]\s+\}$/.test(func.toString());
  }
  /**
   * Tells whether current environment supports Fetch API natively
   * {@link supportsNativeFetch}.
   *
   * @returns true if `window.fetch` is natively implemented, false otherwise
   */
  function supportsNativeFetch() {
      if (!supportsFetch()) {
          return false;
      }
      const global = getGlobalObject();
      // Fast path to avoid DOM I/O
      // tslint:disable-next-line:no-unbound-method
      if (isNativeFetch(global.fetch)) {
          return true;
      }
      // window.fetch is implemented, but is polyfilled or already wrapped (e.g: by a chrome extension)
      // so create a "pure" iframe to see if that has native fetch
      let result = false;
      const doc = global.document;
      if (doc) {
          try {
              const sandbox = doc.createElement('iframe');
              sandbox.hidden = true;
              doc.head.appendChild(sandbox);
              if (sandbox.contentWindow && sandbox.contentWindow.fetch) {
                  // tslint:disable-next-line:no-unbound-method
                  result = isNativeFetch(sandbox.contentWindow.fetch);
              }
              doc.head.removeChild(sandbox);
          }
          catch (err) {
              logger.warn('Could not create sandbox iframe for pure fetch check, bailing to window.fetch: ', err);
          }
      }
      return result;
  }
  /**
   * Tells whether current environment supports Referrer Policy API
   * {@link supportsReferrerPolicy}.
   *
   * @returns Answer to the given question.
   */
  function supportsReferrerPolicy() {
      // Despite all stars in the sky saying that Edge supports old draft syntax, aka 'never', 'always', 'origin' and 'default
      // https://caniuse.com/#feat=referrer-policy
      // It doesn't. And it throw exception instead of ignoring this parameter...
      // REF: https://github.com/getsentry/raven-js/issues/1233
      if (!supportsFetch()) {
          return false;
      }
      try {
          // tslint:disable:no-unused-expression
          new Request('_', {
              referrerPolicy: 'origin',
          });
          return true;
      }
      catch (e) {
          return false;
      }
  }
  /**
   * Tells whether current environment supports History API
   * {@link supportsHistory}.
   *
   * @returns Answer to the given question.
   */
  function supportsHistory() {
      // NOTE: in Chrome App environment, touching history.pushState, *even inside
      //       a try/catch block*, will cause Chrome to output an error to console.error
      // borrowed from: https://github.com/angular/angular.js/pull/13945/files
      const global = getGlobalObject();
      const chrome = global.chrome;
      // tslint:disable-next-line:no-unsafe-any
      const isChromePackagedApp = chrome && chrome.app && chrome.app.runtime;
      const hasHistoryApi = 'history' in global && !!global.history.pushState && !!global.history.replaceState;
      return !isChromePackagedApp && hasHistoryApi;
  }

  /* tslint:disable:only-arrow-functions no-unsafe-any */
  const global$2 = getGlobalObject();
  /**
   * Instrument native APIs to call handlers that can be used to create breadcrumbs, APM spans etc.
   *  - Console API
   *  - Fetch API
   *  - XHR API
   *  - History API
   *  - DOM API (click/typing)
   */
  const handlers = {};
  const instrumented = {};
  /** Instruments given API */
  function instrument(type) {
      if (instrumented[type]) {
          return;
      }
      instrumented[type] = true;
      switch (type) {
          case 'console':
              instrumentConsole();
              break;
          case 'dom':
              instrumentDOM();
              break;
          case 'xhr':
              instrumentXHR();
              break;
          case 'fetch':
              instrumentFetch();
              break;
          case 'history':
              instrumentHistory();
              break;
          default:
              logger.warn('unknown instrumentation type:', type);
      }
  }
  /**
   * Add handler that will be called when given type of instrumentation triggers.
   * Use at your own risk, this might break without changelog notice, only used internally.
   * @hidden
   */
  function addInstrumentationHandler(handler) {
      // tslint:disable-next-line:strict-type-predicates
      if (!handler || typeof handler.type !== 'string' || typeof handler.callback !== 'function') {
          return;
      }
      handlers[handler.type] = handlers[handler.type] || [];
      handlers[handler.type].push(handler.callback);
      instrument(handler.type);
  }
  /** JSDoc */
  function triggerHandlers(type, data) {
      if (!type || !handlers[type]) {
          return;
      }
      for (const handler of handlers[type] || []) {
          try {
              handler(data);
          }
          catch (e) {
              logger.error(`Error while triggering instrumentation handler.\nType: ${type}\nName: ${getFunctionName(handler)}\nError: ${e}`);
          }
      }
  }
  /** JSDoc */
  function instrumentConsole() {
      if (!('console' in global$2)) {
          return;
      }
      ['debug', 'info', 'warn', 'error', 'log', 'assert'].forEach(function (level) {
          if (!(level in global$2.console)) {
              return;
          }
          fill(global$2.console, level, function (originalConsoleLevel) {
              return function (...args) {
                  triggerHandlers('console', { args, level });
                  // this fails for some browsers. :(
                  if (originalConsoleLevel) {
                      Function.prototype.apply.call(originalConsoleLevel, global$2.console, args);
                  }
              };
          });
      });
  }
  /** JSDoc */
  function instrumentFetch() {
      if (!supportsNativeFetch()) {
          return;
      }
      fill(global$2, 'fetch', function (originalFetch) {
          return function (...args) {
              const commonHandlerData = {
                  args,
                  fetchData: {
                      method: getFetchMethod(args),
                      url: getFetchUrl(args),
                  },
                  startTimestamp: Date.now(),
              };
              triggerHandlers('fetch', Object.assign({}, commonHandlerData));
              return originalFetch.apply(global$2, args).then((response) => {
                  triggerHandlers('fetch', Object.assign({}, commonHandlerData, { endTimestamp: Date.now(), response }));
                  return response;
              }, (error) => {
                  triggerHandlers('fetch', Object.assign({}, commonHandlerData, { endTimestamp: Date.now(), error }));
                  throw error;
              });
          };
      });
  }
  /** Extract `method` from fetch call arguments */
  function getFetchMethod(fetchArgs = []) {
      if ('Request' in global$2 && isInstanceOf(fetchArgs[0], Request) && fetchArgs[0].method) {
          return String(fetchArgs[0].method).toUpperCase();
      }
      if (fetchArgs[1] && fetchArgs[1].method) {
          return String(fetchArgs[1].method).toUpperCase();
      }
      return 'GET';
  }
  /** Extract `url` from fetch call arguments */
  function getFetchUrl(fetchArgs = []) {
      if (typeof fetchArgs[0] === 'string') {
          return fetchArgs[0];
      }
      if ('Request' in global$2 && isInstanceOf(fetchArgs[0], Request)) {
          return fetchArgs[0].url;
      }
      return String(fetchArgs[0]);
  }
  /** JSDoc */
  function instrumentXHR() {
      if (!('XMLHttpRequest' in global$2)) {
          return;
      }
      const xhrproto = XMLHttpRequest.prototype;
      fill(xhrproto, 'open', function (originalOpen) {
          return function (...args) {
              const url = args[1];
              this.__sentry_xhr__ = {
                  method: isString(args[0]) ? args[0].toUpperCase() : args[0],
                  url: args[1],
              };
              // if Sentry key appears in URL, don't capture it as a request
              if (isString(url) && this.__sentry_xhr__.method === 'POST' && url.match(/sentry_key/)) {
                  this.__sentry_own_request__ = true;
              }
              return originalOpen.apply(this, args);
          };
      });
      fill(xhrproto, 'send', function (originalSend) {
          return function (...args) {
              const xhr = this; // tslint:disable-line:no-this-assignment
              const commonHandlerData = {
                  args,
                  startTimestamp: Date.now(),
                  xhr,
              };
              triggerHandlers('xhr', Object.assign({}, commonHandlerData));
              xhr.addEventListener('readystatechange', function () {
                  if (xhr.readyState === 4) {
                      try {
                          // touching statusCode in some platforms throws
                          // an exception
                          if (xhr.__sentry_xhr__) {
                              xhr.__sentry_xhr__.status_code = xhr.status;
                          }
                      }
                      catch (e) {
                          /* do nothing */
                      }
                      triggerHandlers('xhr', Object.assign({}, commonHandlerData, { endTimestamp: Date.now() }));
                  }
              });
              return originalSend.apply(this, args);
          };
      });
  }
  let lastHref;
  /** JSDoc */
  function instrumentHistory() {
      if (!supportsHistory()) {
          return;
      }
      const oldOnPopState = global$2.onpopstate;
      global$2.onpopstate = function (...args) {
          const to = global$2.location.href;
          // keep track of the current URL state, as we always receive only the updated state
          const from = lastHref;
          lastHref = to;
          triggerHandlers('history', {
              from,
              to,
          });
          if (oldOnPopState) {
              return oldOnPopState.apply(this, args);
          }
      };
      /** @hidden */
      function historyReplacementFunction(originalHistoryFunction) {
          return function (...args) {
              const url = args.length > 2 ? args[2] : undefined;
              if (url) {
                  // coerce to string (this is what pushState does)
                  const from = lastHref;
                  const to = String(url);
                  // keep track of the current URL state, as we always receive only the updated state
                  lastHref = to;
                  triggerHandlers('history', {
                      from,
                      to,
                  });
              }
              return originalHistoryFunction.apply(this, args);
          };
      }
      fill(global$2.history, 'pushState', historyReplacementFunction);
      fill(global$2.history, 'replaceState', historyReplacementFunction);
  }
  /** JSDoc */
  function instrumentDOM() {
      if (!('document' in global$2)) {
          return;
      }
      // Capture breadcrumbs from any click that is unhandled / bubbled up all the way
      // to the document. Do this before we instrument addEventListener.
      global$2.document.addEventListener('click', domEventHandler('click', triggerHandlers.bind(null, 'dom')), false);
      global$2.document.addEventListener('keypress', keypressEventHandler(triggerHandlers.bind(null, 'dom')), false);
      // After hooking into document bubbled up click and keypresses events, we also hook into user handled click & keypresses.
      ['EventTarget', 'Node'].forEach((target) => {
          const proto = global$2[target] && global$2[target].prototype;
          if (!proto || !proto.hasOwnProperty || !proto.hasOwnProperty('addEventListener')) {
              return;
          }
          fill(proto, 'addEventListener', function (original) {
              return function (eventName, fn, options) {
                  if (fn && fn.handleEvent) {
                      if (eventName === 'click') {
                          fill(fn, 'handleEvent', function (innerOriginal) {
                              return function (event) {
                                  domEventHandler('click', triggerHandlers.bind(null, 'dom'))(event);
                                  return innerOriginal.call(this, event);
                              };
                          });
                      }
                      if (eventName === 'keypress') {
                          fill(fn, 'handleEvent', function (innerOriginal) {
                              return function (event) {
                                  keypressEventHandler(triggerHandlers.bind(null, 'dom'))(event);
                                  return innerOriginal.call(this, event);
                              };
                          });
                      }
                  }
                  else {
                      if (eventName === 'click') {
                          domEventHandler('click', triggerHandlers.bind(null, 'dom'), true)(this);
                      }
                      if (eventName === 'keypress') {
                          keypressEventHandler(triggerHandlers.bind(null, 'dom'))(this);
                      }
                  }
                  return original.call(this, eventName, fn, options);
              };
          });
          fill(proto, 'removeEventListener', function (original) {
              return function (eventName, fn, options) {
                  let callback = fn;
                  try {
                      callback = callback && (callback.__sentry_wrapped__ || callback);
                  }
                  catch (e) {
                      // ignore, accessing __sentry_wrapped__ will throw in some Selenium environments
                  }
                  return original.call(this, eventName, callback, options);
              };
          });
      });
  }
  const debounceDuration = 1000;
  let debounceTimer = 0;
  let keypressTimeout;
  let lastCapturedEvent;
  /**
   * Wraps addEventListener to capture UI breadcrumbs
   * @param name the event name (e.g. "click")
   * @param handler function that will be triggered
   * @param debounce decides whether it should wait till another event loop
   * @returns wrapped breadcrumb events handler
   * @hidden
   */
  function domEventHandler(name, handler, debounce = false) {
      return (event) => {
          // reset keypress timeout; e.g. triggering a 'click' after
          // a 'keypress' will reset the keypress debounce so that a new
          // set of keypresses can be recorded
          keypressTimeout = undefined;
          // It's possible this handler might trigger multiple times for the same
          // event (e.g. event propagation through node ancestors). Ignore if we've
          // already captured the event.
          if (!event || lastCapturedEvent === event) {
              return;
          }
          lastCapturedEvent = event;
          if (debounceTimer) {
              clearTimeout(debounceTimer);
          }
          if (debounce) {
              debounceTimer = setTimeout(() => {
                  handler({ event, name });
              });
          }
          else {
              handler({ event, name });
          }
      };
  }
  /**
   * Wraps addEventListener to capture keypress UI events
   * @param handler function that will be triggered
   * @returns wrapped keypress events handler
   * @hidden
   */
  function keypressEventHandler(handler) {
      // TODO: if somehow user switches keypress target before
      //       debounce timeout is triggered, we will only capture
      //       a single breadcrumb from the FIRST target (acceptable?)
      return (event) => {
          let target;
          try {
              target = event.target;
          }
          catch (e) {
              // just accessing event properties can throw an exception in some rare circumstances
              // see: https://github.com/getsentry/raven-js/issues/838
              return;
          }
          const tagName = target && target.tagName;
          // only consider keypress events on actual input elements
          // this will disregard keypresses targeting body (e.g. tabbing
          // through elements, hotkeys, etc)
          if (!tagName || (tagName !== 'INPUT' && tagName !== 'TEXTAREA' && !target.isContentEditable)) {
              return;
          }
          // record first keypress in a series, but ignore subsequent
          // keypresses until debounce clears
          if (!keypressTimeout) {
              domEventHandler('input', handler)(event);
          }
          clearTimeout(keypressTimeout);
          keypressTimeout = setTimeout(() => {
              keypressTimeout = undefined;
          }, debounceDuration);
      };
  }

  /** Regular expression used to parse a Dsn. */
  const DSN_REGEX = /^(?:(\w+):)\/\/(?:(\w+)(?::(\w+))?@)([\w\.-]+)(?::(\d+))?\/(.+)/;
  /** Error message */
  const ERROR_MESSAGE = 'Invalid Dsn';
  /** The Sentry Dsn, identifying a Sentry instance and project. */
  class Dsn {
      /** Creates a new Dsn component */
      constructor(from) {
          if (typeof from === 'string') {
              this._fromString(from);
          }
          else {
              this._fromComponents(from);
          }
          this._validate();
      }
      /**
       * Renders the string representation of this Dsn.
       *
       * By default, this will render the public representation without the password
       * component. To get the deprecated private _representation, set `withPassword`
       * to true.
       *
       * @param withPassword When set to true, the password will be included.
       */
      toString(withPassword = false) {
          // tslint:disable-next-line:no-this-assignment
          const { host, path, pass, port, projectId, protocol, user } = this;
          return (`${protocol}://${user}${withPassword && pass ? `:${pass}` : ''}` +
              `@${host}${port ? `:${port}` : ''}/${path ? `${path}/` : path}${projectId}`);
      }
      /** Parses a string into this Dsn. */
      _fromString(str) {
          const match = DSN_REGEX.exec(str);
          if (!match) {
              throw new SentryError(ERROR_MESSAGE);
          }
          const [protocol, user, pass = '', host, port = '', lastPath] = match.slice(1);
          let path = '';
          let projectId = lastPath;
          const split = projectId.split('/');
          if (split.length > 1) {
              path = split.slice(0, -1).join('/');
              projectId = split.pop();
          }
          this._fromComponents({ host, pass, path, projectId, port, protocol: protocol, user });
      }
      /** Maps Dsn components into this instance. */
      _fromComponents(components) {
          this.protocol = components.protocol;
          this.user = components.user;
          this.pass = components.pass || '';
          this.host = components.host;
          this.port = components.port || '';
          this.path = components.path || '';
          this.projectId = components.projectId;
      }
      /** Validates this Dsn and throws on error. */
      _validate() {
          ['protocol', 'user', 'host', 'projectId'].forEach(component => {
              if (!this[component]) {
                  throw new SentryError(ERROR_MESSAGE);
              }
          });
          if (this.protocol !== 'http' && this.protocol !== 'https') {
              throw new SentryError(ERROR_MESSAGE);
          }
          if (this.port && isNaN(parseInt(this.port, 10))) {
              throw new SentryError(ERROR_MESSAGE);
          }
      }
  }

  /**
   * Holds additional event information. {@link Scope.applyToEvent} will be
   * called by the client before an event will be sent.
   */
  class Scope {
      constructor() {
          /** Flag if notifiying is happening. */
          this._notifyingListeners = false;
          /** Callback for client to receive scope changes. */
          this._scopeListeners = [];
          /** Callback list that will be called after {@link applyToEvent}. */
          this._eventProcessors = [];
          /** Array of breadcrumbs. */
          this._breadcrumbs = [];
          /** User */
          this._user = {};
          /** Tags */
          this._tags = {};
          /** Extra */
          this._extra = {};
          /** Contexts */
          this._context = {};
      }
      /**
       * Add internal on change listener. Used for sub SDKs that need to store the scope.
       * @hidden
       */
      addScopeListener(callback) {
          this._scopeListeners.push(callback);
      }
      /**
       * @inheritDoc
       */
      addEventProcessor(callback) {
          this._eventProcessors.push(callback);
          return this;
      }
      /**
       * This will be called on every set call.
       */
      _notifyScopeListeners() {
          if (!this._notifyingListeners) {
              this._notifyingListeners = true;
              setTimeout(() => {
                  this._scopeListeners.forEach(callback => {
                      callback(this);
                  });
                  this._notifyingListeners = false;
              });
          }
      }
      /**
       * This will be called after {@link applyToEvent} is finished.
       */
      _notifyEventProcessors(processors, event, hint, index = 0) {
          return new SyncPromise((resolve, reject) => {
              const processor = processors[index];
              // tslint:disable-next-line:strict-type-predicates
              if (event === null || typeof processor !== 'function') {
                  resolve(event);
              }
              else {
                  const result = processor(Object.assign({}, event), hint);
                  if (isThenable(result)) {
                      result
                          .then(final => this._notifyEventProcessors(processors, final, hint, index + 1).then(resolve))
                          .then(null, reject);
                  }
                  else {
                      this._notifyEventProcessors(processors, result, hint, index + 1)
                          .then(resolve)
                          .then(null, reject);
                  }
              }
          });
      }
      /**
       * @inheritDoc
       */
      setUser(user) {
          this._user = user || {};
          this._notifyScopeListeners();
          return this;
      }
      /**
       * @inheritDoc
       */
      setTags(tags) {
          this._tags = Object.assign({}, this._tags, tags);
          this._notifyScopeListeners();
          return this;
      }
      /**
       * @inheritDoc
       */
      setTag(key, value) {
          this._tags = Object.assign({}, this._tags, { [key]: value });
          this._notifyScopeListeners();
          return this;
      }
      /**
       * @inheritDoc
       */
      setExtras(extras) {
          this._extra = Object.assign({}, this._extra, extras);
          this._notifyScopeListeners();
          return this;
      }
      /**
       * @inheritDoc
       */
      setExtra(key, extra) {
          this._extra = Object.assign({}, this._extra, { [key]: extra });
          this._notifyScopeListeners();
          return this;
      }
      /**
       * @inheritDoc
       */
      setFingerprint(fingerprint) {
          this._fingerprint = fingerprint;
          this._notifyScopeListeners();
          return this;
      }
      /**
       * @inheritDoc
       */
      setLevel(level) {
          this._level = level;
          this._notifyScopeListeners();
          return this;
      }
      /**
       * @inheritDoc
       */
      setTransaction(transaction) {
          this._transaction = transaction;
          if (this._span) {
              this._span.transaction = transaction;
          }
          this._notifyScopeListeners();
          return this;
      }
      /**
       * @inheritDoc
       */
      setContext(key, context) {
          this._context = Object.assign({}, this._context, { [key]: context });
          this._notifyScopeListeners();
          return this;
      }
      /**
       * @inheritDoc
       */
      setSpan(span) {
          this._span = span;
          this._notifyScopeListeners();
          return this;
      }
      /**
       * Internal getter for Span, used in Hub.
       * @hidden
       */
      getSpan() {
          return this._span;
      }
      /**
       * Inherit values from the parent scope.
       * @param scope to clone.
       */
      static clone(scope) {
          const newScope = new Scope();
          if (scope) {
              newScope._breadcrumbs = [...scope._breadcrumbs];
              newScope._tags = Object.assign({}, scope._tags);
              newScope._extra = Object.assign({}, scope._extra);
              newScope._context = Object.assign({}, scope._context);
              newScope._user = scope._user;
              newScope._level = scope._level;
              newScope._span = scope._span;
              newScope._transaction = scope._transaction;
              newScope._fingerprint = scope._fingerprint;
              newScope._eventProcessors = [...scope._eventProcessors];
          }
          return newScope;
      }
      /**
       * @inheritDoc
       */
      clear() {
          this._breadcrumbs = [];
          this._tags = {};
          this._extra = {};
          this._user = {};
          this._context = {};
          this._level = undefined;
          this._transaction = undefined;
          this._fingerprint = undefined;
          this._span = undefined;
          this._notifyScopeListeners();
          return this;
      }
      /**
       * @inheritDoc
       */
      addBreadcrumb(breadcrumb, maxBreadcrumbs) {
          const mergedBreadcrumb = Object.assign({ timestamp: timestampWithMs() }, breadcrumb);
          this._breadcrumbs =
              maxBreadcrumbs !== undefined && maxBreadcrumbs >= 0
                  ? [...this._breadcrumbs, mergedBreadcrumb].slice(-maxBreadcrumbs)
                  : [...this._breadcrumbs, mergedBreadcrumb];
          this._notifyScopeListeners();
          return this;
      }
      /**
       * @inheritDoc
       */
      clearBreadcrumbs() {
          this._breadcrumbs = [];
          this._notifyScopeListeners();
          return this;
      }
      /**
       * Applies fingerprint from the scope to the event if there's one,
       * uses message if there's one instead or get rid of empty fingerprint
       */
      _applyFingerprint(event) {
          // Make sure it's an array first and we actually have something in place
          event.fingerprint = event.fingerprint
              ? Array.isArray(event.fingerprint)
                  ? event.fingerprint
                  : [event.fingerprint]
              : [];
          // If we have something on the scope, then merge it with event
          if (this._fingerprint) {
              event.fingerprint = event.fingerprint.concat(this._fingerprint);
          }
          // If we have no data at all, remove empty array default
          if (event.fingerprint && !event.fingerprint.length) {
              delete event.fingerprint;
          }
      }
      /**
       * Applies the current context and fingerprint to the event.
       * Note that breadcrumbs will be added by the client.
       * Also if the event has already breadcrumbs on it, we do not merge them.
       * @param event Event
       * @param hint May contain additional informartion about the original exception.
       * @hidden
       */
      applyToEvent(event, hint) {
          if (this._extra && Object.keys(this._extra).length) {
              event.extra = Object.assign({}, this._extra, event.extra);
          }
          if (this._tags && Object.keys(this._tags).length) {
              event.tags = Object.assign({}, this._tags, event.tags);
          }
          if (this._user && Object.keys(this._user).length) {
              event.user = Object.assign({}, this._user, event.user);
          }
          if (this._context && Object.keys(this._context).length) {
              event.contexts = Object.assign({}, this._context, event.contexts);
          }
          if (this._level) {
              event.level = this._level;
          }
          if (this._transaction) {
              event.transaction = this._transaction;
          }
          this._applyFingerprint(event);
          event.breadcrumbs = [...(event.breadcrumbs || []), ...this._breadcrumbs];
          event.breadcrumbs = event.breadcrumbs.length > 0 ? event.breadcrumbs : undefined;
          return this._notifyEventProcessors([...getGlobalEventProcessors(), ...this._eventProcessors], event, hint);
      }
  }
  /**
   * Retruns the global event processors.
   */
  function getGlobalEventProcessors() {
      const global = getGlobalObject();
      global.__SENTRY__ = global.__SENTRY__ || {};
      global.__SENTRY__.globalEventProcessors = global.__SENTRY__.globalEventProcessors || [];
      return global.__SENTRY__.globalEventProcessors;
  }
  /**
   * Add a EventProcessor to be kept globally.
   * @param callback EventProcessor to add
   */
  function addGlobalEventProcessor(callback) {
      getGlobalEventProcessors().push(callback);
  }

  /**
   * API compatibility version of this hub.
   *
   * WARNING: This number should only be incresed when the global interface
   * changes a and new methods are introduced.
   *
   * @hidden
   */
  const API_VERSION = 3;
  /**
   * Default maximum number of breadcrumbs added to an event. Can be overwritten
   * with {@link Options.maxBreadcrumbs}.
   */
  const DEFAULT_BREADCRUMBS = 100;
  /**
   * Absolute maximum number of breadcrumbs added to an event. The
   * `maxBreadcrumbs` option cannot be higher than this value.
   */
  const MAX_BREADCRUMBS = 100;
  /**
   * @inheritDoc
   */
  class Hub {
      /**
       * Creates a new instance of the hub, will push one {@link Layer} into the
       * internal stack on creation.
       *
       * @param client bound to the hub.
       * @param scope bound to the hub.
       * @param version number, higher number means higher priority.
       */
      constructor(client, scope = new Scope(), _version = API_VERSION) {
          this._version = _version;
          /** Is a {@link Layer}[] containing the client and scope */
          this._stack = [];
          this._stack.push({ client, scope });
      }
      /**
       * Internal helper function to call a method on the top client if it exists.
       *
       * @param method The method to call on the client.
       * @param args Arguments to pass to the client function.
       */
      _invokeClient(method, ...args) {
          const top = this.getStackTop();
          if (top && top.client && top.client[method]) {
              top.client[method](...args, top.scope);
          }
      }
      /**
       * @inheritDoc
       */
      isOlderThan(version) {
          return this._version < version;
      }
      /**
       * @inheritDoc
       */
      bindClient(client) {
          const top = this.getStackTop();
          top.client = client;
      }
      /**
       * @inheritDoc
       */
      pushScope() {
          // We want to clone the content of prev scope
          const stack = this.getStack();
          const parentScope = stack.length > 0 ? stack[stack.length - 1].scope : undefined;
          const scope = Scope.clone(parentScope);
          this.getStack().push({
              client: this.getClient(),
              scope,
          });
          return scope;
      }
      /**
       * @inheritDoc
       */
      popScope() {
          return this.getStack().pop() !== undefined;
      }
      /**
       * @inheritDoc
       */
      withScope(callback) {
          const scope = this.pushScope();
          try {
              callback(scope);
          }
          finally {
              this.popScope();
          }
      }
      /**
       * @inheritDoc
       */
      getClient() {
          return this.getStackTop().client;
      }
      /** Returns the scope of the top stack. */
      getScope() {
          return this.getStackTop().scope;
      }
      /** Returns the scope stack for domains or the process. */
      getStack() {
          return this._stack;
      }
      /** Returns the topmost scope layer in the order domain > local > process. */
      getStackTop() {
          return this._stack[this._stack.length - 1];
      }
      /**
       * @inheritDoc
       */
      captureException(exception, hint) {
          const eventId = (this._lastEventId = uuid4());
          let finalHint = hint;
          // If there's no explicit hint provided, mimick the same thing that would happen
          // in the minimal itself to create a consistent behavior.
          // We don't do this in the client, as it's the lowest level API, and doing this,
          // would prevent user from having full control over direct calls.
          if (!hint) {
              let syntheticException;
              try {
                  throw new Error('Sentry syntheticException');
              }
              catch (exception) {
                  syntheticException = exception;
              }
              finalHint = {
                  originalException: exception,
                  syntheticException,
              };
          }
          this._invokeClient('captureException', exception, Object.assign({}, finalHint, { event_id: eventId }));
          return eventId;
      }
      /**
       * @inheritDoc
       */
      captureMessage(message, level, hint) {
          const eventId = (this._lastEventId = uuid4());
          let finalHint = hint;
          // If there's no explicit hint provided, mimick the same thing that would happen
          // in the minimal itself to create a consistent behavior.
          // We don't do this in the client, as it's the lowest level API, and doing this,
          // would prevent user from having full control over direct calls.
          if (!hint) {
              let syntheticException;
              try {
                  throw new Error(message);
              }
              catch (exception) {
                  syntheticException = exception;
              }
              finalHint = {
                  originalException: message,
                  syntheticException,
              };
          }
          this._invokeClient('captureMessage', message, level, Object.assign({}, finalHint, { event_id: eventId }));
          return eventId;
      }
      /**
       * @inheritDoc
       */
      captureEvent(event, hint) {
          const eventId = (this._lastEventId = uuid4());
          this._invokeClient('captureEvent', event, Object.assign({}, hint, { event_id: eventId }));
          return eventId;
      }
      /**
       * @inheritDoc
       */
      lastEventId() {
          return this._lastEventId;
      }
      /**
       * @inheritDoc
       */
      addBreadcrumb(breadcrumb, hint) {
          const top = this.getStackTop();
          if (!top.scope || !top.client) {
              return;
          }
          const { beforeBreadcrumb = null, maxBreadcrumbs = DEFAULT_BREADCRUMBS } = (top.client.getOptions && top.client.getOptions()) || {};
          if (maxBreadcrumbs <= 0) {
              return;
          }
          const timestamp = timestampWithMs();
          const mergedBreadcrumb = Object.assign({ timestamp }, breadcrumb);
          const finalBreadcrumb = beforeBreadcrumb
              ? consoleSandbox(() => beforeBreadcrumb(mergedBreadcrumb, hint))
              : mergedBreadcrumb;
          if (finalBreadcrumb === null) {
              return;
          }
          top.scope.addBreadcrumb(finalBreadcrumb, Math.min(maxBreadcrumbs, MAX_BREADCRUMBS));
      }
      /**
       * @inheritDoc
       */
      setUser(user) {
          const top = this.getStackTop();
          if (!top.scope) {
              return;
          }
          top.scope.setUser(user);
      }
      /**
       * @inheritDoc
       */
      setTags(tags) {
          const top = this.getStackTop();
          if (!top.scope) {
              return;
          }
          top.scope.setTags(tags);
      }
      /**
       * @inheritDoc
       */
      setExtras(extras) {
          const top = this.getStackTop();
          if (!top.scope) {
              return;
          }
          top.scope.setExtras(extras);
      }
      /**
       * @inheritDoc
       */
      setTag(key, value) {
          const top = this.getStackTop();
          if (!top.scope) {
              return;
          }
          top.scope.setTag(key, value);
      }
      /**
       * @inheritDoc
       */
      setExtra(key, extra) {
          const top = this.getStackTop();
          if (!top.scope) {
              return;
          }
          top.scope.setExtra(key, extra);
      }
      /**
       * @inheritDoc
       */
      setContext(name, context) {
          const top = this.getStackTop();
          if (!top.scope) {
              return;
          }
          top.scope.setContext(name, context);
      }
      /**
       * @inheritDoc
       */
      configureScope(callback) {
          const top = this.getStackTop();
          if (top.scope && top.client) {
              callback(top.scope);
          }
      }
      /**
       * @inheritDoc
       */
      run(callback) {
          const oldHub = makeMain(this);
          try {
              callback(this);
          }
          finally {
              makeMain(oldHub);
          }
      }
      /**
       * @inheritDoc
       */
      getIntegration(integration) {
          const client = this.getClient();
          if (!client) {
              return null;
          }
          try {
              return client.getIntegration(integration);
          }
          catch (_oO) {
              logger.warn(`Cannot retrieve integration ${integration.id} from the current Hub`);
              return null;
          }
      }
      /**
       * @inheritDoc
       */
      startSpan(spanOrSpanContext, forceNoChild = false) {
          return this._callExtensionMethod('startSpan', spanOrSpanContext, forceNoChild);
      }
      /**
       * @inheritDoc
       */
      traceHeaders() {
          return this._callExtensionMethod('traceHeaders');
      }
      /**
       * Calls global extension method and binding current instance to the function call
       */
      // @ts-ignore
      _callExtensionMethod(method, ...args) {
          const carrier = getMainCarrier();
          const sentry = carrier.__SENTRY__;
          // tslint:disable-next-line: strict-type-predicates
          if (sentry && sentry.extensions && typeof sentry.extensions[method] === 'function') {
              return sentry.extensions[method].apply(this, args);
          }
          logger.warn(`Extension method ${method} couldn't be found, doing nothing.`);
      }
  }
  /** Returns the global shim registry. */
  function getMainCarrier() {
      const carrier = getGlobalObject();
      carrier.__SENTRY__ = carrier.__SENTRY__ || {
          extensions: {},
          hub: undefined,
      };
      return carrier;
  }
  /**
   * Replaces the current main hub with the passed one on the global object
   *
   * @returns The old replaced hub
   */
  function makeMain(hub) {
      const registry = getMainCarrier();
      const oldHub = getHubFromCarrier(registry);
      setHubOnCarrier(registry, hub);
      return oldHub;
  }
  /**
   * Returns the default hub instance.
   *
   * If a hub is already registered in the global carrier but this module
   * contains a more recent version, it replaces the registered version.
   * Otherwise, the currently registered hub will be returned.
   */
  function getCurrentHub() {
      // Get main carrier (global for every environment)
      const registry = getMainCarrier();
      // If there's no hub, or its an old API, assign a new one
      if (!hasHubOnCarrier(registry) || getHubFromCarrier(registry).isOlderThan(API_VERSION)) {
          setHubOnCarrier(registry, new Hub());
      }
      // Prefer domains over global if they are there (applicable only to Node environment)
      if (isNodeEnv()) {
          return getHubFromActiveDomain(registry);
      }
      // Return hub that lives on a global object
      return getHubFromCarrier(registry);
  }
  /**
   * Try to read the hub from an active domain, fallback to the registry if one doesnt exist
   * @returns discovered hub
   */
  function getHubFromActiveDomain(registry) {
      try {
          // We need to use `dynamicRequire` because `require` on it's own will be optimized by webpack.
          // We do not want this to happen, we need to try to `require` the domain node module and fail if we are in browser
          // for example so we do not have to shim it and use `getCurrentHub` universally.
          const domain = dynamicRequire(module, 'domain');
          const activeDomain = domain.active;
          // If there no active domain, just return global hub
          if (!activeDomain) {
              return getHubFromCarrier(registry);
          }
          // If there's no hub on current domain, or its an old API, assign a new one
          if (!hasHubOnCarrier(activeDomain) || getHubFromCarrier(activeDomain).isOlderThan(API_VERSION)) {
              const registryHubTopStack = getHubFromCarrier(registry).getStackTop();
              setHubOnCarrier(activeDomain, new Hub(registryHubTopStack.client, Scope.clone(registryHubTopStack.scope)));
          }
          // Return hub that lives on a domain
          return getHubFromCarrier(activeDomain);
      }
      catch (_Oo) {
          // Return hub that lives on a global object
          return getHubFromCarrier(registry);
      }
  }
  /**
   * This will tell whether a carrier has a hub on it or not
   * @param carrier object
   */
  function hasHubOnCarrier(carrier) {
      if (carrier && carrier.__SENTRY__ && carrier.__SENTRY__.hub) {
          return true;
      }
      return false;
  }
  /**
   * This will create a new {@link Hub} and add to the passed object on
   * __SENTRY__.hub.
   * @param carrier object
   * @hidden
   */
  function getHubFromCarrier(carrier) {
      if (carrier && carrier.__SENTRY__ && carrier.__SENTRY__.hub) {
          return carrier.__SENTRY__.hub;
      }
      carrier.__SENTRY__ = carrier.__SENTRY__ || {};
      carrier.__SENTRY__.hub = new Hub();
      return carrier.__SENTRY__.hub;
  }
  /**
   * This will set passed {@link Hub} on the passed object's __SENTRY__.hub attribute
   * @param carrier object
   * @param hub Hub
   */
  function setHubOnCarrier(carrier, hub) {
      if (!carrier) {
          return false;
      }
      carrier.__SENTRY__ = carrier.__SENTRY__ || {};
      carrier.__SENTRY__.hub = hub;
      return true;
  }

  /**
   * This calls a function on the current hub.
   * @param method function to call on hub.
   * @param args to pass to function.
   */
  function callOnHub(method, ...args) {
      const hub = getCurrentHub();
      if (hub && hub[method]) {
          // tslint:disable-next-line:no-unsafe-any
          return hub[method](...args);
      }
      throw new Error(`No hub defined or ${method} was not found on the hub, please open a bug report.`);
  }
  /**
   * Captures an exception event and sends it to Sentry.
   *
   * @param exception An exception-like object.
   * @returns The generated eventId.
   */
  function captureException(exception) {
      let syntheticException;
      try {
          throw new Error('Sentry syntheticException');
      }
      catch (exception) {
          syntheticException = exception;
      }
      return callOnHub('captureException', exception, {
          originalException: exception,
          syntheticException,
      });
  }
  /**
   * Captures a message event and sends it to Sentry.
   *
   * @param message The message to send to Sentry.
   * @param level Define the level of the message.
   * @returns The generated eventId.
   */
  function captureMessage(message, level) {
      let syntheticException;
      try {
          throw new Error(message);
      }
      catch (exception) {
          syntheticException = exception;
      }
      return callOnHub('captureMessage', message, level, {
          originalException: message,
          syntheticException,
      });
  }
  /**
   * Captures a manually created event and sends it to Sentry.
   *
   * @param event The event to send to Sentry.
   * @returns The generated eventId.
   */
  function captureEvent(event) {
      return callOnHub('captureEvent', event);
  }
  /**
   * Callback to set context information onto the scope.
   * @param callback Callback function that receives Scope.
   */
  function configureScope(callback) {
      callOnHub('configureScope', callback);
  }
  /**
   * Records a new breadcrumb which will be attached to future events.
   *
   * Breadcrumbs will be added to subsequent events to provide more context on
   * user's actions prior to an error or crash.
   *
   * @param breadcrumb The breadcrumb to record.
   */
  function addBreadcrumb(breadcrumb) {
      callOnHub('addBreadcrumb', breadcrumb);
  }
  /**
   * Sets context data with the given name.
   * @param name of the context
   * @param context Any kind of data. This data will be normailzed.
   */
  function setContext(name, context) {
      callOnHub('setContext', name, context);
  }
  /**
   * Set an object that will be merged sent as extra data with the event.
   * @param extras Extras object to merge into current context.
   */
  function setExtras(extras) {
      callOnHub('setExtras', extras);
  }
  /**
   * Set an object that will be merged sent as tags data with the event.
   * @param tags Tags context object to merge into current context.
   */
  function setTags(tags) {
      callOnHub('setTags', tags);
  }
  /**
   * Set key:value that will be sent as extra data with the event.
   * @param key String of extra
   * @param extra Any kind of data. This data will be normailzed.
   */
  function setExtra(key, extra) {
      callOnHub('setExtra', key, extra);
  }
  /**
   * Set key:value that will be sent as tags data with the event.
   * @param key String key of tag
   * @param value String value of tag
   */
  function setTag(key, value) {
      callOnHub('setTag', key, value);
  }
  /**
   * Updates user context information for future events.
   *
   * @param user User context object to be set in the current context. Pass `null` to unset the user.
   */
  function setUser(user) {
      callOnHub('setUser', user);
  }
  /**
   * Creates a new scope with and executes the given operation within.
   * The scope is automatically removed once the operation
   * finishes or throws.
   *
   * This is essentially a convenience function for:
   *
   *     pushScope();
   *     callback();
   *     popScope();
   *
   * @param callback that will be enclosed into push/popScope.
   */
  function withScope(callback) {
      callOnHub('withScope', callback);
  }

  const SENTRY_API_VERSION = '7';
  /** Helper class to provide urls to different Sentry endpoints. */
  class API {
      /** Create a new instance of API */
      constructor(dsn) {
          this.dsn = dsn;
          this._dsnObject = new Dsn(dsn);
      }
      /** Returns the Dsn object. */
      getDsn() {
          return this._dsnObject;
      }
      /** Returns a string with auth headers in the url to the store endpoint. */
      getStoreEndpoint() {
          return `${this._getBaseUrl()}${this.getStoreEndpointPath()}`;
      }
      /** Returns the store endpoint with auth added in url encoded. */
      getStoreEndpointWithUrlEncodedAuth() {
          const dsn = this._dsnObject;
          const auth = {
              sentry_key: dsn.user,
              sentry_version: SENTRY_API_VERSION,
          };
          // Auth is intentionally sent as part of query string (NOT as custom HTTP header)
          // to avoid preflight CORS requests
          return `${this.getStoreEndpoint()}?${urlEncode(auth)}`;
      }
      /** Returns the base path of the url including the port. */
      _getBaseUrl() {
          const dsn = this._dsnObject;
          const protocol = dsn.protocol ? `${dsn.protocol}:` : '';
          const port = dsn.port ? `:${dsn.port}` : '';
          return `${protocol}//${dsn.host}${port}`;
      }
      /** Returns only the path component for the store endpoint. */
      getStoreEndpointPath() {
          const dsn = this._dsnObject;
          return `${dsn.path ? `/${dsn.path}` : ''}/api/${dsn.projectId}/store/`;
      }
      /** Returns an object that can be used in request headers. */
      getRequestHeaders(clientName, clientVersion) {
          const dsn = this._dsnObject;
          const header = [`Sentry sentry_version=${SENTRY_API_VERSION}`];
          header.push(`sentry_client=${clientName}/${clientVersion}`);
          header.push(`sentry_key=${dsn.user}`);
          if (dsn.pass) {
              header.push(`sentry_secret=${dsn.pass}`);
          }
          return {
              'Content-Type': 'application/json',
              'X-Sentry-Auth': header.join(', '),
          };
      }
      /** Returns the url to the report dialog endpoint. */
      getReportDialogEndpoint(dialogOptions = {}) {
          const dsn = this._dsnObject;
          const endpoint = `${this._getBaseUrl()}${dsn.path ? `/${dsn.path}` : ''}/api/embed/error-page/`;
          const encodedOptions = [];
          encodedOptions.push(`dsn=${dsn.toString()}`);
          for (const key in dialogOptions) {
              if (key === 'user') {
                  if (!dialogOptions.user) {
                      continue;
                  }
                  if (dialogOptions.user.name) {
                      encodedOptions.push(`name=${encodeURIComponent(dialogOptions.user.name)}`);
                  }
                  if (dialogOptions.user.email) {
                      encodedOptions.push(`email=${encodeURIComponent(dialogOptions.user.email)}`);
                  }
              }
              else {
                  encodedOptions.push(`${encodeURIComponent(key)}=${encodeURIComponent(dialogOptions[key])}`);
              }
          }
          if (encodedOptions.length) {
              return `${endpoint}?${encodedOptions.join('&')}`;
          }
          return endpoint;
      }
  }

  const installedIntegrations = [];
  /** Gets integration to install */
  function getIntegrationsToSetup(options) {
      const defaultIntegrations = (options.defaultIntegrations && [...options.defaultIntegrations]) || [];
      const userIntegrations = options.integrations;
      let integrations = [];
      if (Array.isArray(userIntegrations)) {
          const userIntegrationsNames = userIntegrations.map(i => i.name);
          const pickedIntegrationsNames = [];
          // Leave only unique default integrations, that were not overridden with provided user integrations
          defaultIntegrations.forEach(defaultIntegration => {
              if (userIntegrationsNames.indexOf(defaultIntegration.name) === -1 &&
                  pickedIntegrationsNames.indexOf(defaultIntegration.name) === -1) {
                  integrations.push(defaultIntegration);
                  pickedIntegrationsNames.push(defaultIntegration.name);
              }
          });
          // Don't add same user integration twice
          userIntegrations.forEach(userIntegration => {
              if (pickedIntegrationsNames.indexOf(userIntegration.name) === -1) {
                  integrations.push(userIntegration);
                  pickedIntegrationsNames.push(userIntegration.name);
              }
          });
      }
      else if (typeof userIntegrations === 'function') {
          integrations = userIntegrations(defaultIntegrations);
          integrations = Array.isArray(integrations) ? integrations : [integrations];
      }
      else {
          integrations = [...defaultIntegrations];
      }
      // Make sure that if present, `Debug` integration will always run last
      const integrationsNames = integrations.map(i => i.name);
      const alwaysLastToRun = 'Debug';
      if (integrationsNames.indexOf(alwaysLastToRun) !== -1) {
          integrations.push(...integrations.splice(integrationsNames.indexOf(alwaysLastToRun), 1));
      }
      return integrations;
  }
  /** Setup given integration */
  function setupIntegration(integration) {
      if (installedIntegrations.indexOf(integration.name) !== -1) {
          return;
      }
      integration.setupOnce(addGlobalEventProcessor, getCurrentHub);
      installedIntegrations.push(integration.name);
      logger.log(`Integration installed: ${integration.name}`);
  }
  /**
   * Given a list of integration instances this installs them all. When `withDefaults` is set to `true` then all default
   * integrations are added unless they were already provided before.
   * @param integrations array of integration instances
   * @param withDefault should enable default integrations
   */
  function setupIntegrations(options) {
      const integrations = {};
      getIntegrationsToSetup(options).forEach(integration => {
          integrations[integration.name] = integration;
          setupIntegration(integration);
      });
      return integrations;
  }

  /**
   * Base implementation for all JavaScript SDK clients.
   *
   * Call the constructor with the corresponding backend constructor and options
   * specific to the client subclass. To access these options later, use
   * {@link Client.getOptions}. Also, the Backend instance is available via
   * {@link Client.getBackend}.
   *
   * If a Dsn is specified in the options, it will be parsed and stored. Use
   * {@link Client.getDsn} to retrieve the Dsn at any moment. In case the Dsn is
   * invalid, the constructor will throw a {@link SentryException}. Note that
   * without a valid Dsn, the SDK will not send any events to Sentry.
   *
   * Before sending an event via the backend, it is passed through
   * {@link BaseClient.prepareEvent} to add SDK information and scope data
   * (breadcrumbs and context). To add more custom information, override this
   * method and extend the resulting prepared event.
   *
   * To issue automatically created events (e.g. via instrumentation), use
   * {@link Client.captureEvent}. It will prepare the event and pass it through
   * the callback lifecycle. To issue auto-breadcrumbs, use
   * {@link Client.addBreadcrumb}.
   *
   * @example
   * class NodeClient extends BaseClient<NodeBackend, NodeOptions> {
   *   public constructor(options: NodeOptions) {
   *     super(NodeBackend, options);
   *   }
   *
   *   // ...
   * }
   */
  class BaseClient {
      /**
       * Initializes this client instance.
       *
       * @param backendClass A constructor function to create the backend.
       * @param options Options for the client.
       */
      constructor(backendClass, options) {
          /** Array of used integrations. */
          this._integrations = {};
          /** Is the client still processing a call? */
          this._processing = false;
          this._backend = new backendClass(options);
          this._options = options;
          if (options.dsn) {
              this._dsn = new Dsn(options.dsn);
          }
          if (this._isEnabled()) {
              this._integrations = setupIntegrations(this._options);
          }
      }
      /**
       * @inheritDoc
       */
      captureException(exception, hint, scope) {
          let eventId = hint && hint.event_id;
          this._processing = true;
          this._getBackend()
              .eventFromException(exception, hint)
              .then(event => this._processEvent(event, hint, scope))
              .then(finalEvent => {
              // We need to check for finalEvent in case beforeSend returned null
              eventId = finalEvent && finalEvent.event_id;
              this._processing = false;
          })
              .then(null, reason => {
              logger.error(reason);
              this._processing = false;
          });
          return eventId;
      }
      /**
       * @inheritDoc
       */
      captureMessage(message, level, hint, scope) {
          let eventId = hint && hint.event_id;
          this._processing = true;
          const promisedEvent = isPrimitive(message)
              ? this._getBackend().eventFromMessage(`${message}`, level, hint)
              : this._getBackend().eventFromException(message, hint);
          promisedEvent
              .then(event => this._processEvent(event, hint, scope))
              .then(finalEvent => {
              // We need to check for finalEvent in case beforeSend returned null
              eventId = finalEvent && finalEvent.event_id;
              this._processing = false;
          })
              .then(null, reason => {
              logger.error(reason);
              this._processing = false;
          });
          return eventId;
      }
      /**
       * @inheritDoc
       */
      captureEvent(event, hint, scope) {
          let eventId = hint && hint.event_id;
          this._processing = true;
          this._processEvent(event, hint, scope)
              .then(finalEvent => {
              // We need to check for finalEvent in case beforeSend returned null
              eventId = finalEvent && finalEvent.event_id;
              this._processing = false;
          })
              .then(null, reason => {
              logger.error(reason);
              this._processing = false;
          });
          return eventId;
      }
      /**
       * @inheritDoc
       */
      getDsn() {
          return this._dsn;
      }
      /**
       * @inheritDoc
       */
      getOptions() {
          return this._options;
      }
      /**
       * @inheritDoc
       */
      flush(timeout) {
          return this._isClientProcessing(timeout).then(status => {
              clearInterval(status.interval);
              return this._getBackend()
                  .getTransport()
                  .close(timeout)
                  .then(transportFlushed => status.ready && transportFlushed);
          });
      }
      /**
       * @inheritDoc
       */
      close(timeout) {
          return this.flush(timeout).then(result => {
              this.getOptions().enabled = false;
              return result;
          });
      }
      /**
       * @inheritDoc
       */
      getIntegrations() {
          return this._integrations || {};
      }
      /**
       * @inheritDoc
       */
      getIntegration(integration) {
          try {
              return this._integrations[integration.id] || null;
          }
          catch (_oO) {
              logger.warn(`Cannot retrieve integration ${integration.id} from the current Client`);
              return null;
          }
      }
      /** Waits for the client to be done with processing. */
      _isClientProcessing(timeout) {
          return new SyncPromise(resolve => {
              let ticked = 0;
              const tick = 1;
              let interval = 0;
              clearInterval(interval);
              interval = setInterval(() => {
                  if (!this._processing) {
                      resolve({
                          interval,
                          ready: true,
                      });
                  }
                  else {
                      ticked += tick;
                      if (timeout && ticked >= timeout) {
                          resolve({
                              interval,
                              ready: false,
                          });
                      }
                  }
              }, tick);
          });
      }
      /** Returns the current backend. */
      _getBackend() {
          return this._backend;
      }
      /** Determines whether this SDK is enabled and a valid Dsn is present. */
      _isEnabled() {
          return this.getOptions().enabled !== false && this._dsn !== undefined;
      }
      /**
       * Adds common information to events.
       *
       * The information includes release and environment from `options`,
       * breadcrumbs and context (extra, tags and user) from the scope.
       *
       * Information that is already present in the event is never overwritten. For
       * nested objects, such as the context, keys are merged.
       *
       * @param event The original event.
       * @param hint May contain additional informartion about the original exception.
       * @param scope A scope containing event metadata.
       * @returns A new event with more information.
       */
      _prepareEvent(event, scope, hint) {
          const { environment, release, dist, maxValueLength = 250, normalizeDepth = 3 } = this.getOptions();
          const prepared = Object.assign({}, event);
          if (prepared.environment === undefined && environment !== undefined) {
              prepared.environment = environment;
          }
          if (prepared.release === undefined && release !== undefined) {
              prepared.release = release;
          }
          if (prepared.dist === undefined && dist !== undefined) {
              prepared.dist = dist;
          }
          if (prepared.message) {
              prepared.message = truncate(prepared.message, maxValueLength);
          }
          const exception = prepared.exception && prepared.exception.values && prepared.exception.values[0];
          if (exception && exception.value) {
              exception.value = truncate(exception.value, maxValueLength);
          }
          const request = prepared.request;
          if (request && request.url) {
              request.url = truncate(request.url, maxValueLength);
          }
          if (prepared.event_id === undefined) {
              prepared.event_id = hint && hint.event_id ? hint.event_id : uuid4();
          }
          this._addIntegrations(prepared.sdk);
          // We prepare the result here with a resolved Event.
          let result = SyncPromise.resolve(prepared);
          // This should be the last thing called, since we want that
          // {@link Hub.addEventProcessor} gets the finished prepared event.
          if (scope) {
              // In case we have a hub we reassign it.
              result = scope.applyToEvent(prepared, hint);
          }
          return result.then(evt => {
              // tslint:disable-next-line:strict-type-predicates
              if (typeof normalizeDepth === 'number' && normalizeDepth > 0) {
                  return this._normalizeEvent(evt, normalizeDepth);
              }
              return evt;
          });
      }
      /**
       * Applies `normalize` function on necessary `Event` attributes to make them safe for serialization.
       * Normalized keys:
       * - `breadcrumbs.data`
       * - `user`
       * - `contexts`
       * - `extra`
       * @param event Event
       * @returns Normalized event
       */
      _normalizeEvent(event, depth) {
          if (!event) {
              return null;
          }
          // tslint:disable:no-unsafe-any
          return Object.assign({}, event, (event.breadcrumbs && {
              breadcrumbs: event.breadcrumbs.map(b => (Object.assign({}, b, (b.data && {
                  data: normalize(b.data, depth),
              })))),
          }), (event.user && {
              user: normalize(event.user, depth),
          }), (event.contexts && {
              contexts: normalize(event.contexts, depth),
          }), (event.extra && {
              extra: normalize(event.extra, depth),
          }));
      }
      /**
       * This function adds all used integrations to the SDK info in the event.
       * @param sdkInfo The sdkInfo of the event that will be filled with all integrations.
       */
      _addIntegrations(sdkInfo) {
          const integrationsArray = Object.keys(this._integrations);
          if (sdkInfo && integrationsArray.length > 0) {
              sdkInfo.integrations = integrationsArray;
          }
      }
      /**
       * Processes an event (either error or message) and sends it to Sentry.
       *
       * This also adds breadcrumbs and context information to the event. However,
       * platform specific meta data (such as the User's IP address) must be added
       * by the SDK implementor.
       *
       *
       * @param event The event to send to Sentry.
       * @param hint May contain additional informartion about the original exception.
       * @param scope A scope containing event metadata.
       * @returns A SyncPromise that resolves with the event or rejects in case event was/will not be send.
       */
      _processEvent(event, hint, scope) {
          const { beforeSend, sampleRate } = this.getOptions();
          if (!this._isEnabled()) {
              return SyncPromise.reject('SDK not enabled, will not send event.');
          }
          // 1.0 === 100% events are sent
          // 0.0 === 0% events are sent
          if (typeof sampleRate === 'number' && Math.random() > sampleRate) {
              return SyncPromise.reject('This event has been sampled, will not send event.');
          }
          return new SyncPromise((resolve, reject) => {
              this._prepareEvent(event, scope, hint)
                  .then(prepared => {
                  if (prepared === null) {
                      reject('An event processor returned null, will not send event.');
                      return;
                  }
                  let finalEvent = prepared;
                  const isInternalException = hint && hint.data && hint.data.__sentry__ === true;
                  if (isInternalException || !beforeSend) {
                      this._getBackend().sendEvent(finalEvent);
                      resolve(finalEvent);
                      return;
                  }
                  const beforeSendResult = beforeSend(prepared, hint);
                  // tslint:disable-next-line:strict-type-predicates
                  if (typeof beforeSendResult === 'undefined') {
                      logger.error('`beforeSend` method has to return `null` or a valid event.');
                  }
                  else if (isThenable(beforeSendResult)) {
                      this._handleAsyncBeforeSend(beforeSendResult, resolve, reject);
                  }
                  else {
                      finalEvent = beforeSendResult;
                      if (finalEvent === null) {
                          logger.log('`beforeSend` returned `null`, will not send event.');
                          resolve(null);
                          return;
                      }
                      // From here on we are really async
                      this._getBackend().sendEvent(finalEvent);
                      resolve(finalEvent);
                  }
              })
                  .then(null, reason => {
                  this.captureException(reason, {
                      data: {
                          __sentry__: true,
                      },
                      originalException: reason,
                  });
                  reject(`Event processing pipeline threw an error, original event will not be sent. Details have been sent as a new event.\nReason: ${reason}`);
              });
          });
      }
      /**
       * Resolves before send Promise and calls resolve/reject on parent SyncPromise.
       */
      _handleAsyncBeforeSend(beforeSend, resolve, reject) {
          beforeSend
              .then(processedEvent => {
              if (processedEvent === null) {
                  reject('`beforeSend` returned `null`, will not send event.');
                  return;
              }
              // From here on we are really async
              this._getBackend().sendEvent(processedEvent);
              resolve(processedEvent);
          })
              .then(null, e => {
              reject(`beforeSend rejected with ${e}`);
          });
      }
  }

  /** Noop transport */
  class NoopTransport {
      /**
       * @inheritDoc
       */
      sendEvent(_) {
          return SyncPromise.resolve({
              reason: `NoopTransport: Event has been skipped because no Dsn is configured.`,
              status: exports.Status.Skipped,
          });
      }
      /**
       * @inheritDoc
       */
      close(_) {
          return SyncPromise.resolve(true);
      }
  }

  /**
   * This is the base implemention of a Backend.
   * @hidden
   */
  class BaseBackend {
      /** Creates a new backend instance. */
      constructor(options) {
          this._options = options;
          if (!this._options.dsn) {
              logger.warn('No DSN provided, backend will not do anything.');
          }
          this._transport = this._setupTransport();
      }
      /**
       * Sets up the transport so it can be used later to send requests.
       */
      _setupTransport() {
          return new NoopTransport();
      }
      /**
       * @inheritDoc
       */
      eventFromException(_exception, _hint) {
          throw new SentryError('Backend has to implement `eventFromException` method');
      }
      /**
       * @inheritDoc
       */
      eventFromMessage(_message, _level, _hint) {
          throw new SentryError('Backend has to implement `eventFromMessage` method');
      }
      /**
       * @inheritDoc
       */
      sendEvent(event) {
          this._transport.sendEvent(event).then(null, reason => {
              logger.error(`Error while sending event: ${reason}`);
          });
      }
      /**
       * @inheritDoc
       */
      getTransport() {
          return this._transport;
      }
  }

  /**
   * Internal function to create a new SDK client instance. The client is
   * installed and then bound to the current scope.
   *
   * @param clientClass The client class to instanciate.
   * @param options Options to pass to the client.
   */
  function initAndBind(clientClass, options) {
      if (options.debug === true) {
          logger.enable();
      }
      getCurrentHub().bindClient(new clientClass(options));
  }

  let originalFunctionToString;
  /** Patch toString calls to return proper name for wrapped functions */
  class FunctionToString {
      constructor() {
          /**
           * @inheritDoc
           */
          this.name = FunctionToString.id;
      }
      /**
       * @inheritDoc
       */
      setupOnce() {
          originalFunctionToString = Function.prototype.toString;
          Function.prototype.toString = function (...args) {
              const context = this.__sentry_original__ || this;
              // tslint:disable-next-line:no-unsafe-any
              return originalFunctionToString.apply(context, args);
          };
      }
  }
  /**
   * @inheritDoc
   */
  FunctionToString.id = 'FunctionToString';

  // "Script error." is hard coded into browsers for errors that it can't read.
  // this is the result of a script being pulled in from an external domain and CORS.
  const DEFAULT_IGNORE_ERRORS = [/^Script error\.?$/, /^Javascript error: Script error\.? on line 0$/];
  /** Inbound filters configurable by the user */
  class InboundFilters {
      constructor(_options = {}) {
          this._options = _options;
          /**
           * @inheritDoc
           */
          this.name = InboundFilters.id;
      }
      /**
       * @inheritDoc
       */
      setupOnce() {
          addGlobalEventProcessor((event) => {
              const hub = getCurrentHub();
              if (!hub) {
                  return event;
              }
              const self = hub.getIntegration(InboundFilters);
              if (self) {
                  const client = hub.getClient();
                  const clientOptions = client ? client.getOptions() : {};
                  const options = self._mergeOptions(clientOptions);
                  if (self._shouldDropEvent(event, options)) {
                      return null;
                  }
              }
              return event;
          });
      }
      /** JSDoc */
      _shouldDropEvent(event, options) {
          if (this._isSentryError(event, options)) {
              logger.warn(`Event dropped due to being internal Sentry Error.\nEvent: ${getEventDescription(event)}`);
              return true;
          }
          if (this._isIgnoredError(event, options)) {
              logger.warn(`Event dropped due to being matched by \`ignoreErrors\` option.\nEvent: ${getEventDescription(event)}`);
              return true;
          }
          if (this._isBlacklistedUrl(event, options)) {
              logger.warn(`Event dropped due to being matched by \`blacklistUrls\` option.\nEvent: ${getEventDescription(event)}.\nUrl: ${this._getEventFilterUrl(event)}`);
              return true;
          }
          if (!this._isWhitelistedUrl(event, options)) {
              logger.warn(`Event dropped due to not being matched by \`whitelistUrls\` option.\nEvent: ${getEventDescription(event)}.\nUrl: ${this._getEventFilterUrl(event)}`);
              return true;
          }
          return false;
      }
      /** JSDoc */
      _isSentryError(event, options = {}) {
          if (!options.ignoreInternal) {
              return false;
          }
          try {
              return ((event &&
                  event.exception &&
                  event.exception.values &&
                  event.exception.values[0] &&
                  event.exception.values[0].type === 'SentryError') ||
                  false);
          }
          catch (_oO) {
              return false;
          }
      }
      /** JSDoc */
      _isIgnoredError(event, options = {}) {
          if (!options.ignoreErrors || !options.ignoreErrors.length) {
              return false;
          }
          return this._getPossibleEventMessages(event).some(message => 
          // Not sure why TypeScript complains here...
          options.ignoreErrors.some(pattern => isMatchingPattern(message, pattern)));
      }
      /** JSDoc */
      _isBlacklistedUrl(event, options = {}) {
          // TODO: Use Glob instead?
          if (!options.blacklistUrls || !options.blacklistUrls.length) {
              return false;
          }
          const url = this._getEventFilterUrl(event);
          return !url ? false : options.blacklistUrls.some(pattern => isMatchingPattern(url, pattern));
      }
      /** JSDoc */
      _isWhitelistedUrl(event, options = {}) {
          // TODO: Use Glob instead?
          if (!options.whitelistUrls || !options.whitelistUrls.length) {
              return true;
          }
          const url = this._getEventFilterUrl(event);
          return !url ? true : options.whitelistUrls.some(pattern => isMatchingPattern(url, pattern));
      }
      /** JSDoc */
      _mergeOptions(clientOptions = {}) {
          return {
              blacklistUrls: [...(this._options.blacklistUrls || []), ...(clientOptions.blacklistUrls || [])],
              ignoreErrors: [
                  ...(this._options.ignoreErrors || []),
                  ...(clientOptions.ignoreErrors || []),
                  ...DEFAULT_IGNORE_ERRORS,
              ],
              ignoreInternal: typeof this._options.ignoreInternal !== 'undefined' ? this._options.ignoreInternal : true,
              whitelistUrls: [...(this._options.whitelistUrls || []), ...(clientOptions.whitelistUrls || [])],
          };
      }
      /** JSDoc */
      _getPossibleEventMessages(event) {
          if (event.message) {
              return [event.message];
          }
          if (event.exception) {
              try {
                  const { type = '', value = '' } = (event.exception.values && event.exception.values[0]) || {};
                  return [`${value}`, `${type}: ${value}`];
              }
              catch (oO) {
                  logger.error(`Cannot extract message for event ${getEventDescription(event)}`);
                  return [];
              }
          }
          return [];
      }
      /** JSDoc */
      _getEventFilterUrl(event) {
          try {
              if (event.stacktrace) {
                  const frames = event.stacktrace.frames;
                  return (frames && frames[frames.length - 1].filename) || null;
              }
              if (event.exception) {
                  const frames = event.exception.values && event.exception.values[0].stacktrace && event.exception.values[0].stacktrace.frames;
                  return (frames && frames[frames.length - 1].filename) || null;
              }
              return null;
          }
          catch (oO) {
              logger.error(`Cannot extract url for event ${getEventDescription(event)}`);
              return null;
          }
      }
  }
  /**
   * @inheritDoc
   */
  InboundFilters.id = 'InboundFilters';



  var CoreIntegrations = /*#__PURE__*/Object.freeze({
    FunctionToString: FunctionToString,
    InboundFilters: InboundFilters
  });

  // tslint:disable:object-literal-sort-keys
  // global reference to slice
  const UNKNOWN_FUNCTION = '?';
  // Chromium based browsers: Chrome, Brave, new Opera, new Edge
  const chrome = /^\s*at (?:(.*?) ?\()?((?:file|https?|blob|chrome-extension|address|native|eval|webpack|<anonymous>|[-a-z]+:|.*bundle|\/).*?)(?::(\d+))?(?::(\d+))?\)?\s*$/i;
  // gecko regex: `(?:bundle|\d+\.js)`: `bundle` is for react native, `\d+\.js` also but specifically for ram bundles because it
  // generates filenames without a prefix like `file://` the filenames in the stacktrace are just 42.js
  // We need this specific case for now because we want no other regex to match.
  const gecko = /^\s*(.*?)(?:\((.*?)\))?(?:^|@)?((?:file|https?|blob|chrome|webpack|resource|moz-extension).*?:\/.*?|\[native code\]|[^@]*(?:bundle|\d+\.js))(?::(\d+))?(?::(\d+))?\s*$/i;
  const winjs = /^\s*at (?:((?:\[object object\])?.+) )?\(?((?:file|ms-appx|https?|webpack|blob):.*?):(\d+)(?::(\d+))?\)?\s*$/i;
  const geckoEval = /(\S+) line (\d+)(?: > eval line \d+)* > eval/i;
  const chromeEval = /\((\S*)(?::(\d+))(?::(\d+))\)/;
  /** JSDoc */
  function computeStackTrace(ex) {
      // tslint:disable:no-unsafe-any
      let stack = null;
      const popSize = ex && ex.framesToPop;
      try {
          // This must be tried first because Opera 10 *destroys*
          // its stacktrace property if you try to access the stack
          // property first!!
          stack = computeStackTraceFromStacktraceProp(ex);
          if (stack) {
              return popFrames(stack, popSize);
          }
      }
      catch (e) {
          // no-empty
      }
      try {
          stack = computeStackTraceFromStackProp(ex);
          if (stack) {
              return popFrames(stack, popSize);
          }
      }
      catch (e) {
          // no-empty
      }
      return {
          message: extractMessage(ex),
          name: ex && ex.name,
          stack: [],
          failed: true,
      };
  }
  /** JSDoc */
  // tslint:disable-next-line:cyclomatic-complexity
  function computeStackTraceFromStackProp(ex) {
      // tslint:disable:no-conditional-assignment
      if (!ex || !ex.stack) {
          return null;
      }
      const stack = [];
      const lines = ex.stack.split('\n');
      let isEval;
      let submatch;
      let parts;
      let element;
      for (let i = 0; i < lines.length; ++i) {
          if ((parts = chrome.exec(lines[i]))) {
              const isNative = parts[2] && parts[2].indexOf('native') === 0; // start of line
              isEval = parts[2] && parts[2].indexOf('eval') === 0; // start of line
              if (isEval && (submatch = chromeEval.exec(parts[2]))) {
                  // throw out eval line/column and use top-most line/column number
                  parts[2] = submatch[1]; // url
                  parts[3] = submatch[2]; // line
                  parts[4] = submatch[3]; // column
              }
              element = {
                  // working with the regexp above is super painful. it is quite a hack, but just stripping the `address at `
                  // prefix here seems like the quickest solution for now.
                  url: parts[2] && parts[2].indexOf('address at ') === 0 ? parts[2].substr('address at '.length) : parts[2],
                  func: parts[1] || UNKNOWN_FUNCTION,
                  args: isNative ? [parts[2]] : [],
                  line: parts[3] ? +parts[3] : null,
                  column: parts[4] ? +parts[4] : null,
              };
          }
          else if ((parts = winjs.exec(lines[i]))) {
              element = {
                  url: parts[2],
                  func: parts[1] || UNKNOWN_FUNCTION,
                  args: [],
                  line: +parts[3],
                  column: parts[4] ? +parts[4] : null,
              };
          }
          else if ((parts = gecko.exec(lines[i]))) {
              isEval = parts[3] && parts[3].indexOf(' > eval') > -1;
              if (isEval && (submatch = geckoEval.exec(parts[3]))) {
                  // throw out eval line/column and use top-most line number
                  parts[1] = parts[1] || `eval`;
                  parts[3] = submatch[1];
                  parts[4] = submatch[2];
                  parts[5] = ''; // no column when eval
              }
              else if (i === 0 && !parts[5] && ex.columnNumber !== void 0) {
                  // FireFox uses this awesome columnNumber property for its top frame
                  // Also note, Firefox's column number is 0-based and everything else expects 1-based,
                  // so adding 1
                  // NOTE: this hack doesn't work if top-most frame is eval
                  stack[0].column = ex.columnNumber + 1;
              }
              element = {
                  url: parts[3],
                  func: parts[1] || UNKNOWN_FUNCTION,
                  args: parts[2] ? parts[2].split(',') : [],
                  line: parts[4] ? +parts[4] : null,
                  column: parts[5] ? +parts[5] : null,
              };
          }
          else {
              continue;
          }
          if (!element.func && element.line) {
              element.func = UNKNOWN_FUNCTION;
          }
          stack.push(element);
      }
      if (!stack.length) {
          return null;
      }
      return {
          message: extractMessage(ex),
          name: ex.name,
          stack,
      };
  }
  /** JSDoc */
  function computeStackTraceFromStacktraceProp(ex) {
      if (!ex || !ex.stacktrace) {
          return null;
      }
      // Access and store the stacktrace property before doing ANYTHING
      // else to it because Opera is not very good at providing it
      // reliably in other circumstances.
      const stacktrace = ex.stacktrace;
      const opera10Regex = / line (\d+).*script (?:in )?(\S+)(?:: in function (\S+))?$/i;
      const opera11Regex = / line (\d+), column (\d+)\s*(?:in (?:<anonymous function: ([^>]+)>|([^\)]+))\((.*)\))? in (.*):\s*$/i;
      const lines = stacktrace.split('\n');
      const stack = [];
      let parts;
      for (let line = 0; line < lines.length; line += 2) {
          // tslint:disable:no-conditional-assignment
          let element = null;
          if ((parts = opera10Regex.exec(lines[line]))) {
              element = {
                  url: parts[2],
                  func: parts[3],
                  args: [],
                  line: +parts[1],
                  column: null,
              };
          }
          else if ((parts = opera11Regex.exec(lines[line]))) {
              element = {
                  url: parts[6],
                  func: parts[3] || parts[4],
                  args: parts[5] ? parts[5].split(',') : [],
                  line: +parts[1],
                  column: +parts[2],
              };
          }
          if (element) {
              if (!element.func && element.line) {
                  element.func = UNKNOWN_FUNCTION;
              }
              stack.push(element);
          }
      }
      if (!stack.length) {
          return null;
      }
      return {
          message: extractMessage(ex),
          name: ex.name,
          stack,
      };
  }
  /** Remove N number of frames from the stack */
  function popFrames(stacktrace, popSize) {
      try {
          return Object.assign({}, stacktrace, { stack: stacktrace.stack.slice(popSize) });
      }
      catch (e) {
          return stacktrace;
      }
  }
  /**
   * There are cases where stacktrace.message is an Event object
   * https://github.com/getsentry/sentry-javascript/issues/1949
   * In this specific case we try to extract stacktrace.message.error.message
   */
  function extractMessage(ex) {
      const message = ex && ex.message;
      if (!message) {
          return 'No error message';
      }
      if (message.error && typeof message.error.message === 'string') {
          return message.error.message;
      }
      return message;
  }

  const STACKTRACE_LIMIT = 50;
  /**
   * This function creates an exception from an TraceKitStackTrace
   * @param stacktrace TraceKitStackTrace that will be converted to an exception
   * @hidden
   */
  function exceptionFromStacktrace(stacktrace) {
      const frames = prepareFramesForEvent(stacktrace.stack);
      const exception = {
          type: stacktrace.name,
          value: stacktrace.message,
      };
      if (frames && frames.length) {
          exception.stacktrace = { frames };
      }
      // tslint:disable-next-line:strict-type-predicates
      if (exception.type === undefined && exception.value === '') {
          exception.value = 'Unrecoverable error caught';
      }
      return exception;
  }
  /**
   * @hidden
   */
  function eventFromPlainObject(exception, syntheticException, rejection) {
      const event = {
          exception: {
              values: [
                  {
                      type: isEvent(exception) ? exception.constructor.name : rejection ? 'UnhandledRejection' : 'Error',
                      value: `Non-Error ${rejection ? 'promise rejection' : 'exception'} captured with keys: ${extractExceptionKeysForMessage(exception)}`,
                  },
              ],
          },
          extra: {
              __serialized__: normalizeToSize(exception),
          },
      };
      if (syntheticException) {
          const stacktrace = computeStackTrace(syntheticException);
          const frames = prepareFramesForEvent(stacktrace.stack);
          event.stacktrace = {
              frames,
          };
      }
      return event;
  }
  /**
   * @hidden
   */
  function eventFromStacktrace(stacktrace) {
      const exception = exceptionFromStacktrace(stacktrace);
      return {
          exception: {
              values: [exception],
          },
      };
  }
  /**
   * @hidden
   */
  function prepareFramesForEvent(stack) {
      if (!stack || !stack.length) {
          return [];
      }
      let localStack = stack;
      const firstFrameFunction = localStack[0].func || '';
      const lastFrameFunction = localStack[localStack.length - 1].func || '';
      // If stack starts with one of our API calls, remove it (starts, meaning it's the top of the stack - aka last call)
      if (firstFrameFunction.indexOf('captureMessage') !== -1 || firstFrameFunction.indexOf('captureException') !== -1) {
          localStack = localStack.slice(1);
      }
      // If stack ends with one of our internal API calls, remove it (ends, meaning it's the bottom of the stack - aka top-most call)
      if (lastFrameFunction.indexOf('sentryWrapped') !== -1) {
          localStack = localStack.slice(0, -1);
      }
      // The frame where the crash happened, should be the last entry in the array
      return localStack
          .map((frame) => ({
          colno: frame.column === null ? undefined : frame.column,
          filename: frame.url || localStack[0].url,
          function: frame.func || '?',
          in_app: true,
          lineno: frame.line === null ? undefined : frame.line,
      }))
          .slice(0, STACKTRACE_LIMIT)
          .reverse();
  }

  /** JSDoc */
  function eventFromUnknownInput(exception, syntheticException, options = {}) {
      let event;
      if (isErrorEvent(exception) && exception.error) {
          // If it is an ErrorEvent with `error` property, extract it to get actual Error
          const errorEvent = exception;
          exception = errorEvent.error; // tslint:disable-line:no-parameter-reassignment
          event = eventFromStacktrace(computeStackTrace(exception));
          return event;
      }
      if (isDOMError(exception) || isDOMException(exception)) {
          // If it is a DOMError or DOMException (which are legacy APIs, but still supported in some browsers)
          // then we just extract the name and message, as they don't provide anything else
          // https://developer.mozilla.org/en-US/docs/Web/API/DOMError
          // https://developer.mozilla.org/en-US/docs/Web/API/DOMException
          const domException = exception;
          const name = domException.name || (isDOMError(domException) ? 'DOMError' : 'DOMException');
          const message = domException.message ? `${name}: ${domException.message}` : name;
          event = eventFromString(message, syntheticException, options);
          addExceptionTypeValue(event, message);
          return event;
      }
      if (isError(exception)) {
          // we have a real Error object, do nothing
          event = eventFromStacktrace(computeStackTrace(exception));
          return event;
      }
      if (isPlainObject(exception) || isEvent(exception)) {
          // If it is plain Object or Event, serialize it manually and extract options
          // This will allow us to group events based on top-level keys
          // which is much better than creating new group when any key/value change
          const objectException = exception;
          event = eventFromPlainObject(objectException, syntheticException, options.rejection);
          addExceptionMechanism(event, {
              synthetic: true,
          });
          return event;
      }
      // If none of previous checks were valid, then it means that it's not:
      // - an instance of DOMError
      // - an instance of DOMException
      // - an instance of Event
      // - an instance of Error
      // - a valid ErrorEvent (one with an error property)
      // - a plain Object
      //
      // So bail out and capture it as a simple message:
      event = eventFromString(exception, syntheticException, options);
      addExceptionTypeValue(event, `${exception}`, undefined);
      addExceptionMechanism(event, {
          synthetic: true,
      });
      return event;
  }
  // this._options.attachStacktrace
  /** JSDoc */
  function eventFromString(input, syntheticException, options = {}) {
      const event = {
          message: input,
      };
      if (options.attachStacktrace && syntheticException) {
          const stacktrace = computeStackTrace(syntheticException);
          const frames = prepareFramesForEvent(stacktrace.stack);
          event.stacktrace = {
              frames,
          };
      }
      return event;
  }

  /** Base Transport class implementation */
  class BaseTransport {
      constructor(options) {
          this.options = options;
          /** A simple buffer holding all requests. */
          this._buffer = new PromiseBuffer(30);
          this.url = new API(this.options.dsn).getStoreEndpointWithUrlEncodedAuth();
      }
      /**
       * @inheritDoc
       */
      sendEvent(_) {
          throw new SentryError('Transport Class has to implement `sendEvent` method');
      }
      /**
       * @inheritDoc
       */
      close(timeout) {
          return this._buffer.drain(timeout);
      }
  }

  const global$3 = getGlobalObject();
  /** `fetch` based transport */
  class FetchTransport extends BaseTransport {
      constructor() {
          super(...arguments);
          /** Locks transport after receiving 429 response */
          this._disabledUntil = new Date(Date.now());
      }
      /**
       * @inheritDoc
       */
      sendEvent(event) {
          if (new Date(Date.now()) < this._disabledUntil) {
              return Promise.reject({
                  event,
                  reason: `Transport locked till ${this._disabledUntil} due to too many requests.`,
                  status: 429,
              });
          }
          const defaultOptions = {
              body: JSON.stringify(event),
              method: 'POST',
              // Despite all stars in the sky saying that Edge supports old draft syntax, aka 'never', 'always', 'origin' and 'default
              // https://caniuse.com/#feat=referrer-policy
              // It doesn't. And it throw exception instead of ignoring this parameter...
              // REF: https://github.com/getsentry/raven-js/issues/1233
              referrerPolicy: (supportsReferrerPolicy() ? 'origin' : ''),
          };
          if (this.options.headers !== undefined) {
              defaultOptions.headers = this.options.headers;
          }
          return this._buffer.add(new SyncPromise((resolve, reject) => {
              global$3
                  .fetch(this.url, defaultOptions)
                  .then(response => {
                  const status = exports.Status.fromHttpCode(response.status);
                  if (status === exports.Status.Success) {
                      resolve({ status });
                      return;
                  }
                  if (status === exports.Status.RateLimit) {
                      const now = Date.now();
                      this._disabledUntil = new Date(now + parseRetryAfterHeader(now, response.headers.get('Retry-After')));
                      logger.warn(`Too many requests, backing off till: ${this._disabledUntil}`);
                  }
                  reject(response);
              })
                  .catch(reject);
          }));
      }
  }

  /** `XHR` based transport */
  class XHRTransport extends BaseTransport {
      constructor() {
          super(...arguments);
          /** Locks transport after receiving 429 response */
          this._disabledUntil = new Date(Date.now());
      }
      /**
       * @inheritDoc
       */
      sendEvent(event) {
          if (new Date(Date.now()) < this._disabledUntil) {
              return Promise.reject({
                  event,
                  reason: `Transport locked till ${this._disabledUntil} due to too many requests.`,
                  status: 429,
              });
          }
          return this._buffer.add(new SyncPromise((resolve, reject) => {
              const request = new XMLHttpRequest();
              request.onreadystatechange = () => {
                  if (request.readyState !== 4) {
                      return;
                  }
                  const status = exports.Status.fromHttpCode(request.status);
                  if (status === exports.Status.Success) {
                      resolve({ status });
                      return;
                  }
                  if (status === exports.Status.RateLimit) {
                      const now = Date.now();
                      this._disabledUntil = new Date(now + parseRetryAfterHeader(now, request.getResponseHeader('Retry-After')));
                      logger.warn(`Too many requests, backing off till: ${this._disabledUntil}`);
                  }
                  reject(request);
              };
              request.open('POST', this.url);
              for (const header in this.options.headers) {
                  if (this.options.headers.hasOwnProperty(header)) {
                      request.setRequestHeader(header, this.options.headers[header]);
                  }
              }
              request.send(JSON.stringify(event));
          }));
      }
  }



  var index = /*#__PURE__*/Object.freeze({
    BaseTransport: BaseTransport,
    FetchTransport: FetchTransport,
    XHRTransport: XHRTransport
  });

  /**
   * The Sentry Browser SDK Backend.
   * @hidden
   */
  class BrowserBackend extends BaseBackend {
      /**
       * @inheritDoc
       */
      _setupTransport() {
          if (!this._options.dsn) {
              // We return the noop transport here in case there is no Dsn.
              return super._setupTransport();
          }
          const transportOptions = Object.assign({}, this._options.transportOptions, { dsn: this._options.dsn });
          if (this._options.transport) {
              return new this._options.transport(transportOptions);
          }
          if (supportsFetch()) {
              return new FetchTransport(transportOptions);
          }
          return new XHRTransport(transportOptions);
      }
      /**
       * @inheritDoc
       */
      eventFromException(exception, hint) {
          const syntheticException = (hint && hint.syntheticException) || undefined;
          const event = eventFromUnknownInput(exception, syntheticException, {
              attachStacktrace: this._options.attachStacktrace,
          });
          addExceptionMechanism(event, {
              handled: true,
              type: 'generic',
          });
          event.level = exports.Severity.Error;
          if (hint && hint.event_id) {
              event.event_id = hint.event_id;
          }
          return SyncPromise.resolve(event);
      }
      /**
       * @inheritDoc
       */
      eventFromMessage(message, level = exports.Severity.Info, hint) {
          const syntheticException = (hint && hint.syntheticException) || undefined;
          const event = eventFromString(message, syntheticException, {
              attachStacktrace: this._options.attachStacktrace,
          });
          event.level = level;
          if (hint && hint.event_id) {
              event.event_id = hint.event_id;
          }
          return SyncPromise.resolve(event);
      }
  }

  const SDK_NAME = 'sentry.javascript.browser';
  const SDK_VERSION = '5.13.0';

  /**
   * The Sentry Browser SDK Client.
   *
   * @see BrowserOptions for documentation on configuration options.
   * @see SentryClient for usage documentation.
   */
  class BrowserClient extends BaseClient {
      /**
       * Creates a new Browser SDK instance.
       *
       * @param options Configuration options for this SDK.
       */
      constructor(options = {}) {
          super(BrowserBackend, options);
      }
      /**
       * @inheritDoc
       */
      _prepareEvent(event, scope, hint) {
          event.platform = event.platform || 'javascript';
          event.sdk = Object.assign({}, event.sdk, { name: SDK_NAME, packages: [
                  ...((event.sdk && event.sdk.packages) || []),
                  {
                      name: 'npm:@sentry/browser',
                      version: SDK_VERSION,
                  },
              ], version: SDK_VERSION });
          return super._prepareEvent(event, scope, hint);
      }
      /**
       * Show a report dialog to the user to send feedback to a specific event.
       *
       * @param options Set individual options for the dialog
       */
      showReportDialog(options = {}) {
          // doesn't work without a document (React Native)
          const document = getGlobalObject().document;
          if (!document) {
              return;
          }
          if (!this._isEnabled()) {
              logger.error('Trying to call showReportDialog with Sentry Client is disabled');
              return;
          }
          const dsn = options.dsn || this.getDsn();
          if (!options.eventId) {
              logger.error('Missing `eventId` option in showReportDialog call');
              return;
          }
          if (!dsn) {
              logger.error('Missing `Dsn` option in showReportDialog call');
              return;
          }
          const script = document.createElement('script');
          script.async = true;
          script.src = new API(dsn).getReportDialogEndpoint(options);
          if (options.onLoad) {
              script.onload = options.onLoad;
          }
          (document.head || document.body).appendChild(script);
      }
  }

  let ignoreOnError = 0;
  /**
   * @hidden
   */
  function shouldIgnoreOnError() {
      return ignoreOnError > 0;
  }
  /**
   * @hidden
   */
  function ignoreNextOnError() {
      // onerror should trigger before setTimeout
      ignoreOnError += 1;
      setTimeout(() => {
          ignoreOnError -= 1;
      });
  }
  /**
   * Instruments the given function and sends an event to Sentry every time the
   * function throws an exception.
   *
   * @param fn A function to wrap.
   * @returns The wrapped function.
   * @hidden
   */
  function wrap(fn, options = {}, before) {
      // tslint:disable-next-line:strict-type-predicates
      if (typeof fn !== 'function') {
          return fn;
      }
      try {
          // We don't wanna wrap it twice
          if (fn.__sentry__) {
              return fn;
          }
          // If this has already been wrapped in the past, return that wrapped function
          if (fn.__sentry_wrapped__) {
              return fn.__sentry_wrapped__;
          }
      }
      catch (e) {
          // Just accessing custom props in some Selenium environments
          // can cause a "Permission denied" exception (see raven-js#495).
          // Bail on wrapping and return the function as-is (defers to window.onerror).
          return fn;
      }
      const sentryWrapped = function () {
          const args = Array.prototype.slice.call(arguments);
          // tslint:disable:no-unsafe-any
          try {
              // tslint:disable-next-line:strict-type-predicates
              if (before && typeof before === 'function') {
                  before.apply(this, arguments);
              }
              const wrappedArguments = args.map((arg) => wrap(arg, options));
              if (fn.handleEvent) {
                  // Attempt to invoke user-land function
                  // NOTE: If you are a Sentry user, and you are seeing this stack frame, it
                  //       means the sentry.javascript SDK caught an error invoking your application code. This
                  //       is expected behavior and NOT indicative of a bug with sentry.javascript.
                  return fn.handleEvent.apply(this, wrappedArguments);
              }
              // Attempt to invoke user-land function
              // NOTE: If you are a Sentry user, and you are seeing this stack frame, it
              //       means the sentry.javascript SDK caught an error invoking your application code. This
              //       is expected behavior and NOT indicative of a bug with sentry.javascript.
              return fn.apply(this, wrappedArguments);
              // tslint:enable:no-unsafe-any
          }
          catch (ex) {
              ignoreNextOnError();
              withScope((scope) => {
                  scope.addEventProcessor((event) => {
                      const processedEvent = Object.assign({}, event);
                      if (options.mechanism) {
                          addExceptionTypeValue(processedEvent, undefined, undefined);
                          addExceptionMechanism(processedEvent, options.mechanism);
                      }
                      processedEvent.extra = Object.assign({}, processedEvent.extra, { arguments: args });
                      return processedEvent;
                  });
                  captureException(ex);
              });
              throw ex;
          }
      };
      // Accessing some objects may throw
      // ref: https://github.com/getsentry/sentry-javascript/issues/1168
      try {
          for (const property in fn) {
              if (Object.prototype.hasOwnProperty.call(fn, property)) {
                  sentryWrapped[property] = fn[property];
              }
          }
      }
      catch (_oO) { } // tslint:disable-line:no-empty
      fn.prototype = fn.prototype || {};
      sentryWrapped.prototype = fn.prototype;
      Object.defineProperty(fn, '__sentry_wrapped__', {
          enumerable: false,
          value: sentryWrapped,
      });
      // Signal that this function has been wrapped/filled already
      // for both debugging and to prevent it to being wrapped/filled twice
      Object.defineProperties(sentryWrapped, {
          __sentry__: {
              enumerable: false,
              value: true,
          },
          __sentry_original__: {
              enumerable: false,
              value: fn,
          },
      });
      // Restore original function name (not all browsers allow that)
      try {
          const descriptor = Object.getOwnPropertyDescriptor(sentryWrapped, 'name');
          if (descriptor.configurable) {
              Object.defineProperty(sentryWrapped, 'name', {
                  get() {
                      return fn.name;
                  },
              });
          }
      }
      catch (_oO) {
          /*no-empty*/
      }
      return sentryWrapped;
  }

  /** Global handlers */
  class GlobalHandlers {
      /** JSDoc */
      constructor(options) {
          /**
           * @inheritDoc
           */
          this.name = GlobalHandlers.id;
          /** JSDoc */
          this._global = getGlobalObject();
          /** JSDoc */
          this._oldOnErrorHandler = null;
          /** JSDoc */
          this._oldOnUnhandledRejectionHandler = null;
          /** JSDoc */
          this._onErrorHandlerInstalled = false;
          /** JSDoc */
          this._onUnhandledRejectionHandlerInstalled = false;
          this._options = Object.assign({ onerror: true, onunhandledrejection: true }, options);
      }
      /**
       * @inheritDoc
       */
      setupOnce() {
          Error.stackTraceLimit = 50;
          if (this._options.onerror) {
              logger.log('Global Handler attached: onerror');
              this._installGlobalOnErrorHandler();
          }
          if (this._options.onunhandledrejection) {
              logger.log('Global Handler attached: onunhandledrejection');
              this._installGlobalOnUnhandledRejectionHandler();
          }
      }
      /** JSDoc */
      _installGlobalOnErrorHandler() {
          if (this._onErrorHandlerInstalled) {
              return;
          }
          const self = this; // tslint:disable-line:no-this-assignment
          this._oldOnErrorHandler = this._global.onerror;
          this._global.onerror = function (msg, url, line, column, error) {
              const currentHub = getCurrentHub();
              const hasIntegration = currentHub.getIntegration(GlobalHandlers);
              const isFailedOwnDelivery = error && error.__sentry_own_request__ === true;
              if (!hasIntegration || shouldIgnoreOnError() || isFailedOwnDelivery) {
                  if (self._oldOnErrorHandler) {
                      return self._oldOnErrorHandler.apply(this, arguments);
                  }
                  return false;
              }
              const client = currentHub.getClient();
              const event = isPrimitive(error)
                  ? self._eventFromIncompleteOnError(msg, url, line, column)
                  : self._enhanceEventWithInitialFrame(eventFromUnknownInput(error, undefined, {
                      attachStacktrace: client && client.getOptions().attachStacktrace,
                      rejection: false,
                  }), url, line, column);
              addExceptionMechanism(event, {
                  handled: false,
                  type: 'onerror',
              });
              currentHub.captureEvent(event, {
                  originalException: error,
              });
              if (self._oldOnErrorHandler) {
                  return self._oldOnErrorHandler.apply(this, arguments);
              }
              return false;
          };
          this._onErrorHandlerInstalled = true;
      }
      /** JSDoc */
      _installGlobalOnUnhandledRejectionHandler() {
          if (this._onUnhandledRejectionHandlerInstalled) {
              return;
          }
          const self = this; // tslint:disable-line:no-this-assignment
          this._oldOnUnhandledRejectionHandler = this._global.onunhandledrejection;
          this._global.onunhandledrejection = function (e) {
              let error = e;
              // dig the object of the rejection out of known event types
              try {
                  // PromiseRejectionEvents store the object of the rejection under 'reason'
                  // see https://developer.mozilla.org/en-US/docs/Web/API/PromiseRejectionEvent
                  if ('reason' in e) {
                      error = e.reason;
                  }
                  // something, somewhere, (likely a browser extension) effectively casts PromiseRejectionEvents
                  // to CustomEvents, moving the `promise` and `reason` attributes of the PRE into
                  // the CustomEvent's `detail` attribute, since they're not part of CustomEvent's spec
                  // see https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent and
                  // https://github.com/getsentry/sentry-javascript/issues/2380
                  else if ('detail' in e && 'reason' in e.detail) {
                      error = e.detail.reason;
                  }
              }
              catch (_oO) {
                  // no-empty
              }
              const currentHub = getCurrentHub();
              const hasIntegration = currentHub.getIntegration(GlobalHandlers);
              const isFailedOwnDelivery = error && error.__sentry_own_request__ === true;
              if (!hasIntegration || shouldIgnoreOnError() || isFailedOwnDelivery) {
                  if (self._oldOnUnhandledRejectionHandler) {
                      return self._oldOnUnhandledRejectionHandler.apply(this, arguments);
                  }
                  return true;
              }
              const client = currentHub.getClient();
              const event = isPrimitive(error)
                  ? self._eventFromIncompleteRejection(error)
                  : eventFromUnknownInput(error, undefined, {
                      attachStacktrace: client && client.getOptions().attachStacktrace,
                      rejection: true,
                  });
              event.level = exports.Severity.Error;
              addExceptionMechanism(event, {
                  handled: false,
                  type: 'onunhandledrejection',
              });
              currentHub.captureEvent(event, {
                  originalException: error,
              });
              if (self._oldOnUnhandledRejectionHandler) {
                  return self._oldOnUnhandledRejectionHandler.apply(this, arguments);
              }
              return true;
          };
          this._onUnhandledRejectionHandlerInstalled = true;
      }
      /**
       * This function creates a stack from an old, error-less onerror handler.
       */
      _eventFromIncompleteOnError(msg, url, line, column) {
          const ERROR_TYPES_RE = /^(?:[Uu]ncaught (?:exception: )?)?(?:((?:Eval|Internal|Range|Reference|Syntax|Type|URI|)Error): )?(.*)$/i;
          // If 'message' is ErrorEvent, get real message from inside
          let message = isErrorEvent(msg) ? msg.message : msg;
          let name;
          if (isString(message)) {
              const groups = message.match(ERROR_TYPES_RE);
              if (groups) {
                  name = groups[1];
                  message = groups[2];
              }
          }
          const event = {
              exception: {
                  values: [
                      {
                          type: name || 'Error',
                          value: message,
                      },
                  ],
              },
          };
          return this._enhanceEventWithInitialFrame(event, url, line, column);
      }
      /**
       * This function creates an Event from an TraceKitStackTrace that has part of it missing.
       */
      _eventFromIncompleteRejection(error) {
          return {
              exception: {
                  values: [
                      {
                          type: 'UnhandledRejection',
                          value: `Non-Error promise rejection captured with value: ${error}`,
                      },
                  ],
              },
          };
      }
      /** JSDoc */
      _enhanceEventWithInitialFrame(event, url, line, column) {
          event.exception = event.exception || {};
          event.exception.values = event.exception.values || [];
          event.exception.values[0] = event.exception.values[0] || {};
          event.exception.values[0].stacktrace = event.exception.values[0].stacktrace || {};
          event.exception.values[0].stacktrace.frames = event.exception.values[0].stacktrace.frames || [];
          const colno = isNaN(parseInt(column, 10)) ? undefined : column;
          const lineno = isNaN(parseInt(line, 10)) ? undefined : line;
          const filename = isString(url) && url.length > 0 ? url : getLocationHref();
          if (event.exception.values[0].stacktrace.frames.length === 0) {
              event.exception.values[0].stacktrace.frames.push({
                  colno,
                  filename,
                  function: '?',
                  in_app: true,
                  lineno,
              });
          }
          return event;
      }
  }
  /**
   * @inheritDoc
   */
  GlobalHandlers.id = 'GlobalHandlers';

  /** Wrap timer functions and event targets to catch errors and provide better meta data */
  class TryCatch {
      constructor() {
          /** JSDoc */
          this._ignoreOnError = 0;
          /**
           * @inheritDoc
           */
          this.name = TryCatch.id;
      }
      /** JSDoc */
      _wrapTimeFunction(original) {
          return function (...args) {
              const originalCallback = args[0];
              args[0] = wrap(originalCallback, {
                  mechanism: {
                      data: { function: getFunctionName(original) },
                      handled: true,
                      type: 'instrument',
                  },
              });
              return original.apply(this, args);
          };
      }
      /** JSDoc */
      _wrapRAF(original) {
          return function (callback) {
              return original(wrap(callback, {
                  mechanism: {
                      data: {
                          function: 'requestAnimationFrame',
                          handler: getFunctionName(original),
                      },
                      handled: true,
                      type: 'instrument',
                  },
              }));
          };
      }
      /** JSDoc */
      _wrapEventTarget(target) {
          const global = getGlobalObject();
          const proto = global[target] && global[target].prototype;
          if (!proto || !proto.hasOwnProperty || !proto.hasOwnProperty('addEventListener')) {
              return;
          }
          fill(proto, 'addEventListener', function (original) {
              return function (eventName, fn, options) {
                  try {
                      // tslint:disable-next-line:no-unbound-method strict-type-predicates
                      if (typeof fn.handleEvent === 'function') {
                          fn.handleEvent = wrap(fn.handleEvent.bind(fn), {
                              mechanism: {
                                  data: {
                                      function: 'handleEvent',
                                      handler: getFunctionName(fn),
                                      target,
                                  },
                                  handled: true,
                                  type: 'instrument',
                              },
                          });
                      }
                  }
                  catch (err) {
                      // can sometimes get 'Permission denied to access property "handle Event'
                  }
                  return original.call(this, eventName, wrap(fn, {
                      mechanism: {
                          data: {
                              function: 'addEventListener',
                              handler: getFunctionName(fn),
                              target,
                          },
                          handled: true,
                          type: 'instrument',
                      },
                  }), options);
              };
          });
          fill(proto, 'removeEventListener', function (original) {
              return function (eventName, fn, options) {
                  let callback = fn;
                  try {
                      callback = callback && (callback.__sentry_wrapped__ || callback);
                  }
                  catch (e) {
                      // ignore, accessing __sentry_wrapped__ will throw in some Selenium environments
                  }
                  return original.call(this, eventName, callback, options);
              };
          });
      }
      /** JSDoc */
      _wrapXHR(originalSend) {
          return function (...args) {
              const xhr = this; // tslint:disable-line:no-this-assignment
              const xmlHttpRequestProps = ['onload', 'onerror', 'onprogress', 'onreadystatechange'];
              xmlHttpRequestProps.forEach(prop => {
                  if (prop in xhr && typeof xhr[prop] === 'function') {
                      fill(xhr, prop, function (original) {
                          const wrapOptions = {
                              mechanism: {
                                  data: {
                                      function: prop,
                                      handler: getFunctionName(original),
                                  },
                                  handled: true,
                                  type: 'instrument',
                              },
                          };
                          // If Instrument integration has been called before TryCatch, get the name of original function
                          if (original.__sentry_original__) {
                              wrapOptions.mechanism.data.handler = getFunctionName(original.__sentry_original__);
                          }
                          // Otherwise wrap directly
                          return wrap(original, wrapOptions);
                      });
                  }
              });
              return originalSend.apply(this, args);
          };
      }
      /**
       * Wrap timer functions and event targets to catch errors
       * and provide better metadata.
       */
      setupOnce() {
          this._ignoreOnError = this._ignoreOnError;
          const global = getGlobalObject();
          fill(global, 'setTimeout', this._wrapTimeFunction.bind(this));
          fill(global, 'setInterval', this._wrapTimeFunction.bind(this));
          fill(global, 'requestAnimationFrame', this._wrapRAF.bind(this));
          if ('XMLHttpRequest' in global) {
              fill(XMLHttpRequest.prototype, 'send', this._wrapXHR.bind(this));
          }
          [
              'EventTarget',
              'Window',
              'Node',
              'ApplicationCache',
              'AudioTrackList',
              'ChannelMergerNode',
              'CryptoOperation',
              'EventSource',
              'FileReader',
              'HTMLUnknownElement',
              'IDBDatabase',
              'IDBRequest',
              'IDBTransaction',
              'KeyOperation',
              'MediaController',
              'MessagePort',
              'ModalWindow',
              'Notification',
              'SVGElementInstance',
              'Screen',
              'TextTrack',
              'TextTrackCue',
              'TextTrackList',
              'WebSocket',
              'WebSocketWorker',
              'Worker',
              'XMLHttpRequest',
              'XMLHttpRequestEventTarget',
              'XMLHttpRequestUpload',
          ].forEach(this._wrapEventTarget.bind(this));
      }
  }
  /**
   * @inheritDoc
   */
  TryCatch.id = 'TryCatch';

  /**
   * Default Breadcrumbs instrumentations
   * TODO: Deprecated - with v6, this will be renamed to `Instrument`
   */
  class Breadcrumbs {
      /**
       * @inheritDoc
       */
      constructor(options) {
          /**
           * @inheritDoc
           */
          this.name = Breadcrumbs.id;
          this._options = Object.assign({ console: true, dom: true, fetch: true, history: true, sentry: true, xhr: true }, options);
      }
      /**
       * Creates breadcrumbs from console API calls
       */
      _consoleBreadcrumb(handlerData) {
          const breadcrumb = {
              category: 'console',
              data: {
                  arguments: handlerData.args,
                  logger: 'console',
              },
              level: exports.Severity.fromString(handlerData.level),
              message: safeJoin(handlerData.args, ' '),
          };
          if (handlerData.level === 'assert') {
              if (handlerData.args[0] === false) {
                  breadcrumb.message = `Assertion failed: ${safeJoin(handlerData.args.slice(1), ' ') || 'console.assert'}`;
                  breadcrumb.data.arguments = handlerData.args.slice(1);
              }
              else {
                  // Don't capture a breadcrumb for passed assertions
                  return;
              }
          }
          getCurrentHub().addBreadcrumb(breadcrumb, {
              input: handlerData.args,
              level: handlerData.level,
          });
      }
      /**
       * Creates breadcrumbs from DOM API calls
       */
      _domBreadcrumb(handlerData) {
          let target;
          // Accessing event.target can throw (see getsentry/raven-js#838, #768)
          try {
              target = handlerData.event.target
                  ? htmlTreeAsString(handlerData.event.target)
                  : htmlTreeAsString(handlerData.event);
          }
          catch (e) {
              target = '<unknown>';
          }
          if (target.length === 0) {
              return;
          }
          getCurrentHub().addBreadcrumb({
              category: `ui.${handlerData.name}`,
              message: target,
          }, {
              event,
              name: handlerData.name,
          });
      }
      /**
       * Creates breadcrumbs from XHR API calls
       */
      _xhrBreadcrumb(handlerData) {
          if (handlerData.endTimestamp) {
              // We only capture complete, non-sentry requests
              if (handlerData.xhr.__sentry_own_request__) {
                  return;
              }
              getCurrentHub().addBreadcrumb({
                  category: 'xhr',
                  data: handlerData.xhr.__sentry_xhr__,
                  type: 'http',
              }, {
                  xhr: handlerData.xhr,
              });
              return;
          }
          // We only capture issued sentry requests
          if (handlerData.xhr.__sentry_own_request__) {
              addSentryBreadcrumb(handlerData.args[0]);
          }
      }
      /**
       * Creates breadcrumbs from fetch API calls
       */
      _fetchBreadcrumb(handlerData) {
          // We only capture complete fetch requests
          if (!handlerData.endTimestamp) {
              return;
          }
          const client = getCurrentHub().getClient();
          const dsn = client && client.getDsn();
          if (dsn) {
              const filterUrl = new API(dsn).getStoreEndpoint();
              // if Sentry key appears in URL, don't capture it as a request
              // but rather as our own 'sentry' type breadcrumb
              if (filterUrl &&
                  handlerData.fetchData.url.indexOf(filterUrl) !== -1 &&
                  handlerData.fetchData.method === 'POST' &&
                  handlerData.args[1] &&
                  handlerData.args[1].body) {
                  addSentryBreadcrumb(handlerData.args[1].body);
                  return;
              }
          }
          if (handlerData.error) {
              getCurrentHub().addBreadcrumb({
                  category: 'fetch',
                  data: Object.assign({}, handlerData.fetchData, { status_code: handlerData.response.status }),
                  level: exports.Severity.Error,
                  type: 'http',
              }, {
                  data: handlerData.error,
                  input: handlerData.args,
              });
          }
          else {
              getCurrentHub().addBreadcrumb({
                  category: 'fetch',
                  data: Object.assign({}, handlerData.fetchData, { status_code: handlerData.response.status }),
                  type: 'http',
              }, {
                  input: handlerData.args,
                  response: handlerData.response,
              });
          }
      }
      /**
       * Creates breadcrumbs from history API calls
       */
      _historyBreadcrumb(handlerData) {
          const global = getGlobalObject();
          let from = handlerData.from;
          let to = handlerData.to;
          const parsedLoc = parseUrl(global.location.href);
          let parsedFrom = parseUrl(from);
          const parsedTo = parseUrl(to);
          // Initial pushState doesn't provide `from` information
          if (!parsedFrom.path) {
              parsedFrom = parsedLoc;
          }
          // Use only the path component of the URL if the URL matches the current
          // document (almost all the time when using pushState)
          if (parsedLoc.protocol === parsedTo.protocol && parsedLoc.host === parsedTo.host) {
              // tslint:disable-next-line:no-parameter-reassignment
              to = parsedTo.relative;
          }
          if (parsedLoc.protocol === parsedFrom.protocol && parsedLoc.host === parsedFrom.host) {
              // tslint:disable-next-line:no-parameter-reassignment
              from = parsedFrom.relative;
          }
          getCurrentHub().addBreadcrumb({
              category: 'navigation',
              data: {
                  from,
                  to,
              },
          });
      }
      /**
       * Instrument browser built-ins w/ breadcrumb capturing
       *  - Console API
       *  - DOM API (click/typing)
       *  - XMLHttpRequest API
       *  - Fetch API
       *  - History API
       */
      setupOnce() {
          if (this._options.console) {
              addInstrumentationHandler({
                  callback: (...args) => {
                      this._consoleBreadcrumb(...args);
                  },
                  type: 'console',
              });
          }
          if (this._options.dom) {
              addInstrumentationHandler({
                  callback: (...args) => {
                      this._domBreadcrumb(...args);
                  },
                  type: 'dom',
              });
          }
          if (this._options.xhr) {
              addInstrumentationHandler({
                  callback: (...args) => {
                      this._xhrBreadcrumb(...args);
                  },
                  type: 'xhr',
              });
          }
          if (this._options.fetch) {
              addInstrumentationHandler({
                  callback: (...args) => {
                      this._fetchBreadcrumb(...args);
                  },
                  type: 'fetch',
              });
          }
          if (this._options.history) {
              addInstrumentationHandler({
                  callback: (...args) => {
                      this._historyBreadcrumb(...args);
                  },
                  type: 'history',
              });
          }
      }
  }
  /**
   * @inheritDoc
   */
  Breadcrumbs.id = 'Breadcrumbs';
  /**
   * Create a breadcrumb of `sentry` from the events themselves
   */
  function addSentryBreadcrumb(serializedData) {
      // There's always something that can go wrong with deserialization...
      try {
          const event = JSON.parse(serializedData);
          getCurrentHub().addBreadcrumb({
              category: `sentry.${event.type === 'transaction' ? 'transaction' : 'event'}`,
              event_id: event.event_id,
              level: event.level || exports.Severity.fromString('error'),
              message: getEventDescription(event),
          }, {
              event,
          });
      }
      catch (_oO) {
          logger.error('Error while adding sentry type breadcrumb');
      }
  }

  const DEFAULT_KEY = 'cause';
  const DEFAULT_LIMIT = 5;
  /** Adds SDK info to an event. */
  class LinkedErrors {
      /**
       * @inheritDoc
       */
      constructor(options = {}) {
          /**
           * @inheritDoc
           */
          this.name = LinkedErrors.id;
          this._key = options.key || DEFAULT_KEY;
          this._limit = options.limit || DEFAULT_LIMIT;
      }
      /**
       * @inheritDoc
       */
      setupOnce() {
          addGlobalEventProcessor((event, hint) => {
              const self = getCurrentHub().getIntegration(LinkedErrors);
              if (self) {
                  return self._handler(event, hint);
              }
              return event;
          });
      }
      /**
       * @inheritDoc
       */
      _handler(event, hint) {
          if (!event.exception || !event.exception.values || !hint || !isInstanceOf(hint.originalException, Error)) {
              return event;
          }
          const linkedErrors = this._walkErrorTree(hint.originalException, this._key);
          event.exception.values = [...linkedErrors, ...event.exception.values];
          return event;
      }
      /**
       * @inheritDoc
       */
      _walkErrorTree(error, key, stack = []) {
          if (!isInstanceOf(error[key], Error) || stack.length + 1 >= this._limit) {
              return stack;
          }
          const stacktrace = computeStackTrace(error[key]);
          const exception = exceptionFromStacktrace(stacktrace);
          return this._walkErrorTree(error[key], key, [exception, ...stack]);
      }
  }
  /**
   * @inheritDoc
   */
  LinkedErrors.id = 'LinkedErrors';

  const global$4 = getGlobalObject();
  /** UserAgent */
  class UserAgent {
      constructor() {
          /**
           * @inheritDoc
           */
          this.name = UserAgent.id;
      }
      /**
       * @inheritDoc
       */
      setupOnce() {
          addGlobalEventProcessor((event) => {
              if (getCurrentHub().getIntegration(UserAgent)) {
                  if (!global$4.navigator || !global$4.location) {
                      return event;
                  }
                  // Request Interface: https://docs.sentry.io/development/sdk-dev/event-payloads/request/
                  const request = event.request || {};
                  request.url = request.url || global$4.location.href;
                  request.headers = request.headers || {};
                  request.headers['User-Agent'] = global$4.navigator.userAgent;
                  return Object.assign({}, event, { request });
              }
              return event;
          });
      }
  }
  /**
   * @inheritDoc
   */
  UserAgent.id = 'UserAgent';



  var BrowserIntegrations = /*#__PURE__*/Object.freeze({
    GlobalHandlers: GlobalHandlers,
    TryCatch: TryCatch,
    Breadcrumbs: Breadcrumbs,
    LinkedErrors: LinkedErrors,
    UserAgent: UserAgent
  });

  const defaultIntegrations = [
      new InboundFilters(),
      new FunctionToString(),
      new TryCatch(),
      new Breadcrumbs(),
      new GlobalHandlers(),
      new LinkedErrors(),
      new UserAgent(),
  ];
  /**
   * The Sentry Browser SDK Client.
   *
   * To use this SDK, call the {@link init} function as early as possible when
   * loading the web page. To set context information or send manual events, use
   * the provided methods.
   *
   * @example
   *
   * ```
   *
   * import { init } from '@sentry/browser';
   *
   * init({
   *   dsn: '__DSN__',
   *   // ...
   * });
   * ```
   *
   * @example
   * ```
   *
   * import { configureScope } from '@sentry/browser';
   * configureScope((scope: Scope) => {
   *   scope.setExtra({ battery: 0.7 });
   *   scope.setTag({ user_mode: 'admin' });
   *   scope.setUser({ id: '4711' });
   * });
   * ```
   *
   * @example
   * ```
   *
   * import { addBreadcrumb } from '@sentry/browser';
   * addBreadcrumb({
   *   message: 'My Breadcrumb',
   *   // ...
   * });
   * ```
   *
   * @example
   *
   * ```
   *
   * import * as Sentry from '@sentry/browser';
   * Sentry.captureMessage('Hello, world!');
   * Sentry.captureException(new Error('Good bye'));
   * Sentry.captureEvent({
   *   message: 'Manual',
   *   stacktrace: [
   *     // ...
   *   ],
   * });
   * ```
   *
   * @see {@link BrowserOptions} for documentation on configuration options.
   */
  function init(options = {}) {
      if (options.defaultIntegrations === undefined) {
          options.defaultIntegrations = defaultIntegrations;
      }
      if (options.release === undefined) {
          const window = getGlobalObject();
          // This supports the variable that sentry-webpack-plugin injects
          if (window.SENTRY_RELEASE && window.SENTRY_RELEASE.id) {
              options.release = window.SENTRY_RELEASE.id;
          }
      }
      initAndBind(BrowserClient, options);
  }
  /**
   * Present the user with a report dialog.
   *
   * @param options Everything is optional, we try to fetch all info need from the global scope.
   */
  function showReportDialog(options = {}) {
      if (!options.eventId) {
          options.eventId = getCurrentHub().lastEventId();
      }
      const client = getCurrentHub().getClient();
      if (client) {
          client.showReportDialog(options);
      }
  }
  /**
   * This is the getter for lastEventId.
   *
   * @returns The last event id of a captured event.
   */
  function lastEventId() {
      return getCurrentHub().lastEventId();
  }
  /**
   * This function is here to be API compatible with the loader.
   * @hidden
   */
  function forceLoad() {
      // Noop
  }
  /**
   * This function is here to be API compatible with the loader.
   * @hidden
   */
  function onLoad(callback) {
      callback();
  }
  /**
   * A promise that resolves when all current events have been sent.
   * If you provide a timeout and the queue takes longer to drain the promise returns false.
   *
   * @param timeout Maximum time in ms the client should wait.
   */
  function flush(timeout) {
      const client = getCurrentHub().getClient();
      if (client) {
          return client.flush(timeout);
      }
      return SyncPromise.reject(false);
  }
  /**
   * A promise that resolves when all current events have been sent.
   * If you provide a timeout and the queue takes longer to drain the promise returns false.
   *
   * @param timeout Maximum time in ms the client should wait.
   */
  function close(timeout) {
      const client = getCurrentHub().getClient();
      if (client) {
          return client.close(timeout);
      }
      return SyncPromise.reject(false);
  }
  /**
   * Wrap code within a try/catch block so the SDK is able to capture errors.
   *
   * @param fn A function to wrap.
   *
   * @returns The result of wrapped function call.
   */
  function wrap$1(fn) {
      return wrap(fn)(); // tslint:disable-line:no-unsafe-any
  }

  let windowIntegrations = {};
  // This block is needed to add compatibility with the integrations packages when used with a CDN
  // tslint:disable: no-unsafe-any
  const _window = getGlobalObject();
  if (_window.Sentry && _window.Sentry.Integrations) {
      windowIntegrations = _window.Sentry.Integrations;
  }
  // tslint:enable: no-unsafe-any
  const INTEGRATIONS = Object.assign({}, windowIntegrations, CoreIntegrations, BrowserIntegrations);

  exports.BrowserClient = BrowserClient;
  exports.Hub = Hub;
  exports.Integrations = INTEGRATIONS;
  exports.SDK_NAME = SDK_NAME;
  exports.SDK_VERSION = SDK_VERSION;
  exports.Scope = Scope;
  exports.Transports = index;
  exports.addBreadcrumb = addBreadcrumb;
  exports.addGlobalEventProcessor = addGlobalEventProcessor;
  exports.captureEvent = captureEvent;
  exports.captureException = captureException;
  exports.captureMessage = captureMessage;
  exports.close = close;
  exports.configureScope = configureScope;
  exports.defaultIntegrations = defaultIntegrations;
  exports.flush = flush;
  exports.forceLoad = forceLoad;
  exports.getCurrentHub = getCurrentHub;
  exports.getHubFromCarrier = getHubFromCarrier;
  exports.init = init;
  exports.lastEventId = lastEventId;
  exports.onLoad = onLoad;
  exports.setContext = setContext;
  exports.setExtra = setExtra;
  exports.setExtras = setExtras;
  exports.setTag = setTag;
  exports.setTags = setTags;
  exports.setUser = setUser;
  exports.showReportDialog = showReportDialog;
  exports.withScope = withScope;
  exports.wrap = wrap$1;

  return exports;

}({}));
//# sourceMappingURL=bundle.es6.js.map
