diff options
Diffstat (limited to 'shared/logger/node_modules/@sentry/browser/esm/integrations')
6 files changed, 1194 insertions, 0 deletions
diff --git a/shared/logger/node_modules/@sentry/browser/esm/integrations/breadcrumbs.js b/shared/logger/node_modules/@sentry/browser/esm/integrations/breadcrumbs.js new file mode 100644 index 0000000..4117cc4 --- /dev/null +++ b/shared/logger/node_modules/@sentry/browser/esm/integrations/breadcrumbs.js @@ -0,0 +1,320 @@ +import { getCurrentHub } from '@sentry/core'; +import { addInstrumentationHandler, getEventDescription, severityLevelFromString, safeJoin, SENTRY_XHR_DATA_KEY, parseUrl, logger, htmlTreeAsString } from '@sentry/utils'; +import { WINDOW } from '../helpers.js'; + +/* eslint-disable @typescript-eslint/no-unsafe-member-access */ + +/** maxStringLength gets capped to prevent 100 breadcrumbs exceeding 1MB event payload size */ +const MAX_ALLOWED_STRING_LENGTH = 1024; + +const BREADCRUMB_INTEGRATION_ID = 'Breadcrumbs'; + +/** + * Default Breadcrumbs instrumentations + * TODO: Deprecated - with v6, this will be renamed to `Instrument` + */ +class Breadcrumbs { + /** + * @inheritDoc + */ + static __initStatic() {this.id = BREADCRUMB_INTEGRATION_ID;} + + /** + * @inheritDoc + */ + __init() {this.name = Breadcrumbs.id;} + + /** + * Options of the breadcrumbs integration. + */ + // This field is public, because we use it in the browser client to check if the `sentry` option is enabled. + + /** + * @inheritDoc + */ + constructor(options) {Breadcrumbs.prototype.__init.call(this); + this.options = { + console: true, + dom: true, + fetch: true, + history: true, + sentry: true, + xhr: true, + ...options, + }; + } + + /** + * 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('console', _consoleBreadcrumb); + } + if (this.options.dom) { + addInstrumentationHandler('dom', _domBreadcrumb(this.options.dom)); + } + if (this.options.xhr) { + addInstrumentationHandler('xhr', _xhrBreadcrumb); + } + if (this.options.fetch) { + addInstrumentationHandler('fetch', _fetchBreadcrumb); + } + if (this.options.history) { + addInstrumentationHandler('history', _historyBreadcrumb); + } + } + + /** + * Adds a breadcrumb for Sentry events or transactions if this option is enabled. + */ + addSentryBreadcrumb(event) { + if (this.options.sentry) { + getCurrentHub().addBreadcrumb( + { + category: `sentry.${event.type === 'transaction' ? 'transaction' : 'event'}`, + event_id: event.event_id, + level: event.level, + message: getEventDescription(event), + }, + { + event, + }, + ); + } + } +} Breadcrumbs.__initStatic(); + +/** + * A HOC that creaes a function that creates breadcrumbs from DOM API calls. + * This is a HOC so that we get access to dom options in the closure. + */ +function _domBreadcrumb(dom) { + function _innerDomBreadcrumb(handlerData) { + let target; + let keyAttrs = typeof dom === 'object' ? dom.serializeAttribute : undefined; + + let maxStringLength = + typeof dom === 'object' && typeof dom.maxStringLength === 'number' ? dom.maxStringLength : undefined; + if (maxStringLength && maxStringLength > MAX_ALLOWED_STRING_LENGTH) { + (typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && + logger.warn( + `\`dom.maxStringLength\` cannot exceed ${MAX_ALLOWED_STRING_LENGTH}, but a value of ${maxStringLength} was configured. Sentry will use ${MAX_ALLOWED_STRING_LENGTH} instead.`, + ); + maxStringLength = MAX_ALLOWED_STRING_LENGTH; + } + + if (typeof keyAttrs === 'string') { + keyAttrs = [keyAttrs]; + } + + // Accessing event.target can throw (see getsentry/raven-js#838, #768) + try { + const event = handlerData.event ; + target = _isEvent(event) + ? htmlTreeAsString(event.target, { keyAttrs, maxStringLength }) + : htmlTreeAsString(event, { keyAttrs, maxStringLength }); + } catch (e) { + target = '<unknown>'; + } + + if (target.length === 0) { + return; + } + + getCurrentHub().addBreadcrumb( + { + category: `ui.${handlerData.name}`, + message: target, + }, + { + event: handlerData.event, + name: handlerData.name, + global: handlerData.global, + }, + ); + } + + return _innerDomBreadcrumb; +} + +/** + * Creates breadcrumbs from console API calls + */ +function _consoleBreadcrumb(handlerData) { + // This is a hack to fix a Vue3-specific bug that causes an infinite loop of + // console warnings. This happens when a Vue template is rendered with + // an undeclared variable, which we try to stringify, ultimately causing + // Vue to issue another warning which repeats indefinitely. + // see: https://github.com/getsentry/sentry-javascript/pull/6010 + // see: https://github.com/getsentry/sentry-javascript/issues/5916 + for (let i = 0; i < handlerData.args.length; i++) { + if (handlerData.args[i] === 'ref=Ref<') { + handlerData.args[i + 1] = 'viewRef'; + break; + } + } + const breadcrumb = { + category: 'console', + data: { + arguments: handlerData.args, + logger: 'console', + }, + level: severityLevelFromString(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 XHR API calls + */ +function _xhrBreadcrumb(handlerData) { + const { startTimestamp, endTimestamp } = handlerData; + + const sentryXhrData = handlerData.xhr[SENTRY_XHR_DATA_KEY]; + + // We only capture complete, non-sentry requests + if (!startTimestamp || !endTimestamp || !sentryXhrData) { + return; + } + + const { method, url, status_code, body } = sentryXhrData; + + const data = { + method, + url, + status_code, + }; + + const hint = { + xhr: handlerData.xhr, + input: body, + startTimestamp, + endTimestamp, + }; + + getCurrentHub().addBreadcrumb( + { + category: 'xhr', + data, + type: 'http', + }, + hint, + ); +} + +/** + * Creates breadcrumbs from fetch API calls + */ +function _fetchBreadcrumb(handlerData) { + const { startTimestamp, endTimestamp } = handlerData; + + // We only capture complete fetch requests + if (!endTimestamp) { + return; + } + + if (handlerData.fetchData.url.match(/sentry_key/) && handlerData.fetchData.method === 'POST') { + // We will not create breadcrumbs for fetch requests that contain `sentry_key` (internal sentry requests) + return; + } + + if (handlerData.error) { + const data = handlerData.fetchData; + const hint = { + data: handlerData.error, + input: handlerData.args, + startTimestamp, + endTimestamp, + }; + + getCurrentHub().addBreadcrumb( + { + category: 'fetch', + data, + level: 'error', + type: 'http', + }, + hint, + ); + } else { + const data = { + ...handlerData.fetchData, + status_code: handlerData.response && handlerData.response.status, + }; + const hint = { + input: handlerData.args, + response: handlerData.response, + startTimestamp, + endTimestamp, + }; + getCurrentHub().addBreadcrumb( + { + category: 'fetch', + data, + type: 'http', + }, + hint, + ); + } +} + +/** + * Creates breadcrumbs from history API calls + */ +function _historyBreadcrumb(handlerData) { + let from = handlerData.from; + let to = handlerData.to; + const parsedLoc = parseUrl(WINDOW.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) { + to = parsedTo.relative; + } + if (parsedLoc.protocol === parsedFrom.protocol && parsedLoc.host === parsedFrom.host) { + from = parsedFrom.relative; + } + + getCurrentHub().addBreadcrumb({ + category: 'navigation', + data: { + from, + to, + }, + }); +} + +function _isEvent(event) { + return !!event && !!(event ).target; +} + +export { BREADCRUMB_INTEGRATION_ID, Breadcrumbs }; +//# sourceMappingURL=breadcrumbs.js.map diff --git a/shared/logger/node_modules/@sentry/browser/esm/integrations/dedupe.js b/shared/logger/node_modules/@sentry/browser/esm/integrations/dedupe.js new file mode 100644 index 0000000..591a552 --- /dev/null +++ b/shared/logger/node_modules/@sentry/browser/esm/integrations/dedupe.js @@ -0,0 +1,211 @@ +import { logger } from '@sentry/utils'; + +/** Deduplication filter */ +class Dedupe {constructor() { Dedupe.prototype.__init.call(this); } + /** + * @inheritDoc + */ + static __initStatic() {this.id = 'Dedupe';} + + /** + * @inheritDoc + */ + __init() {this.name = Dedupe.id;} + + /** + * @inheritDoc + */ + + /** + * @inheritDoc + */ + setupOnce(addGlobalEventProcessor, getCurrentHub) { + const eventProcessor = currentEvent => { + // We want to ignore any non-error type events, e.g. transactions or replays + // These should never be deduped, and also not be compared against as _previousEvent. + if (currentEvent.type) { + return currentEvent; + } + + const self = getCurrentHub().getIntegration(Dedupe); + if (self) { + // Juuust in case something goes wrong + try { + if (_shouldDropEvent(currentEvent, self._previousEvent)) { + (typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && logger.warn('Event dropped due to being a duplicate of previously captured event.'); + return null; + } + } catch (_oO) { + return (self._previousEvent = currentEvent); + } + + return (self._previousEvent = currentEvent); + } + return currentEvent; + }; + + eventProcessor.id = this.name; + addGlobalEventProcessor(eventProcessor); + } +} Dedupe.__initStatic(); + +/** JSDoc */ +function _shouldDropEvent(currentEvent, previousEvent) { + if (!previousEvent) { + return false; + } + + if (_isSameMessageEvent(currentEvent, previousEvent)) { + return true; + } + + if (_isSameExceptionEvent(currentEvent, previousEvent)) { + return true; + } + + return false; +} + +/** JSDoc */ +function _isSameMessageEvent(currentEvent, previousEvent) { + const currentMessage = currentEvent.message; + const previousMessage = previousEvent.message; + + // If neither event has a message property, they were both exceptions, so bail out + if (!currentMessage && !previousMessage) { + return false; + } + + // If only one event has a stacktrace, but not the other one, they are not the same + if ((currentMessage && !previousMessage) || (!currentMessage && previousMessage)) { + return false; + } + + if (currentMessage !== previousMessage) { + return false; + } + + if (!_isSameFingerprint(currentEvent, previousEvent)) { + return false; + } + + if (!_isSameStacktrace(currentEvent, previousEvent)) { + return false; + } + + return true; +} + +/** JSDoc */ +function _isSameExceptionEvent(currentEvent, previousEvent) { + const previousException = _getExceptionFromEvent(previousEvent); + const currentException = _getExceptionFromEvent(currentEvent); + + if (!previousException || !currentException) { + return false; + } + + if (previousException.type !== currentException.type || previousException.value !== currentException.value) { + return false; + } + + if (!_isSameFingerprint(currentEvent, previousEvent)) { + return false; + } + + if (!_isSameStacktrace(currentEvent, previousEvent)) { + return false; + } + + return true; +} + +/** JSDoc */ +function _isSameStacktrace(currentEvent, previousEvent) { + let currentFrames = _getFramesFromEvent(currentEvent); + let previousFrames = _getFramesFromEvent(previousEvent); + + // If neither event has a stacktrace, they are assumed to be the same + if (!currentFrames && !previousFrames) { + return true; + } + + // If only one event has a stacktrace, but not the other one, they are not the same + if ((currentFrames && !previousFrames) || (!currentFrames && previousFrames)) { + return false; + } + + currentFrames = currentFrames ; + previousFrames = previousFrames ; + + // If number of frames differ, they are not the same + if (previousFrames.length !== currentFrames.length) { + return false; + } + + // Otherwise, compare the two + for (let i = 0; i < previousFrames.length; i++) { + const frameA = previousFrames[i]; + const frameB = currentFrames[i]; + + if ( + frameA.filename !== frameB.filename || + frameA.lineno !== frameB.lineno || + frameA.colno !== frameB.colno || + frameA.function !== frameB.function + ) { + return false; + } + } + + return true; +} + +/** JSDoc */ +function _isSameFingerprint(currentEvent, previousEvent) { + let currentFingerprint = currentEvent.fingerprint; + let previousFingerprint = previousEvent.fingerprint; + + // If neither event has a fingerprint, they are assumed to be the same + if (!currentFingerprint && !previousFingerprint) { + return true; + } + + // If only one event has a fingerprint, but not the other one, they are not the same + if ((currentFingerprint && !previousFingerprint) || (!currentFingerprint && previousFingerprint)) { + return false; + } + + currentFingerprint = currentFingerprint ; + previousFingerprint = previousFingerprint ; + + // Otherwise, compare the two + try { + return !!(currentFingerprint.join('') === previousFingerprint.join('')); + } catch (_oO) { + return false; + } +} + +/** JSDoc */ +function _getExceptionFromEvent(event) { + return event.exception && event.exception.values && event.exception.values[0]; +} + +/** JSDoc */ +function _getFramesFromEvent(event) { + const exception = event.exception; + + if (exception) { + try { + // @ts-ignore Object could be undefined + return exception.values[0].stacktrace.frames; + } catch (_oO) { + return undefined; + } + } + return undefined; +} + +export { Dedupe }; +//# sourceMappingURL=dedupe.js.map diff --git a/shared/logger/node_modules/@sentry/browser/esm/integrations/globalhandlers.js b/shared/logger/node_modules/@sentry/browser/esm/integrations/globalhandlers.js new file mode 100644 index 0000000..65c343c --- /dev/null +++ b/shared/logger/node_modules/@sentry/browser/esm/integrations/globalhandlers.js @@ -0,0 +1,248 @@ +import { getCurrentHub } from '@sentry/core'; +import { addInstrumentationHandler, isString, isPrimitive, isErrorEvent, getLocationHref, logger, addExceptionMechanism } from '@sentry/utils'; +import { eventFromUnknownInput } from '../eventbuilder.js'; +import { shouldIgnoreOnError } from '../helpers.js'; + +/* eslint-disable @typescript-eslint/no-unsafe-member-access */ + +/** Global handlers */ +class GlobalHandlers { + /** + * @inheritDoc + */ + static __initStatic() {this.id = 'GlobalHandlers';} + + /** + * @inheritDoc + */ + __init() {this.name = GlobalHandlers.id;} + + /** JSDoc */ + + /** + * Stores references functions to installing handlers. Will set to undefined + * after they have been run so that they are not used twice. + */ + __init2() {this._installFunc = { + onerror: _installGlobalOnErrorHandler, + onunhandledrejection: _installGlobalOnUnhandledRejectionHandler, + };} + + /** JSDoc */ + constructor(options) {GlobalHandlers.prototype.__init.call(this);GlobalHandlers.prototype.__init2.call(this); + this._options = { + onerror: true, + onunhandledrejection: true, + ...options, + }; + } + /** + * @inheritDoc + */ + setupOnce() { + Error.stackTraceLimit = 50; + const options = this._options; + + // We can disable guard-for-in as we construct the options object above + do checks against + // `this._installFunc` for the property. + // eslint-disable-next-line guard-for-in + for (const key in options) { + const installFunc = this._installFunc[key ]; + if (installFunc && options[key ]) { + globalHandlerLog(key); + installFunc(); + this._installFunc[key ] = undefined; + } + } + } +} GlobalHandlers.__initStatic(); + +/** JSDoc */ +function _installGlobalOnErrorHandler() { + addInstrumentationHandler( + 'error', + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (data) => { + const [hub, stackParser, attachStacktrace] = getHubAndOptions(); + if (!hub.getIntegration(GlobalHandlers)) { + return; + } + const { msg, url, line, column, error } = data; + if (shouldIgnoreOnError() || (error && error.__sentry_own_request__)) { + return; + } + + const event = + error === undefined && isString(msg) + ? _eventFromIncompleteOnError(msg, url, line, column) + : _enhanceEventWithInitialFrame( + eventFromUnknownInput(stackParser, error || msg, undefined, attachStacktrace, false), + url, + line, + column, + ); + + event.level = 'error'; + + addMechanismAndCapture(hub, error, event, 'onerror'); + }, + ); +} + +/** JSDoc */ +function _installGlobalOnUnhandledRejectionHandler() { + addInstrumentationHandler( + 'unhandledrejection', + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (e) => { + const [hub, stackParser, attachStacktrace] = getHubAndOptions(); + if (!hub.getIntegration(GlobalHandlers)) { + return; + } + 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 + } + + if (shouldIgnoreOnError() || (error && error.__sentry_own_request__)) { + return true; + } + + const event = isPrimitive(error) + ? _eventFromRejectionWithPrimitive(error) + : eventFromUnknownInput(stackParser, error, undefined, attachStacktrace, true); + + event.level = 'error'; + + addMechanismAndCapture(hub, error, event, 'onunhandledrejection'); + return; + }, + ); +} + +/** + * Create an event from a promise rejection where the `reason` is a primitive. + * + * @param reason: The `reason` property of the promise rejection + * @returns An Event object with an appropriate `exception` value + */ +function _eventFromRejectionWithPrimitive(reason) { + return { + exception: { + values: [ + { + type: 'UnhandledRejection', + // String() is needed because the Primitive type includes symbols (which can't be automatically stringified) + value: `Non-Error promise rejection captured with value: ${String(reason)}`, + }, + ], + }, + }; +} + +/** + * This function creates a stack from an old, error-less onerror handler. + */ +// eslint-disable-next-line @typescript-eslint/no-explicit-any +function _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 = 'Error'; + + const groups = message.match(ERROR_TYPES_RE); + if (groups) { + name = groups[1]; + message = groups[2]; + } + + const event = { + exception: { + values: [ + { + type: name, + value: message, + }, + ], + }, + }; + + return _enhanceEventWithInitialFrame(event, url, line, column); +} + +/** JSDoc */ +// eslint-disable-next-line @typescript-eslint/no-explicit-any +function _enhanceEventWithInitialFrame(event, url, line, column) { + // event.exception + const e = (event.exception = event.exception || {}); + // event.exception.values + const ev = (e.values = e.values || []); + // event.exception.values[0] + const ev0 = (ev[0] = ev[0] || {}); + // event.exception.values[0].stacktrace + const ev0s = (ev0.stacktrace = ev0.stacktrace || {}); + // event.exception.values[0].stacktrace.frames + const ev0sf = (ev0s.frames = ev0s.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(); + + // event.exception.values[0].stacktrace.frames + if (ev0sf.length === 0) { + ev0sf.push({ + colno, + filename, + function: '?', + in_app: true, + lineno, + }); + } + + return event; +} + +function globalHandlerLog(type) { + (typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && logger.log(`Global Handler attached: ${type}`); +} + +function addMechanismAndCapture(hub, error, event, type) { + addExceptionMechanism(event, { + handled: false, + type, + }); + hub.captureEvent(event, { + originalException: error, + }); +} + +function getHubAndOptions() { + const hub = getCurrentHub(); + const client = hub.getClient(); + const options = (client && client.getOptions()) || { + stackParser: () => [], + attachStacktrace: false, + }; + return [hub, options.stackParser, options.attachStacktrace]; +} + +export { GlobalHandlers }; +//# sourceMappingURL=globalhandlers.js.map diff --git a/shared/logger/node_modules/@sentry/browser/esm/integrations/httpcontext.js b/shared/logger/node_modules/@sentry/browser/esm/integrations/httpcontext.js new file mode 100644 index 0000000..014a182 --- /dev/null +++ b/shared/logger/node_modules/@sentry/browser/esm/integrations/httpcontext.js @@ -0,0 +1,47 @@ +import { addGlobalEventProcessor, getCurrentHub } from '@sentry/core'; +import { WINDOW } from '../helpers.js'; + +/** HttpContext integration collects information about HTTP request headers */ +class HttpContext {constructor() { HttpContext.prototype.__init.call(this); } + /** + * @inheritDoc + */ + static __initStatic() {this.id = 'HttpContext';} + + /** + * @inheritDoc + */ + __init() {this.name = HttpContext.id;} + + /** + * @inheritDoc + */ + setupOnce() { + addGlobalEventProcessor((event) => { + if (getCurrentHub().getIntegration(HttpContext)) { + // if none of the information we want exists, don't bother + if (!WINDOW.navigator && !WINDOW.location && !WINDOW.document) { + return event; + } + + // grab as much info as exists and add it to the event + const url = (event.request && event.request.url) || (WINDOW.location && WINDOW.location.href); + const { referrer } = WINDOW.document || {}; + const { userAgent } = WINDOW.navigator || {}; + + const headers = { + ...(event.request && event.request.headers), + ...(referrer && { Referer: referrer }), + ...(userAgent && { 'User-Agent': userAgent }), + }; + const request = { ...event.request, ...(url && { url }), headers }; + + return { ...event, request }; + } + return event; + }); + } +} HttpContext.__initStatic(); + +export { HttpContext }; +//# sourceMappingURL=httpcontext.js.map diff --git a/shared/logger/node_modules/@sentry/browser/esm/integrations/linkederrors.js b/shared/logger/node_modules/@sentry/browser/esm/integrations/linkederrors.js new file mode 100644 index 0000000..d44a5e9 --- /dev/null +++ b/shared/logger/node_modules/@sentry/browser/esm/integrations/linkederrors.js @@ -0,0 +1,87 @@ +import { getCurrentHub, addGlobalEventProcessor } from '@sentry/core'; +import { isInstanceOf } from '@sentry/utils'; +import { exceptionFromError } from '../eventbuilder.js'; + +const DEFAULT_KEY = 'cause'; +const DEFAULT_LIMIT = 5; + +/** Adds SDK info to an event. */ +class LinkedErrors { + /** + * @inheritDoc + */ + static __initStatic() {this.id = 'LinkedErrors';} + + /** + * @inheritDoc + */ + __init() {this.name = LinkedErrors.id;} + + /** + * @inheritDoc + */ + + /** + * @inheritDoc + */ + + /** + * @inheritDoc + */ + constructor(options = {}) {LinkedErrors.prototype.__init.call(this); + this._key = options.key || DEFAULT_KEY; + this._limit = options.limit || DEFAULT_LIMIT; + } + + /** + * @inheritDoc + */ + setupOnce() { + const client = getCurrentHub().getClient(); + if (!client) { + return; + } + addGlobalEventProcessor((event, hint) => { + const self = getCurrentHub().getIntegration(LinkedErrors); + return self ? _handler(client.getOptions().stackParser, self._key, self._limit, event, hint) : event; + }); + } +} LinkedErrors.__initStatic(); + +/** + * @inheritDoc + */ +function _handler( + parser, + key, + limit, + event, + hint, +) { + if (!event.exception || !event.exception.values || !hint || !isInstanceOf(hint.originalException, Error)) { + return event; + } + const linkedErrors = _walkErrorTree(parser, limit, hint.originalException , key); + event.exception.values = [...linkedErrors, ...event.exception.values]; + return event; +} + +/** + * JSDOC + */ +function _walkErrorTree( + parser, + limit, + error, + key, + stack = [], +) { + if (!isInstanceOf(error[key], Error) || stack.length + 1 >= limit) { + return stack; + } + const exception = exceptionFromError(parser, error[key]); + return _walkErrorTree(parser, limit, error[key], key, [exception, ...stack]); +} + +export { LinkedErrors, _handler, _walkErrorTree }; +//# sourceMappingURL=linkederrors.js.map diff --git a/shared/logger/node_modules/@sentry/browser/esm/integrations/trycatch.js b/shared/logger/node_modules/@sentry/browser/esm/integrations/trycatch.js new file mode 100644 index 0000000..69e112f --- /dev/null +++ b/shared/logger/node_modules/@sentry/browser/esm/integrations/trycatch.js @@ -0,0 +1,281 @@ +import { fill, getFunctionName, getOriginalFunction } from '@sentry/utils'; +import { WINDOW, wrap } from '../helpers.js'; + +const DEFAULT_EVENT_TARGET = [ + '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', +]; + +/** Wrap timer functions and event targets to catch errors and provide better meta data */ +class TryCatch { + /** + * @inheritDoc + */ + static __initStatic() {this.id = 'TryCatch';} + + /** + * @inheritDoc + */ + __init() {this.name = TryCatch.id;} + + /** JSDoc */ + + /** + * @inheritDoc + */ + constructor(options) {TryCatch.prototype.__init.call(this); + this._options = { + XMLHttpRequest: true, + eventTarget: true, + requestAnimationFrame: true, + setInterval: true, + setTimeout: true, + ...options, + }; + } + + /** + * Wrap timer functions and event targets to catch errors + * and provide better metadata. + */ + setupOnce() { + if (this._options.setTimeout) { + fill(WINDOW, 'setTimeout', _wrapTimeFunction); + } + + if (this._options.setInterval) { + fill(WINDOW, 'setInterval', _wrapTimeFunction); + } + + if (this._options.requestAnimationFrame) { + fill(WINDOW, 'requestAnimationFrame', _wrapRAF); + } + + if (this._options.XMLHttpRequest && 'XMLHttpRequest' in WINDOW) { + fill(XMLHttpRequest.prototype, 'send', _wrapXHR); + } + + const eventTargetOption = this._options.eventTarget; + if (eventTargetOption) { + const eventTarget = Array.isArray(eventTargetOption) ? eventTargetOption : DEFAULT_EVENT_TARGET; + eventTarget.forEach(_wrapEventTarget); + } + } +} TryCatch.__initStatic(); + +/** JSDoc */ +function _wrapTimeFunction(original) { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + 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 */ +// eslint-disable-next-line @typescript-eslint/no-explicit-any +function _wrapRAF(original) { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + return function ( callback) { + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + return original.apply(this, [ + wrap(callback, { + mechanism: { + data: { + function: 'requestAnimationFrame', + handler: getFunctionName(original), + }, + handled: true, + type: 'instrument', + }, + }), + ]); + }; +} + +/** JSDoc */ +function _wrapXHR(originalSend) { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + return function ( ...args) { + // eslint-disable-next-line @typescript-eslint/no-this-alias + const xhr = this; + const xmlHttpRequestProps = ['onload', 'onerror', 'onprogress', 'onreadystatechange']; + + xmlHttpRequestProps.forEach(prop => { + if (prop in xhr && typeof xhr[prop] === 'function') { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + 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 + const originalFunction = getOriginalFunction(original); + if (originalFunction) { + wrapOptions.mechanism.data.handler = getFunctionName(originalFunction); + } + + // Otherwise wrap directly + return wrap(original, wrapOptions); + }); + } + }); + + return originalSend.apply(this, args); + }; +} + +/** JSDoc */ +function _wrapEventTarget(target) { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const globalObject = WINDOW ; + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + const proto = globalObject[target] && globalObject[target].prototype; + + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, no-prototype-builtins + if (!proto || !proto.hasOwnProperty || !proto.hasOwnProperty('addEventListener')) { + return; + } + + fill(proto, 'addEventListener', function (original) + + { + return function ( + // eslint-disable-next-line @typescript-eslint/no-explicit-any + + eventName, + fn, + options, + ) { + try { + if (typeof fn.handleEvent === 'function') { + // ESlint disable explanation: + // First, it is generally safe to call `wrap` with an unbound function. Furthermore, using `.bind()` would + // introduce a bug here, because bind returns a new function that doesn't have our + // flags(like __sentry_original__) attached. `wrap` checks for those flags to avoid unnecessary wrapping. + // Without those flags, every call to addEventListener wraps the function again, causing a memory leak. + // eslint-disable-next-line @typescript-eslint/unbound-method + fn.handleEvent = wrap(fn.handleEvent, { + 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.apply(this, [ + eventName, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + wrap(fn , { + mechanism: { + data: { + function: 'addEventListener', + handler: getFunctionName(fn), + target, + }, + handled: true, + type: 'instrument', + }, + }), + options, + ]); + }; + }); + + fill( + proto, + 'removeEventListener', + function ( + originalRemoveEventListener, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + ) { + return function ( + // eslint-disable-next-line @typescript-eslint/no-explicit-any + + eventName, + fn, + options, + ) { + /** + * There are 2 possible scenarios here: + * + * 1. Someone passes a callback, which was attached prior to Sentry initialization, or by using unmodified + * method, eg. `document.addEventListener.call(el, name, handler). In this case, we treat this function + * as a pass-through, and call original `removeEventListener` with it. + * + * 2. Someone passes a callback, which was attached after Sentry was initialized, which means that it was using + * our wrapped version of `addEventListener`, which internally calls `wrap` helper. + * This helper "wraps" whole callback inside a try/catch statement, and attached appropriate metadata to it, + * in order for us to make a distinction between wrapped/non-wrapped functions possible. + * If a function was wrapped, it has additional property of `__sentry_wrapped__`, holding the handler. + * + * When someone adds a handler prior to initialization, and then do it again, but after, + * then we have to detach both of them. Otherwise, if we'd detach only wrapped one, it'd be impossible + * to get rid of the initial handler and it'd stick there forever. + */ + const wrappedEventHandler = fn ; + try { + const originalEventHandler = wrappedEventHandler && wrappedEventHandler.__sentry_wrapped__; + if (originalEventHandler) { + originalRemoveEventListener.call(this, eventName, originalEventHandler, options); + } + } catch (e) { + // ignore, accessing __sentry_wrapped__ will throw in some Selenium environments + } + return originalRemoveEventListener.call(this, eventName, wrappedEventHandler, options); + }; + }, + ); +} + +export { TryCatch }; +//# sourceMappingURL=trycatch.js.map |
