UNPKG

@sentry/browser

Version:
1,273 lines (1,247 loc) 304 kB
/*! @sentry/browser 6.19.7 (5b3a175) | https://github.com/getsentry/sentry-javascript */ var Sentry = (function (exports) { /*! ***************************************************************************** Copyright (c) Microsoft Corporation. Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ***************************************************************************** */ /* global Reflect, Promise */ var extendStatics = function(d, b) { extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; return extendStatics(d, b); }; function __extends(d, b) { if (typeof b !== "function" && b !== null) throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); } var __assign = function() { __assign = Object.assign || function __assign(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; function __values(o) { var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0; if (m) return m.call(o); if (o && typeof o.length === "number") return { next: function () { if (o && i >= o.length) o = void 0; return { value: o && o[i++], done: !o }; } }; throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined."); } function __read(o, n) { var m = typeof Symbol === "function" && o[Symbol.iterator]; if (!m) return o; var i = m.call(o), r, ar = [], e; try { while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); } catch (error) { e = { error: error }; } finally { try { if (r && !r.done && (m = i["return"])) m.call(i); } finally { if (e) throw e.error; } } return ar; } /** @deprecated */ function __spread() { for (var ar = [], i = 0; i < arguments.length; i++) ar = ar.concat(__read(arguments[i])); return ar; } /** * TODO(v7): Remove this enum and replace with SeverityLevel */ exports.Severity = void 0; (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 = {})); /** * Consumes the promise and logs the error when it rejects. * @param promise A promise to forget. */ // eslint-disable-next-line @typescript-eslint/no-explicit-any function forget(promise) { void promise.then(null, function (e) { // TODO: Use a better logging mechanism // eslint-disable-next-line no-console console.error(e); }); } /** * NOTE: In order to avoid circular dependencies, if you add a function to this module and it needs to print something, * you must either a) use `console.log` rather than the logger, or b) put your function elsewhere. */ var fallbackGlobalObject = {}; /** * Safely get global scope object * * @returns Global scope object */ function getGlobalObject() { return (typeof window !== 'undefined' // eslint-disable-line no-restricted-globals ? window // eslint-disable-line no-restricted-globals : typeof self !== 'undefined' ? self : fallbackGlobalObject); } /** * Returns a global singleton contained in the global `__SENTRY__` object. * * If the singleton doesn't already exist in `__SENTRY__`, it will be created using the given factory * function and added to the `__SENTRY__` object. * * @param name name of the global singleton on __SENTRY__ * @param creator creator Factory function to create the singleton if it doesn't already exist on `__SENTRY__` * @param obj (Optional) The global object on which to look for `__SENTRY__`, if not `getGlobalObject`'s return value * @returns the singleton */ function getGlobalSingleton(name, creator, obj) { var global = (obj || getGlobalObject()); var __SENTRY__ = (global.__SENTRY__ = global.__SENTRY__ || {}); var singleton = __SENTRY__[name] || (__SENTRY__[name] = creator()); return singleton; } /* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/explicit-module-boundary-types */ // eslint-disable-next-line @typescript-eslint/unbound-method var objectToString = Object.prototype.toString; /** * 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 (objectToString.call(wat)) { case '[object Error]': case '[object Exception]': case '[object DOMException]': return true; default: return isInstanceOf(wat, Error); } } function isBuiltin(wat, ty) { return objectToString.call(wat) === "[object " + ty + "]"; } /** * 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 isBuiltin(wat, '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 isBuiltin(wat, '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 isBuiltin(wat, '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 isBuiltin(wat, 'String'); } /** * Checks whether given value is a primitive (undefined, null, number, boolean, string, bigint, symbol) * {@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 isBuiltin(wat, '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) { 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) { 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 isBuiltin(wat, 'RegExp'); } /** * Checks whether given value has a then function. * @param wat A value to be checked. */ function isThenable(wat) { // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access return Boolean(wat && wat.then && typeof wat.then === 'function'); } /** * 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) { return isPlainObject(wat) && 'nativeEvent' in wat && 'preventDefault' in wat && 'stopPropagation' in wat; } /** * Checks whether given value is NaN * {@link isNaN}. * * @param wat A value to be checked. * @returns A boolean representing the result. */ function isNaN$1(wat) { return typeof wat === 'number' && wat !== 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 { return wat instanceof base; } catch (_e) { return false; } } /** * 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, keyAttrs) { // 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 { var currentElem = elem; var MAX_TRAVERSE_HEIGHT = 5; var MAX_OUTPUT_LEN = 80; var out = []; var height = 0; var len = 0; var separator = ' > '; var sepLength = separator.length; var nextStr = void 0; // eslint-disable-next-line no-plusplus while (currentElem && height++ < MAX_TRAVERSE_HEIGHT) { nextStr = _htmlElementAsString(currentElem, keyAttrs); // 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, keyAttrs) { var elem = el; var out = []; var className; var classes; var key; var attr; var i; if (!elem || !elem.tagName) { return ''; } out.push(elem.tagName.toLowerCase()); // Pairs of attribute keys defined in `serializeAttribute` and their values on element. var keyAttrPairs = keyAttrs && keyAttrs.length ? keyAttrs.filter(function (keyAttr) { return elem.getAttribute(keyAttr); }).map(function (keyAttr) { return [keyAttr, elem.getAttribute(keyAttr)]; }) : null; if (keyAttrPairs && keyAttrPairs.length) { keyAttrPairs.forEach(function (keyAttrPair) { out.push("[" + keyAttrPair[0] + "=\"" + keyAttrPair[1] + "\"]"); }); } else { if (elem.id) { out.push("#" + elem.id); } // eslint-disable-next-line prefer-const className = elem.className; if (className && isString(className)) { classes = className.split(/\s+/); for (i = 0; i < classes.length; i++) { out.push("." + classes[i]); } } } var allowedAttrs = ['type', 'name', 'title', 'alt']; for (i = 0; i < allowedAttrs.length; i++) { key = allowedAttrs[i]; attr = elem.getAttribute(key); if (attr) { out.push("[" + key + "=\"" + attr + "\"]"); } } return out.join(''); } /** * A safe form of location.href */ function getLocationHref() { var global = getGlobalObject(); try { return global.document.location.href; } catch (oO) { return ''; } } var setPrototypeOf = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array ? setProtoOf : mixinProperties); /** * setPrototypeOf polyfill using __proto__ */ // eslint-disable-next-line @typescript-eslint/ban-types function setProtoOf(obj, proto) { // @ts-ignore __proto__ does not exist on obj obj.__proto__ = proto; return obj; } /** * setPrototypeOf polyfill using mixin */ // eslint-disable-next-line @typescript-eslint/ban-types function mixinProperties(obj, proto) { for (var prop in proto) { if (!Object.prototype.hasOwnProperty.call(obj, prop)) { // @ts-ignore typescript complains about indexing so we remove obj[prop] = proto[prop]; } } return obj; } /** An error emitted by Sentry SDKs and related utilities. */ var SentryError = /** @class */ (function (_super) { __extends(SentryError, _super); function SentryError(message) { var _newTarget = this.constructor; var _this = _super.call(this, message) || this; _this.message = message; _this.name = _newTarget.prototype.constructor.name; setPrototypeOf(_this, _newTarget.prototype); return _this; } return SentryError; }(Error)); /* * This file defines flags and constants that can be modified during compile time in order to facilitate tree shaking * for users. * * Debug flags need to be declared in each package individually and must not be imported across package boundaries, * because some build tools have trouble tree-shaking imported guards. * * As a convention, we define debug flags in a `flags.ts` file in the root of a package's `src` folder. * * Debug flag files will contain "magic strings" like `true` that may get replaced with actual values during * our, or the user's build process. Take care when introducing new flags - they must not throw if they are not * replaced. */ /** Flag that is true for debug builds, false otherwise. */ var IS_DEBUG_BUILD$3 = true; /** Regular expression used to parse a Dsn. */ var DSN_REGEX = /^(?:(\w+):)\/\/(?:(\w+)(?::(\w+))?@)([\w.-]+)(?::(\d+))?\/(.+)/; function isValidProtocol(protocol) { return protocol === 'http' || protocol === 'https'; } /** * 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. */ function dsnToString(dsn, withPassword) { if (withPassword === void 0) { withPassword = false; } var host = dsn.host, path = dsn.path, pass = dsn.pass, port = dsn.port, projectId = dsn.projectId, protocol = dsn.protocol, publicKey = dsn.publicKey; return (protocol + "://" + publicKey + (withPassword && pass ? ":" + pass : '') + ("@" + host + (port ? ":" + port : '') + "/" + (path ? path + "/" : path) + projectId)); } function dsnFromString(str) { var match = DSN_REGEX.exec(str); if (!match) { throw new SentryError("Invalid Sentry Dsn: " + str); } var _a = __read(match.slice(1), 6), protocol = _a[0], publicKey = _a[1], _b = _a[2], pass = _b === void 0 ? '' : _b, host = _a[3], _c = _a[4], port = _c === void 0 ? '' : _c, lastPath = _a[5]; var path = ''; var projectId = lastPath; var split = projectId.split('/'); if (split.length > 1) { path = split.slice(0, -1).join('/'); projectId = split.pop(); } if (projectId) { var projectMatch = projectId.match(/^\d+/); if (projectMatch) { projectId = projectMatch[0]; } } return dsnFromComponents({ host: host, pass: pass, path: path, projectId: projectId, port: port, protocol: protocol, publicKey: publicKey }); } function dsnFromComponents(components) { // TODO this is for backwards compatibility, and can be removed in a future version if ('user' in components && !('publicKey' in components)) { components.publicKey = components.user; } return { user: components.publicKey || '', protocol: components.protocol, publicKey: components.publicKey || '', pass: components.pass || '', host: components.host, port: components.port || '', path: components.path || '', projectId: components.projectId, }; } function validateDsn(dsn) { var port = dsn.port, projectId = dsn.projectId, protocol = dsn.protocol; var requiredComponents = ['protocol', 'publicKey', 'host', 'projectId']; requiredComponents.forEach(function (component) { if (!dsn[component]) { throw new SentryError("Invalid Sentry Dsn: " + component + " missing"); } }); if (!projectId.match(/^\d+$/)) { throw new SentryError("Invalid Sentry Dsn: Invalid projectId " + projectId); } if (!isValidProtocol(protocol)) { throw new SentryError("Invalid Sentry Dsn: Invalid protocol " + protocol); } if (port && isNaN(parseInt(port, 10))) { throw new SentryError("Invalid Sentry Dsn: Invalid port " + port); } return true; } /** The Sentry Dsn, identifying a Sentry instance and project. */ function makeDsn(from) { var components = typeof from === 'string' ? dsnFromString(from) : dsnFromComponents(from); validateDsn(components); return components; } var SeverityLevels = ['fatal', 'error', 'warning', 'log', 'info', 'debug', 'critical']; // TODO: Implement different loggers for different environments var global$6 = getGlobalObject(); /** Prefix for logging strings */ var PREFIX = 'Sentry Logger '; var CONSOLE_LEVELS = ['debug', 'info', 'warn', 'error', 'log', 'assert']; /** * Temporarily disable sentry console instrumentations. * * @param callback The function to run against the original `console` messages * @returns The results of the callback */ function consoleSandbox(callback) { var global = getGlobalObject(); if (!('console' in global)) { return callback(); } var originalConsole = global.console; var wrappedLevels = {}; // Restore all wrapped console methods CONSOLE_LEVELS.forEach(function (level) { // TODO(v7): Remove this check as it's only needed for Node 6 var originalWrappedFunc = originalConsole[level] && originalConsole[level].__sentry_original__; if (level in global.console && originalWrappedFunc) { wrappedLevels[level] = originalConsole[level]; originalConsole[level] = originalWrappedFunc; } }); try { return callback(); } finally { // Revert restoration to wrapped state Object.keys(wrappedLevels).forEach(function (level) { originalConsole[level] = wrappedLevels[level]; }); } } function makeLogger() { var enabled = false; var logger = { enable: function () { enabled = true; }, disable: function () { enabled = false; }, }; if (IS_DEBUG_BUILD$3) { CONSOLE_LEVELS.forEach(function (name) { // eslint-disable-next-line @typescript-eslint/no-explicit-any logger[name] = function () { var args = []; for (var _i = 0; _i < arguments.length; _i++) { args[_i] = arguments[_i]; } if (enabled) { consoleSandbox(function () { var _a; (_a = global$6.console)[name].apply(_a, __spread([PREFIX + "[" + name + "]:"], args)); }); } }; }); } else { CONSOLE_LEVELS.forEach(function (name) { logger[name] = function () { return undefined; }; }); } return logger; } // Ensure we only have a single logger instance, even if multiple versions of @sentry/utils are being used var logger; if (IS_DEBUG_BUILD$3) { logger = getGlobalSingleton('logger', makeLogger); } else { logger = makeLogger(); } /** * 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 (0 = unlimited) * @returns string Encoded */ function truncate(str, max) { if (max === void 0) { max = 0; } 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 */ // eslint-disable-next-line @typescript-eslint/no-explicit-any function safeJoin(input, delimiter) { if (!Array.isArray(input)) { return ''; } var output = []; // eslint-disable-next-line @typescript-eslint/prefer-for-of for (var i = 0; i < input.length; i++) { var 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 (!isString(value)) { return false; } if (isRegExp(pattern)) { return pattern.test(value); } if (typeof pattern === 'string') { return value.indexOf(pattern) !== -1; } return false; } /** * Replace a method in an object with a wrapped version of itself. * * @param source An object that contains a method to be wrapped. * @param name The name of the method to be wrapped. * @param replacementFactory A higher-order function that takes the original version of the given method and returns a * wrapped version. Note: The function returned by `replacementFactory` needs to be a non-arrow function, in order to * preserve the correct value of `this`, and the original method must be called using `origMethod.call(this, <other * args>)` or `origMethod.apply(this, [<other args>])` (rather than being called directly), again to preserve `this`. * @returns void */ function fill(source, name, replacementFactory) { if (!(name in source)) { return; } var original = source[name]; var wrapped = replacementFactory(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" if (typeof wrapped === 'function') { try { markFunctionWrapped(wrapped, 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; } /** * Defines a non-enumerable property on the given object. * * @param obj The object on which to set the property * @param name The name of the property to be set * @param value The value to which to set the property */ function addNonEnumerableProperty(obj, name, value) { Object.defineProperty(obj, name, { // enumerable: false, // the default, so we can save on bundle size by not explicitly setting it value: value, writable: true, configurable: true, }); } /** * Remembers the original function on the wrapped function and * patches up the prototype. * * @param wrapped the wrapper function * @param original the original function that gets wrapped */ function markFunctionWrapped(wrapped, original) { var proto = original.prototype || {}; wrapped.prototype = original.prototype = proto; addNonEnumerableProperty(wrapped, '__sentry_original__', original); } /** * This extracts the original function if available. See * `markFunctionWrapped` for more information. * * @param func the function to unwrap * @returns the unwrapped version of the function if available. */ function getOriginalFunction(func) { return func.__sentry_original__; } /** * 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(function (key) { return encodeURIComponent(key) + "=" + encodeURIComponent(object[key]); }) .join('&'); } /** * Transforms any object into an object literal with all its attributes * attached to it. * * @param value Initial source that we have to transform in order for it to be usable by the serializer */ function convertToPlainObject(value) { var newObj = value; if (isError(value)) { newObj = __assign({ message: value.message, name: value.name, stack: value.stack }, getOwnProperties(value)); } else if (isEvent(value)) { var event_1 = value; newObj = __assign({ type: event_1.type, target: serializeEventTarget(event_1.target), currentTarget: serializeEventTarget(event_1.currentTarget) }, getOwnProperties(event_1)); if (typeof CustomEvent !== 'undefined' && isInstanceOf(value, CustomEvent)) { newObj.detail = event_1.detail; } } return newObj; } /** Creates a string representation of the target of an `Event` object */ function serializeEventTarget(target) { try { return isElement(target) ? htmlTreeAsString(target) : Object.prototype.toString.call(target); } catch (_oO) { return '<unknown>'; } } /** Filters out all but an object's own properties */ function getOwnProperties(obj) { var extractedProps = {}; for (var property in obj) { if (Object.prototype.hasOwnProperty.call(obj, property)) { extractedProps[property] = obj[property]; } } return extractedProps; } /** * 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` */ // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types function extractExceptionKeysForMessage(exception, maxLength) { if (maxLength === void 0) { maxLength = 40; } var keys = Object.keys(convertToPlainObject(exception)); keys.sort(); if (!keys.length) { return '[object has no keys]'; } if (keys[0].length >= maxLength) { return truncate(keys[0], maxLength); } for (var includedKeys = keys.length; includedKeys > 0; includedKeys--) { var serialized = keys.slice(0, includedKeys).join(', '); if (serialized.length > maxLength) { continue; } if (includedKeys === keys.length) { return serialized; } return truncate(serialized, maxLength); } return ''; } /** * Given any object, return the new object with removed keys that value was `undefined`. * Works recursively on objects and arrays. */ function dropUndefinedKeys(val) { var e_1, _a; if (isPlainObject(val)) { var rv = {}; try { for (var _b = __values(Object.keys(val)), _c = _b.next(); !_c.done; _c = _b.next()) { var key = _c.value; if (typeof val[key] !== 'undefined') { rv[key] = dropUndefinedKeys(val[key]); } } } catch (e_1_1) { e_1 = { error: e_1_1 }; } finally { try { if (_c && !_c.done && (_a = _b.return)) _a.call(_b); } finally { if (e_1) throw e_1.error; } } return rv; } if (Array.isArray(val)) { return val.map(dropUndefinedKeys); } return val; } var STACKTRACE_LIMIT = 50; /** * Creates a stack parser with the supplied line parsers * * StackFrames are returned in the correct order for Sentry Exception * frames and with Sentry SDK internal frames removed from the top and bottom * */ function createStackParser() { var parsers = []; for (var _i = 0; _i < arguments.length; _i++) { parsers[_i] = arguments[_i]; } var sortedParsers = parsers.sort(function (a, b) { return a[0] - b[0]; }).map(function (p) { return p[1]; }); return function (stack, skipFirst) { var e_1, _a, e_2, _b; if (skipFirst === void 0) { skipFirst = 0; } var frames = []; try { for (var _c = __values(stack.split('\n').slice(skipFirst)), _d = _c.next(); !_d.done; _d = _c.next()) { var line = _d.value; try { for (var sortedParsers_1 = (e_2 = void 0, __values(sortedParsers)), sortedParsers_1_1 = sortedParsers_1.next(); !sortedParsers_1_1.done; sortedParsers_1_1 = sortedParsers_1.next()) { var parser = sortedParsers_1_1.value; var frame = parser(line); if (frame) { frames.push(frame); break; } } } catch (e_2_1) { e_2 = { error: e_2_1 }; } finally { try { if (sortedParsers_1_1 && !sortedParsers_1_1.done && (_b = sortedParsers_1.return)) _b.call(sortedParsers_1); } finally { if (e_2) throw e_2.error; } } } } catch (e_1_1) { e_1 = { error: e_1_1 }; } finally { try { if (_d && !_d.done && (_a = _c.return)) _a.call(_c); } finally { if (e_1) throw e_1.error; } } return stripSentryFramesAndReverse(frames); }; } /** * @hidden */ function stripSentryFramesAndReverse(stack) { if (!stack.length) { return []; } var localStack = stack; var firstFrameFunction = localStack[0].function || ''; var lastFrameFunction = localStack[localStack.length - 1].function || ''; // 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 .slice(0, STACKTRACE_LIMIT) .map(function (frame) { return (__assign(__assign({}, frame), { filename: frame.filename || localStack[0].filename, function: frame.function || '?' })); }) .reverse(); } var 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; } } /** * Tells whether current environment supports Fetch API * {@link supportsFetch}. * * @returns Answer to the given question. */ function supportsFetch() { if (!('fetch' in getGlobalObject())) { return false; } try { new Headers(); new Request(''); new Response(); return true; } catch (e) { return false; } } /** * isNativeFetch checks if the given function is a native implementation of fetch() */ // eslint-disable-next-line @typescript-eslint/ban-types 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; } var global = getGlobalObject(); // Fast path to avoid DOM I/O // eslint-disable-next-line @typescript-eslint/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 var result = false; var doc = global.document; // eslint-disable-next-line deprecation/deprecation if (doc && typeof doc.createElement === 'function') { try { var sandbox = doc.createElement('iframe'); sandbox.hidden = true; doc.head.appendChild(sandbox); if (sandbox.contentWindow && sandbox.contentWindow.fetch) { // eslint-disable-next-line @typescript-eslint/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' // (see https://caniuse.com/#feat=referrer-policy), // it doesn't. And it throws an exception instead of ignoring this parameter... // REF: https://github.com/getsentry/raven-js/issues/1233 if (!supportsFetch()) { return false; } try { 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 var global = getGlobalObject(); /* eslint-disable @typescript-eslint/no-unsafe-member-access */ // eslint-disable-next-line @typescript-eslint/no-explicit-any var chrome = global.chrome; var isChromePackagedApp = chrome && chrome.app && chrome.app.runtime; /* eslint-enable @typescript-eslint/no-unsafe-member-access */ var hasHistoryApi = 'history' in global && !!global.history.pushState && !!global.history.replaceState; return !isChromePackagedApp && hasHistoryApi; } var global$5 = 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) * - Error API * - UnhandledRejection API */ var handlers = {}; var 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; case 'error': instrumentError(); break; case 'unhandledrejection': instrumentUnhandledRejection(); break; default: logger.warn('unknown instrumentation type:', type); return; } } /** * 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(type, callback) { handlers[type] = handlers[type] || []; handlers[type].push(callback); instrument(type); } /** JSDoc */ function triggerHandlers(type, data) { var e_1, _a; if (!type || !handlers[type]) { return; } try { for (var _b = __values(handlers[type] || []), _c = _b.next(); !_c.done; _c = _b.next()) { var handler = _c.value; try { handler(data); } catch (e) { logger.error("Error while triggering instrumentation handler.\nType: " + type + "\nName: " + getFunctionName(handler) + "\nError:", e); } } } catch (e_1_1) { e_1 = { error: e_1_1 }; } finally { try { if (_c && !_c.done && (_a = _b.return)) _a.call(_b); } finally { if (e_1) throw e_1.error; } } } /** JSDoc */ function instrumentConsole() { if (!('console' in global$5)) { return; } CONSOLE_LEVELS.forEach(function (level) { if (!(level in global$5.console)) { return; } fill(global$5.console, level, function (originalConsoleMethod) { return function () { var args = []; for (var _i = 0; _i < arguments.length; _i++) { args[_i] = arguments[_i]; } triggerHandlers('console', { args: args, level: level }); // this fails for some browsers. :( if (originalConsoleMethod) { originalConsoleMethod.apply(global$5.console, args); } }; }); }); } /** JSDoc */ function instrumentFetch() { if (!supportsNativeFetch()) { return; } fill(global$5, 'fetch', function (originalFetch) { return function () { var args = []; for (var _i = 0; _i < arguments.length; _i++) { args[_i] = arguments[_i]; } var handlerData = { args: args, fetchData: { method: getFetchMethod(args), url: getFetchUrl(args), }, startTimestamp: Date.now(), }; triggerHandlers('fetch', __assign({}, handlerData)); // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access return originalFetch.apply(global$5, args).then(function (response) { triggerHandlers('fetch', __assign(__assign({}, handlerData), { endTimestamp: Date.now(), response: response })); return response; }, function (error) { triggerHandlers('fetch', __assign(__assign({}, handlerData), { endTimestamp: Date.now(), error: error })); // 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. throw error; }); }; }); } /* eslint-disable @typescript-eslint/no-unsafe-member-access */ /** Extract `method` from fetch call arguments */ function getFetchMethod(fetchArgs) { if (fetchArgs === void 0) { fetchArgs = []; } if ('Request' in global$5 && 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 (fetchArgs === void 0) { fetchArgs = []; } if (typeof fetchArgs[0] === 'string') { return fetchArgs[0]; } if ('Request' in global$5 && isInstanceOf(fetchArgs[0], Request)) { return fetchArgs[0].url; } return String(fetchArgs[0]); } /* eslint-enable @typescript-eslint/no-unsafe-member-access */ /** JSDoc */ function instrumentXHR() { if (!('XMLHttpRequest' in global$5)) { return; } var xhrproto = XMLHttpRequest.prototype; fill(xhrproto, 'open', function (originalOpen) { return function () { var args = []; for (var _i = 0; _i < arguments.length; _i++) { args[_i] = arguments[_i]; } // eslint-disable-next-line @typescript-eslint/no-this-alias var xhr = this; var url = args[1]; var xhrInfo = (xhr.__sentry_xhr__ = { // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access 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 // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access if (isString(url) && xhrInfo.method === 'POST' && url.match(/sentry_key/)) { xhr.__sentry_own_request__ = true; } var onreadystatechangeHandler = function () { if (xhr.readyState === 4) { try { // touching statusCode in some platforms throws // an exception xhrInfo.status_code = xhr.status; } catch (e) { /* do nothing */ } triggerHandlers('xhr', { args: args, endTimestamp: Date.now(), startTimestamp: Date.now(), xhr: xhr, }); } }; if ('onreadystatechange' in xhr && typeof xhr.onreadystatechange === 'function') { fill(xhr, 'onreadystatechange', function (original) {