UNPKG

@sentry/bundler-plugin-core

Version:
1,483 lines (1,337 loc) 337 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var core = require('@babel/core'); var componentNameAnnotatePlugin = require('@sentry/babel-plugin-component-annotate'); var SentryCli = require('@sentry/cli'); var fs = require('fs'); var glob = require('glob'); var MagicString = require('magic-string'); var path = require('path'); var unplugin = require('unplugin'); var dotenv = require('dotenv'); var os = require('os'); var findUp = require('find-up'); var crypto = require('crypto'); var childProcess = require('child_process'); var https = require('node:https'); var node_stream = require('node:stream'); var node_zlib = require('node:zlib'); var url = require('url'); var util = require('util'); function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; } function _interopNamespace(e) { if (e && e.__esModule) return e; var n = Object.create(null); if (e) { Object.keys(e).forEach(function (k) { if (k !== 'default') { var d = Object.getOwnPropertyDescriptor(e, k); Object.defineProperty(n, k, d.get ? d : { enumerable: true, get: function () { return e[k]; } }); } }); } n["default"] = e; return Object.freeze(n); } var componentNameAnnotatePlugin__default = /*#__PURE__*/_interopDefaultLegacy(componentNameAnnotatePlugin); var SentryCli__default = /*#__PURE__*/_interopDefaultLegacy(SentryCli); var fs__default = /*#__PURE__*/_interopDefaultLegacy(fs); var fs__namespace = /*#__PURE__*/_interopNamespace(fs); var MagicString__default = /*#__PURE__*/_interopDefaultLegacy(MagicString); var path__default = /*#__PURE__*/_interopDefaultLegacy(path); var path__namespace = /*#__PURE__*/_interopNamespace(path); var dotenv__namespace = /*#__PURE__*/_interopNamespace(dotenv); var os__default = /*#__PURE__*/_interopDefaultLegacy(os); var os__namespace = /*#__PURE__*/_interopNamespace(os); var findUp__default = /*#__PURE__*/_interopDefaultLegacy(findUp); var crypto__default = /*#__PURE__*/_interopDefaultLegacy(crypto); var childProcess__default = /*#__PURE__*/_interopDefaultLegacy(childProcess); var https__namespace = /*#__PURE__*/_interopNamespace(https); var url__namespace = /*#__PURE__*/_interopNamespace(url); var util__namespace = /*#__PURE__*/_interopNamespace(util); function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; } function _objectSpread2(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; } function _regeneratorRuntime() { _regeneratorRuntime = function () { return exports; }; var exports = {}, Op = Object.prototype, hasOwn = Op.hasOwnProperty, defineProperty = Object.defineProperty || function (obj, key, desc) { obj[key] = desc.value; }, $Symbol = "function" == typeof Symbol ? Symbol : {}, iteratorSymbol = $Symbol.iterator || "@@iterator", asyncIteratorSymbol = $Symbol.asyncIterator || "@@asyncIterator", toStringTagSymbol = $Symbol.toStringTag || "@@toStringTag"; function define(obj, key, value) { return Object.defineProperty(obj, key, { value: value, enumerable: !0, configurable: !0, writable: !0 }), obj[key]; } try { define({}, ""); } catch (err) { define = function (obj, key, value) { return obj[key] = value; }; } function wrap(innerFn, outerFn, self, tryLocsList) { var protoGenerator = outerFn && outerFn.prototype instanceof Generator ? outerFn : Generator, generator = Object.create(protoGenerator.prototype), context = new Context(tryLocsList || []); return defineProperty(generator, "_invoke", { value: makeInvokeMethod(innerFn, self, context) }), generator; } function tryCatch(fn, obj, arg) { try { return { type: "normal", arg: fn.call(obj, arg) }; } catch (err) { return { type: "throw", arg: err }; } } exports.wrap = wrap; var ContinueSentinel = {}; function Generator() {} function GeneratorFunction() {} function GeneratorFunctionPrototype() {} var IteratorPrototype = {}; define(IteratorPrototype, iteratorSymbol, function () { return this; }); var getProto = Object.getPrototypeOf, NativeIteratorPrototype = getProto && getProto(getProto(values([]))); NativeIteratorPrototype && NativeIteratorPrototype !== Op && hasOwn.call(NativeIteratorPrototype, iteratorSymbol) && (IteratorPrototype = NativeIteratorPrototype); var Gp = GeneratorFunctionPrototype.prototype = Generator.prototype = Object.create(IteratorPrototype); function defineIteratorMethods(prototype) { ["next", "throw", "return"].forEach(function (method) { define(prototype, method, function (arg) { return this._invoke(method, arg); }); }); } function AsyncIterator(generator, PromiseImpl) { function invoke(method, arg, resolve, reject) { var record = tryCatch(generator[method], generator, arg); if ("throw" !== record.type) { var result = record.arg, value = result.value; return value && "object" == typeof value && hasOwn.call(value, "__await") ? PromiseImpl.resolve(value.__await).then(function (value) { invoke("next", value, resolve, reject); }, function (err) { invoke("throw", err, resolve, reject); }) : PromiseImpl.resolve(value).then(function (unwrapped) { result.value = unwrapped, resolve(result); }, function (error) { return invoke("throw", error, resolve, reject); }); } reject(record.arg); } var previousPromise; defineProperty(this, "_invoke", { value: function (method, arg) { function callInvokeWithMethodAndArg() { return new PromiseImpl(function (resolve, reject) { invoke(method, arg, resolve, reject); }); } return previousPromise = previousPromise ? previousPromise.then(callInvokeWithMethodAndArg, callInvokeWithMethodAndArg) : callInvokeWithMethodAndArg(); } }); } function makeInvokeMethod(innerFn, self, context) { var state = "suspendedStart"; return function (method, arg) { if ("executing" === state) throw new Error("Generator is already running"); if ("completed" === state) { if ("throw" === method) throw arg; return doneResult(); } for (context.method = method, context.arg = arg;;) { var delegate = context.delegate; if (delegate) { var delegateResult = maybeInvokeDelegate(delegate, context); if (delegateResult) { if (delegateResult === ContinueSentinel) continue; return delegateResult; } } if ("next" === context.method) context.sent = context._sent = context.arg;else if ("throw" === context.method) { if ("suspendedStart" === state) throw state = "completed", context.arg; context.dispatchException(context.arg); } else "return" === context.method && context.abrupt("return", context.arg); state = "executing"; var record = tryCatch(innerFn, self, context); if ("normal" === record.type) { if (state = context.done ? "completed" : "suspendedYield", record.arg === ContinueSentinel) continue; return { value: record.arg, done: context.done }; } "throw" === record.type && (state = "completed", context.method = "throw", context.arg = record.arg); } }; } function maybeInvokeDelegate(delegate, context) { var methodName = context.method, method = delegate.iterator[methodName]; if (undefined === method) return context.delegate = null, "throw" === methodName && delegate.iterator.return && (context.method = "return", context.arg = undefined, maybeInvokeDelegate(delegate, context), "throw" === context.method) || "return" !== methodName && (context.method = "throw", context.arg = new TypeError("The iterator does not provide a '" + methodName + "' method")), ContinueSentinel; var record = tryCatch(method, delegate.iterator, context.arg); if ("throw" === record.type) return context.method = "throw", context.arg = record.arg, context.delegate = null, ContinueSentinel; var info = record.arg; return info ? info.done ? (context[delegate.resultName] = info.value, context.next = delegate.nextLoc, "return" !== context.method && (context.method = "next", context.arg = undefined), context.delegate = null, ContinueSentinel) : info : (context.method = "throw", context.arg = new TypeError("iterator result is not an object"), context.delegate = null, ContinueSentinel); } function pushTryEntry(locs) { var entry = { tryLoc: locs[0] }; 1 in locs && (entry.catchLoc = locs[1]), 2 in locs && (entry.finallyLoc = locs[2], entry.afterLoc = locs[3]), this.tryEntries.push(entry); } function resetTryEntry(entry) { var record = entry.completion || {}; record.type = "normal", delete record.arg, entry.completion = record; } function Context(tryLocsList) { this.tryEntries = [{ tryLoc: "root" }], tryLocsList.forEach(pushTryEntry, this), this.reset(!0); } function values(iterable) { if (iterable) { var iteratorMethod = iterable[iteratorSymbol]; if (iteratorMethod) return iteratorMethod.call(iterable); if ("function" == typeof iterable.next) return iterable; if (!isNaN(iterable.length)) { var i = -1, next = function next() { for (; ++i < iterable.length;) if (hasOwn.call(iterable, i)) return next.value = iterable[i], next.done = !1, next; return next.value = undefined, next.done = !0, next; }; return next.next = next; } } return { next: doneResult }; } function doneResult() { return { value: undefined, done: !0 }; } return GeneratorFunction.prototype = GeneratorFunctionPrototype, defineProperty(Gp, "constructor", { value: GeneratorFunctionPrototype, configurable: !0 }), defineProperty(GeneratorFunctionPrototype, "constructor", { value: GeneratorFunction, configurable: !0 }), GeneratorFunction.displayName = define(GeneratorFunctionPrototype, toStringTagSymbol, "GeneratorFunction"), exports.isGeneratorFunction = function (genFun) { var ctor = "function" == typeof genFun && genFun.constructor; return !!ctor && (ctor === GeneratorFunction || "GeneratorFunction" === (ctor.displayName || ctor.name)); }, exports.mark = function (genFun) { return Object.setPrototypeOf ? Object.setPrototypeOf(genFun, GeneratorFunctionPrototype) : (genFun.__proto__ = GeneratorFunctionPrototype, define(genFun, toStringTagSymbol, "GeneratorFunction")), genFun.prototype = Object.create(Gp), genFun; }, exports.awrap = function (arg) { return { __await: arg }; }, defineIteratorMethods(AsyncIterator.prototype), define(AsyncIterator.prototype, asyncIteratorSymbol, function () { return this; }), exports.AsyncIterator = AsyncIterator, exports.async = function (innerFn, outerFn, self, tryLocsList, PromiseImpl) { void 0 === PromiseImpl && (PromiseImpl = Promise); var iter = new AsyncIterator(wrap(innerFn, outerFn, self, tryLocsList), PromiseImpl); return exports.isGeneratorFunction(outerFn) ? iter : iter.next().then(function (result) { return result.done ? result.value : iter.next(); }); }, defineIteratorMethods(Gp), define(Gp, toStringTagSymbol, "Generator"), define(Gp, iteratorSymbol, function () { return this; }), define(Gp, "toString", function () { return "[object Generator]"; }), exports.keys = function (val) { var object = Object(val), keys = []; for (var key in object) keys.push(key); return keys.reverse(), function next() { for (; keys.length;) { var key = keys.pop(); if (key in object) return next.value = key, next.done = !1, next; } return next.done = !0, next; }; }, exports.values = values, Context.prototype = { constructor: Context, reset: function (skipTempReset) { if (this.prev = 0, this.next = 0, this.sent = this._sent = undefined, this.done = !1, this.delegate = null, this.method = "next", this.arg = undefined, this.tryEntries.forEach(resetTryEntry), !skipTempReset) for (var name in this) "t" === name.charAt(0) && hasOwn.call(this, name) && !isNaN(+name.slice(1)) && (this[name] = undefined); }, stop: function () { this.done = !0; var rootRecord = this.tryEntries[0].completion; if ("throw" === rootRecord.type) throw rootRecord.arg; return this.rval; }, dispatchException: function (exception) { if (this.done) throw exception; var context = this; function handle(loc, caught) { return record.type = "throw", record.arg = exception, context.next = loc, caught && (context.method = "next", context.arg = undefined), !!caught; } for (var i = this.tryEntries.length - 1; i >= 0; --i) { var entry = this.tryEntries[i], record = entry.completion; if ("root" === entry.tryLoc) return handle("end"); if (entry.tryLoc <= this.prev) { var hasCatch = hasOwn.call(entry, "catchLoc"), hasFinally = hasOwn.call(entry, "finallyLoc"); if (hasCatch && hasFinally) { if (this.prev < entry.catchLoc) return handle(entry.catchLoc, !0); if (this.prev < entry.finallyLoc) return handle(entry.finallyLoc); } else if (hasCatch) { if (this.prev < entry.catchLoc) return handle(entry.catchLoc, !0); } else { if (!hasFinally) throw new Error("try statement without catch or finally"); if (this.prev < entry.finallyLoc) return handle(entry.finallyLoc); } } } }, abrupt: function (type, arg) { for (var i = this.tryEntries.length - 1; i >= 0; --i) { var entry = this.tryEntries[i]; if (entry.tryLoc <= this.prev && hasOwn.call(entry, "finallyLoc") && this.prev < entry.finallyLoc) { var finallyEntry = entry; break; } } finallyEntry && ("break" === type || "continue" === type) && finallyEntry.tryLoc <= arg && arg <= finallyEntry.finallyLoc && (finallyEntry = null); var record = finallyEntry ? finallyEntry.completion : {}; return record.type = type, record.arg = arg, finallyEntry ? (this.method = "next", this.next = finallyEntry.finallyLoc, ContinueSentinel) : this.complete(record); }, complete: function (record, afterLoc) { if ("throw" === record.type) throw record.arg; return "break" === record.type || "continue" === record.type ? this.next = record.arg : "return" === record.type ? (this.rval = this.arg = record.arg, this.method = "return", this.next = "end") : "normal" === record.type && afterLoc && (this.next = afterLoc), ContinueSentinel; }, finish: function (finallyLoc) { for (var i = this.tryEntries.length - 1; i >= 0; --i) { var entry = this.tryEntries[i]; if (entry.finallyLoc === finallyLoc) return this.complete(entry.completion, entry.afterLoc), resetTryEntry(entry), ContinueSentinel; } }, catch: function (tryLoc) { for (var i = this.tryEntries.length - 1; i >= 0; --i) { var entry = this.tryEntries[i]; if (entry.tryLoc === tryLoc) { var record = entry.completion; if ("throw" === record.type) { var thrown = record.arg; resetTryEntry(entry); } return thrown; } } throw new Error("illegal catch attempt"); }, delegateYield: function (iterable, resultName, nextLoc) { return this.delegate = { iterator: values(iterable), resultName: resultName, nextLoc: nextLoc }, "next" === this.method && (this.arg = undefined), ContinueSentinel; } }, exports; } function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); } function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } } function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; } function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function _toPrimitive(input, hint) { if (typeof input !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (typeof res !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); } function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return typeof key === "symbol" ? key : String(key); } // eslint-disable-next-line @typescript-eslint/unbound-method const 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); } } /** * Checks whether given value is an instance of the given built-in class. * * @param wat The value to be checked * @param className * @returns A boolean representing the result. */ function isBuiltin(wat, className) { return objectToString.call(wat) === `[object ${className}]`; } /** * 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$1(wat) { return isBuiltin(wat, 'ErrorEvent'); } /** * 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 string is parameterized * {@link isParameterizedString}. * * @param wat A value to be checked. * @returns A boolean representing the result. */ function isParameterizedString(wat) { return ( typeof wat === 'object' && wat !== null && '__sentry_template_string__' in wat && '__sentry_template_values__' in wat ); } /** * 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 || isParameterizedString(wat) || (typeof wat !== 'object' && typeof wat !== 'function'); } /** * Checks whether given value's type is an object literal, or a class instance. * {@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 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'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; } } /** * Checks whether given value's type is a Vue ViewModel. * * @param wat A value to be checked. * @returns A boolean representing the result. */ function isVueViewModel(wat) { // Not using Object.prototype.toString because in Vue 3 it would read the instance's Symbol(Symbol.toStringTag) property. return !!(typeof wat === 'object' && wat !== null && ((wat ).__isVue || (wat )._isVue)); } /** * 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 = 0) { if (typeof str !== 'string' || max === 0) { return str; } return str.length <= max ? str : `${str.slice(0, max)}...`; } const SDK_VERSION = '8.30.0'; /** Get's the global object for the current JavaScript runtime */ const GLOBAL_OBJ = globalThis ; /** * 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 `GLOBAL_OBJ`'s return value * @returns the singleton */ function getGlobalSingleton(name, creator, obj) { const gbl = (obj || GLOBAL_OBJ) ; const __SENTRY__ = (gbl.__SENTRY__ = gbl.__SENTRY__ || {}); const versionedCarrier = (__SENTRY__[SDK_VERSION] = __SENTRY__[SDK_VERSION] || {}); return versionedCarrier[name] || (versionedCarrier[name] = creator()); } const WINDOW = GLOBAL_OBJ ; const DEFAULT_MAX_STRING_LENGTH = 80; /** * 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, options = {}, ) { if (!elem) { return '<unknown>'; } // 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 out = []; let height = 0; let len = 0; const separator = ' > '; const sepLength = separator.length; let nextStr; const keyAttrs = Array.isArray(options) ? options : options.keyAttrs; const maxStringLength = (!Array.isArray(options) && options.maxStringLength) || DEFAULT_MAX_STRING_LENGTH; 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 maxStringLength // (ignore this limit if we are on the first iteration) if (nextStr === 'html' || (height > 1 && len + out.length * sepLength + nextStr.length >= maxStringLength)) { 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) { const elem = el ; const out = []; if (!elem || !elem.tagName) { return ''; } // @ts-expect-error WINDOW has HTMLElement if (WINDOW.HTMLElement) { // If using the component name annotation plugin, this value may be available on the DOM node if (elem instanceof HTMLElement && elem.dataset) { if (elem.dataset['sentryComponent']) { return elem.dataset['sentryComponent']; } if (elem.dataset['sentryElement']) { return elem.dataset['sentryElement']; } } } out.push(elem.tagName.toLowerCase()); // Pairs of attribute keys defined in `serializeAttribute` and their values on element. const keyAttrPairs = keyAttrs && keyAttrs.length ? keyAttrs.filter(keyAttr => elem.getAttribute(keyAttr)).map(keyAttr => [keyAttr, elem.getAttribute(keyAttr)]) : null; if (keyAttrPairs && keyAttrPairs.length) { keyAttrPairs.forEach(keyAttrPair => { out.push(`[${keyAttrPair[0]}="${keyAttrPair[1]}"]`); }); } else { if (elem.id) { out.push(`#${elem.id}`); } const className = elem.className; if (className && isString(className)) { const classes = className.split(/\s+/); for (const c of classes) { out.push(`.${c}`); } } } const allowedAttrs = ['aria-label', 'type', 'name', 'title', 'alt']; for (const k of allowedAttrs) { const attr = elem.getAttribute(k); if (attr) { out.push(`[${k}="${attr}"]`); } } return out.join(''); } /** * This serves as a build time flag that will be true by default, but false in non-debug builds or if users replace `__SENTRY_DEBUG__` in their generated code. * * ATTENTION: This constant must never cross package boundaries (i.e. be exported) to guarantee that it can be used for tree shaking. */ const DEBUG_BUILD$1 = (typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__); /** Prefix for logging strings */ const PREFIX = 'Sentry Logger '; const CONSOLE_LEVELS = [ 'debug', 'info', 'warn', 'error', 'log', 'assert', 'trace', ] ; /** This may be mutated by the console instrumentation. */ const originalConsoleMethods = {}; /** JSDoc */ /** * 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) { if (!('console' in GLOBAL_OBJ)) { return callback(); } const console = GLOBAL_OBJ.console ; const wrappedFuncs = {}; const wrappedLevels = Object.keys(originalConsoleMethods) ; // Restore all wrapped console methods wrappedLevels.forEach(level => { const originalConsoleMethod = originalConsoleMethods[level] ; wrappedFuncs[level] = console[level] ; console[level] = originalConsoleMethod; }); try { return callback(); } finally { // Revert restoration to wrapped state wrappedLevels.forEach(level => { console[level] = wrappedFuncs[level] ; }); } } function makeLogger() { let enabled = false; const logger = { enable: () => { enabled = true; }, disable: () => { enabled = false; }, isEnabled: () => enabled, }; if (DEBUG_BUILD$1) { CONSOLE_LEVELS.forEach(name => { // eslint-disable-next-line @typescript-eslint/no-explicit-any logger[name] = (...args) => { if (enabled) { consoleSandbox(() => { GLOBAL_OBJ.console[name](`${PREFIX}[${name}]:`, ...args); }); } }; }); } else { CONSOLE_LEVELS.forEach(name => { logger[name] = () => undefined; }); } return logger ; } /** * This is a logger singleton which either logs things or no-ops if logging is not enabled. * The logger is a singleton on the carrier, to ensure that a consistent logger is used throughout the SDK. */ const logger = getGlobalSingleton('logger', makeLogger); /** Regular expression used to parse a Dsn. */ const 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 = false) { const { host, path, pass, port, projectId, protocol, publicKey } = dsn; return ( `${protocol}://${publicKey}${withPassword && pass ? `:${pass}` : ''}` + `@${host}${port ? `:${port}` : ''}/${path ? `${path}/` : path}${projectId}` ); } /** * Parses a Dsn from a given string. * * @param str A Dsn as string * @returns Dsn as DsnComponents or undefined if @param str is not a valid DSN string */ function dsnFromString(str) { const match = DSN_REGEX.exec(str); if (!match) { // This should be logged to the console consoleSandbox(() => { // eslint-disable-next-line no-console console.error(`Invalid Sentry Dsn: ${str}`); }); return undefined; } const [protocol, publicKey, 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() ; } if (projectId) { const projectMatch = projectId.match(/^\d+/); if (projectMatch) { projectId = projectMatch[0]; } } return dsnFromComponents({ host, pass, path, projectId, port, protocol: protocol , publicKey }); } function dsnFromComponents(components) { return { protocol: components.protocol, publicKey: components.publicKey || '', pass: components.pass || '', host: components.host, port: components.port || '', path: components.path || '', projectId: components.projectId, }; } function validateDsn(dsn) { if (!DEBUG_BUILD$1) { return true; } const { port, projectId, protocol } = dsn; const requiredComponents = ['protocol', 'publicKey', 'host', 'projectId']; const hasMissingRequiredComponent = requiredComponents.find(component => { if (!dsn[component]) { logger.error(`Invalid Sentry Dsn: ${component} missing`); return true; } return false; }); if (hasMissingRequiredComponent) { return false; } if (!projectId.match(/^\d+$/)) { logger.error(`Invalid Sentry Dsn: Invalid projectId ${projectId}`); return false; } if (!isValidProtocol(protocol)) { logger.error(`Invalid Sentry Dsn: Invalid protocol ${protocol}`); return false; } if (port && isNaN(parseInt(port, 10))) { logger.error(`Invalid Sentry Dsn: Invalid port ${port}`); return false; } return true; } /** * Creates a valid Sentry Dsn object, identifying a Sentry instance and project. * @returns a valid DsnComponents object or `undefined` if @param from is an invalid DSN source */ function makeDsn(from) { const components = typeof from === 'string' ? dsnFromString(from) : dsnFromComponents(from); if (!components || !validateDsn(components)) { return undefined; } return components; } /** An error emitted by Sentry SDKs and related utilities. */ class SentryError extends Error { /** Display name of this error instance. */ constructor( message, logLevel = 'warn') { super(message);this.message = message; this.name = new.target.prototype.constructor.name; // This sets the prototype to be `Error`, not `SentryError`. It's unclear why we do this, but commenting this line // out causes various (seemingly totally unrelated) playwright tests consistently time out. FYI, this makes // instances of `SentryError` fail `obj instanceof SentryError` checks. Object.setPrototypeOf(this, new.target.prototype); this.logLevel = logLevel; } } /** * 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) { try { 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, }); } catch (o_O) { DEBUG_BUILD$1 && logger.log(`Failed to add non-enumerable property "${name}" to object`, obj); } } /** * 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(key => `${encodeURIComponent(key)}=${encodeURIComponent(object[key])}`) .join('&'); } /** * Transforms any `Error` or `Event` into a plain object with all of their enumerable properties, and some of their * non-enumerable properties attached. * * @param value Initial source that we have to transform in order for it to be usable by the serializer * @returns An Event or Error turned into an object - or the value argurment itself, when value is neither an Event nor * an Error. */ function convertToPlainObject( value, ) { if (isError(value)) { return { message: value.message, name: value.name, stack: value.stack, ...getOwnProperties(value), }; } else if (isEvent(value)) { const newObj = { type: value.type, target: serializeEventTarget(value.target), currentTarget: serializeEventTarget(value.currentTarget), ...getOwnProperties(value), }; if (typeof CustomEvent !== 'undefined' && isInstanceOf(value, CustomEvent)) { newObj.detail = value.detail; } return newObj; } else { return value; } } /** 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) { if (typeof obj === 'object' && obj !== null) { const extractedProps = {}; for (const property in obj) { if (Object.prototype.hasOwnProperty.call(obj, property)) { extractedProps[property] = (obj )[property]; } } return extractedProps; } else { return {}; } } /** * 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) { const keys = Object.keys(convertToPlainObject(exception)); keys.sort(); const firstKey = keys[0]; if (!firstKey) { return '[object has no keys]'; } if (firstKey.length >= maxLength) { return truncate(firstKey, 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 ''; } /** * Given any object, return a new object having removed all fields whose value was `undefined`. * Works recursively on objects and arrays. * * Attention: This function keeps circular references in the returned object. */ function dropUndefinedKeys(inputValue) { // This map keeps track of what already visited nodes map to. // Our Set - based memoBuilder doesn't work here because we want to the output object to have the same circular // references as the input object. const memoizationMap = new Map(); // This function just proxies `_dropUndefinedKeys` to keep the `memoBuilder` out of this function's API return _dropUndefinedKeys(inputValue, memoizationMap); } function _dropUndefinedKeys(inputValue, memoizationMap) { if (isPojo(inputValue)) { // If this node has already been visited due to a circular reference, return the object it was mapped to in the new object const memoVal = memoizationMap.get(inputValue); if (memoVal !== undefined) { return memoVal ; } const returnValue = {}; // Store the mapping of this value in case we visit it again, in case of circular data memoizationMap.set(inputValue, returnValue); for (const key of Object.keys(inputValue)) { if (typeof inputValue[key] !== 'undefined') { returnValue[key] = _dropUndefinedKeys(inputValue[key], memoizationMap); } } return returnValue ; } if (Array.isArray(inputValue)) { // If this node has already been visited due to a circular reference, return the array it was mapped to in the new object const memoVal = memoizationMap.get(inputValue); if (memoVal !== undefined) { return memoVal ; } const returnValue = []; // Store the mapping of this value in case we visit it again, in case of circular data memoizationMap.set(inputValue, returnValue); inputValue.forEach((item) => { returnValue.push(_dropUndefinedKeys(item, memoizationMap)); }); return returnValue ; } return inputValue; } function isPojo(input) { if (!isPlainObject(input)) { return false; } try { const name = (Object.getPrototypeOf(input) ).constructor.name; return !name || name === 'Object'; } catch (e) { return true; } } const STACKTRACE_FRAME_LIMIT = 50; const UNKNOWN_FUNCTION = '?'; // Used to sanitize webpack (error: *) wrapped stack errors const WEBPACK_ERROR_REGEXP = /\(error: (.*)\)/; const STRIP_FRAME_REGEXP = /captureMessage|captureException/; /** * 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(...parsers) { const sortedParsers = parsers.sort((a, b) => a[0] - b[0]).map(p => p[1]); return (stack, skipFirstLines = 0, framesToPop = 0) => { const frames = []; const lines = stack.split('\n'); for (let i = skipFirstLines; i < lines.length; i++) { const line = lines[i] ; // Ignore lines over 1kb as they are unlikely to be stack frames. // Many of the regular expressions use backtracking which results in run time that increases exponentially with // input size. Huge strings can result in hangs/Denial of Service: // https://github.com/getsentry/sentry-javascript/issues/2286 if (line.length > 1024) { continue; } // https://github.com/getsentry/sentry-javascript/issues/5459 // Remove webpack (error: *) wrappers const cleanedLine = WEBPACK_ERROR_REGEXP.test(line) ? line.replace(WEBPACK_ERROR_REGEXP, '$1') : line; // https://github.com/getsentry/sentry-javascript/issues/7813 // Skip Error: lines if (cleanedLine.match(/\S*Error: /)) { continue; } for (const parser of sortedParsers) { const frame = parser(cleanedLine); if (frame) { frames.push(frame); break; } } if (frames.length >= STACKTRACE_FRAME_LIMIT + framesToPop) { break; } } return stripSentryFramesAndReverse(frames.slice(framesToPop)); }; } /** * Removes Sentry frames from the top and bottom of the stack if present and enforces a limit of max number of frames. * Assumes stack input is ordered from top to bottom and returns the reverse representation so call site of the * function that caused the crash is the last frame in the array. * @hidden */ function stripSentryFramesAndReverse(stack) { if (!stack.length) { return []; } const localStack = Array.from(stack); // If stack starts with one of our API calls, remove it (starts, meaning it's the top of the stack - aka last call) if (/sentryWrapped/.test(getLastStackFrame(localStack).function || '')) { localStack.pop(); } // Reversing in the middle of the procedure allows us to just pop the values off the stack localStack.reverse(); // 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 (STRIP_FRAME_REGEXP.test(getLastStackFrame(localStack).function || '')) { localStack.pop(); // When using synthetic events, we will have a 2 levels deep stack, as `new Error('Sentry syntheticException')` // is produced within the hub itself, making it: // // Sentry.captureException() // getCurrentHub().captureException() // // instead of just the top `Sentry` call itself. // This forces us to possibly strip an additional frame in the exact same was as above. if (STRIP_FRAME_REGEXP.test(getLastStackFrame(localStack).function || '')) { localStack.pop(); } } return localStack.slice(0, STACKTRACE_FRAME_LIMIT).map(frame => ({ ...frame, filename: frame.filename || getLastStackFrame(localStack).filename, function: frame.function || UNKNOWN_FUNCTION, })); } function getLastStackFrame(arr) { return arr[arr.length - 1] || {}; } 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; } } // We keep the handlers globally const handlers = {}; const instrumented = {}; /** Add a handler function. */ function addHandler(type, handler) { handlers[type] = handlers[type] || []; (handlers[type] ).push(handler); } /** Maybe run an instrumentation function, unless it was already called. */ function maybeInstrument(type, instrumentFn) { if (!instrumented[type]) { instrumentFn(); instrumented[type] = true; } } /** Trigger handlers for a given instrumentation type. */ function triggerHandlers(type, data) { const typeHandlers = type && handlers[type]; if (!typeHandlers) { return; } for (const handler of typeHandlers) { try { handler(data); } catch (e) { DEBUG_BUILD$1 && logger.error( `Error while triggering instrumentation handler.\nType: ${type}\nName: ${getFunctionName(handler)}\nError:`, e, ); } } } const ONE_SECOND_IN_MS = 1000; /** * A partial definition of the [Performance Web API]{@link https://developer.mozilla.org/en-US/docs/Web/API/Performance} * for accessing a high-resolution monotonic clock. */ /** * Returns a timestamp in seconds since the UNIX epoch using the Date API. * * TODO(v8): Return type should be rounded. */ function dateTimestampInSeconds() { return Date.now() / ONE_SECOND_IN_MS; } /** * Returns a wrapper around the native Performance API browser implementation, or undefined for browsers that do not * support the API. * * Wrapping the native API works around differences in behavior from different browsers. */ function createUnixTimestampInSecondsFunc() { const { performance } = GLOBAL_OBJ ; if (!performance || !performance.now) { return dateTimestampInSeconds; } // Some browser and environments don't have a timeOrigin, so we fallback to // using Date.now() to compute the starting time. const approxStartingTimeOrigin = Date.now() - performance.now(); const timeOrigin = performance.timeOrigin == undefined ? approxStartingTimeOrigin : performance.timeOrigin; // performance.now() is a monotonic clock, which means it starts at 0 when the process begins. To get the current // wall clock time (actual UNIX timestamp), we need to add the starting time origin and the current time elapsed. // // TODO: This does not account for the case where the monotonic clock that powers performance.now() drifts from the // wall clock time, which causes the returned timestamp to be inaccurate. We should investigate how to detect and // correct for this. // See: https://github.com/getsentry/sentry-javascript/issues/2590 // See: https://github.com/mdn/content/issues/4713 // See: https://dev.to/noamr/when-a-millisecond-is-not-a-millisecond-3h6 return () => { return (timeOrigin + performance.now()) / ONE_SECOND_IN_MS; }; } /** * Returns a timestamp in seconds since the UNIX epoch using either the Performance or Date APIs, depending on the * availability of the Performance API. * * BUG: Note that because of how browsers implement the Performance API, the clock might stop when the computer is * asleep. This creates a skew between `dateTimestampInSeconds` and `timestampInSeconds`. The * skew can grow to arbitrary amounts like days, weeks or months. * See https://github.com/getsentry/sentry-javascript/issues/2590. */ const timestampInSeconds = createUnixTimestampInSecondsFunc(); /** * The number of milliseconds since the UNIX epoch. This value is only usable in a browser, and only when the * performance API is available. */ (() => { // Unfortunately browsers may report an inaccurate time origin data, through either performance.timeOrigin or // performance.timing.navigationStart, which results in poor results in performance data. We only treat time origin // data as reliable if they are within a reasonable threshold of the current time. const { performance } = GLOBAL_OBJ ; if (!performance || !performance.now) { return undefined; } const threshold = 3600 * 1000; const performanceNow = performance.now(); const dateNow = Date.now(); // if timeOrigin isn't available set delta to threshold so it isn't used const timeOriginDelta = performance.timeOrigin ? Math.abs(performance.timeOrigin + performanceNow - dateNow) : threshold; const timeOriginIsReliable = timeOriginDelta < threshold; // While performance.timing.navigationStart is deprecated in favor of performance.timeOrigin, performance.timeOrigin // is not as widely supported. Namely, performance.timeOrigin is undefined in Safari as of writing. // Also as of writing, performance.timing is not available in Web Workers in mainstream browsers, so it is not always // a valid fallback. In the absence of an initial time provided by the browser, fallback to the current time from the // Date API. // eslint-disable-next-line deprecation/deprecation const navigationStart = performance.timing && performance.timing.navigationStart; const hasNavigationStart = typeof navigationStart === 'number'; // if navigationStart isn't available set delta to threshold so it isn't used const navigationStartDelta = hasNavigationStart ? Math.abs(navigationStart + performanceNow - dateNow) : threshold; const navigationStartIsReliable = navigationStartDelta < threshold; if (timeOriginIsReliable || navigationStartIsReliable) { // Use the more reliable time origin if (timeOriginDelta <= navigationStartDelta) { return performance.timeOrigin; } else { return navigationStart; } } return dateNow; })(); let _oldOnErrorHandler = null; /** * Add an instrumentation handler for when an error is captured by the global error handler. * * Use at your own risk, this might break without changelog notice, only used internally. * @hidden */ function addGlobalErrorInstrumentationHandler(handler) { const ty