mirror of
https://github.com/rxliuli/apps.apple.com.git
synced 2025-11-10 00:30:32 +00:00
init commit
This commit is contained in:
139
shared/logger/node_modules/@sentry/browser/esm/client.js
generated
vendored
Normal file
139
shared/logger/node_modules/@sentry/browser/esm/client.js
generated
vendored
Normal file
@@ -0,0 +1,139 @@
|
||||
import { BaseClient, SDK_VERSION } from '@sentry/core';
|
||||
import { getSDKSource, logger, createClientReportEnvelope, dsnToString } from '@sentry/utils';
|
||||
import { eventFromException, eventFromMessage } from './eventbuilder.js';
|
||||
import { WINDOW } from './helpers.js';
|
||||
import { BREADCRUMB_INTEGRATION_ID } from './integrations/breadcrumbs.js';
|
||||
import { createUserFeedbackEnvelope } from './userfeedback.js';
|
||||
|
||||
/**
|
||||
* Configuration options for the Sentry Browser SDK.
|
||||
* @see @sentry/types Options for more information.
|
||||
*/
|
||||
|
||||
/**
|
||||
* The Sentry Browser SDK Client.
|
||||
*
|
||||
* @see BrowserOptions for documentation on configuration options.
|
||||
* @see SentryClient for usage documentation.
|
||||
*/
|
||||
class BrowserClient extends BaseClient {
|
||||
/**
|
||||
* Creates a new Browser SDK instance.
|
||||
*
|
||||
* @param options Configuration options for this SDK.
|
||||
*/
|
||||
constructor(options) {
|
||||
const sdkSource = WINDOW.SENTRY_SDK_SOURCE || getSDKSource();
|
||||
|
||||
options._metadata = options._metadata || {};
|
||||
options._metadata.sdk = options._metadata.sdk || {
|
||||
name: 'sentry.javascript.browser',
|
||||
packages: [
|
||||
{
|
||||
name: `${sdkSource}:@sentry/browser`,
|
||||
version: SDK_VERSION,
|
||||
},
|
||||
],
|
||||
version: SDK_VERSION,
|
||||
};
|
||||
|
||||
super(options);
|
||||
|
||||
if (options.sendClientReports && WINDOW.document) {
|
||||
WINDOW.document.addEventListener('visibilitychange', () => {
|
||||
if (WINDOW.document.visibilityState === 'hidden') {
|
||||
this._flushOutcomes();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
eventFromException(exception, hint) {
|
||||
return eventFromException(this._options.stackParser, exception, hint, this._options.attachStacktrace);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
eventFromMessage(
|
||||
message,
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
level = 'info',
|
||||
hint,
|
||||
) {
|
||||
return eventFromMessage(this._options.stackParser, message, level, hint, this._options.attachStacktrace);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
sendEvent(event, hint) {
|
||||
// We only want to add the sentry event breadcrumb when the user has the breadcrumb integration installed and
|
||||
// activated its `sentry` option.
|
||||
// We also do not want to use the `Breadcrumbs` class here directly, because we do not want it to be included in
|
||||
// bundles, if it is not used by the SDK.
|
||||
// This all sadly is a bit ugly, but we currently don't have a "pre-send" hook on the integrations so we do it this
|
||||
// way for now.
|
||||
const breadcrumbIntegration = this.getIntegrationById(BREADCRUMB_INTEGRATION_ID) ;
|
||||
// We check for definedness of `addSentryBreadcrumb` in case users provided their own integration with id
|
||||
// "Breadcrumbs" that does not have this function.
|
||||
if (breadcrumbIntegration && breadcrumbIntegration.addSentryBreadcrumb) {
|
||||
breadcrumbIntegration.addSentryBreadcrumb(event);
|
||||
}
|
||||
|
||||
super.sendEvent(event, hint);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends user feedback to Sentry.
|
||||
*/
|
||||
captureUserFeedback(feedback) {
|
||||
if (!this._isEnabled()) {
|
||||
(typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && logger.warn('SDK not enabled, will not capture user feedback.');
|
||||
return;
|
||||
}
|
||||
|
||||
const envelope = createUserFeedbackEnvelope(feedback, {
|
||||
metadata: this.getSdkMetadata(),
|
||||
dsn: this.getDsn(),
|
||||
tunnel: this.getOptions().tunnel,
|
||||
});
|
||||
void this._sendEnvelope(envelope);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
_prepareEvent(event, hint, scope) {
|
||||
event.platform = event.platform || 'javascript';
|
||||
return super._prepareEvent(event, hint, scope);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends client reports as an envelope.
|
||||
*/
|
||||
_flushOutcomes() {
|
||||
const outcomes = this._clearOutcomes();
|
||||
|
||||
if (outcomes.length === 0) {
|
||||
(typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && logger.log('No outcomes to send');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this._dsn) {
|
||||
(typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && logger.log('No dsn provided, will not send outcomes');
|
||||
return;
|
||||
}
|
||||
|
||||
(typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && logger.log('Sending outcomes:', outcomes);
|
||||
|
||||
const envelope = createClientReportEnvelope(outcomes, this._options.tunnel && dsnToString(this._dsn));
|
||||
void this._sendEnvelope(envelope);
|
||||
}
|
||||
}
|
||||
|
||||
export { BrowserClient };
|
||||
//# sourceMappingURL=client.js.map
|
||||
304
shared/logger/node_modules/@sentry/browser/esm/eventbuilder.js
generated
vendored
Normal file
304
shared/logger/node_modules/@sentry/browser/esm/eventbuilder.js
generated
vendored
Normal file
@@ -0,0 +1,304 @@
|
||||
import { getCurrentHub } from '@sentry/core';
|
||||
import { addExceptionMechanism, resolvedSyncPromise, isErrorEvent, isDOMError, isDOMException, addExceptionTypeValue, isError, isPlainObject, isEvent, normalizeToSize, extractExceptionKeysForMessage } from '@sentry/utils';
|
||||
|
||||
/**
|
||||
* This function creates an exception from a JavaScript Error
|
||||
*/
|
||||
function exceptionFromError(stackParser, ex) {
|
||||
// Get the frames first since Opera can lose the stack if we touch anything else first
|
||||
const frames = parseStackFrames(stackParser, ex);
|
||||
|
||||
const exception = {
|
||||
type: ex && ex.name,
|
||||
value: extractMessage(ex),
|
||||
};
|
||||
|
||||
if (frames.length) {
|
||||
exception.stacktrace = { frames };
|
||||
}
|
||||
|
||||
if (exception.type === undefined && exception.value === '') {
|
||||
exception.value = 'Unrecoverable error caught';
|
||||
}
|
||||
|
||||
return exception;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hidden
|
||||
*/
|
||||
function eventFromPlainObject(
|
||||
stackParser,
|
||||
exception,
|
||||
syntheticException,
|
||||
isUnhandledRejection,
|
||||
) {
|
||||
const hub = getCurrentHub();
|
||||
const client = hub.getClient();
|
||||
const normalizeDepth = client && client.getOptions().normalizeDepth;
|
||||
|
||||
const event = {
|
||||
exception: {
|
||||
values: [
|
||||
{
|
||||
type: isEvent(exception) ? exception.constructor.name : isUnhandledRejection ? 'UnhandledRejection' : 'Error',
|
||||
value: getNonErrorObjectExceptionValue(exception, { isUnhandledRejection }),
|
||||
},
|
||||
],
|
||||
},
|
||||
extra: {
|
||||
__serialized__: normalizeToSize(exception, normalizeDepth),
|
||||
},
|
||||
};
|
||||
|
||||
if (syntheticException) {
|
||||
const frames = parseStackFrames(stackParser, syntheticException);
|
||||
if (frames.length) {
|
||||
// event.exception.values[0] has been set above
|
||||
(event.exception ).values[0].stacktrace = { frames };
|
||||
}
|
||||
}
|
||||
|
||||
return event;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hidden
|
||||
*/
|
||||
function eventFromError(stackParser, ex) {
|
||||
return {
|
||||
exception: {
|
||||
values: [exceptionFromError(stackParser, ex)],
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/** Parses stack frames from an error */
|
||||
function parseStackFrames(
|
||||
stackParser,
|
||||
ex,
|
||||
) {
|
||||
// Access and store the stacktrace property before doing ANYTHING
|
||||
// else to it because Opera is not very good at providing it
|
||||
// reliably in other circumstances.
|
||||
const stacktrace = ex.stacktrace || ex.stack || '';
|
||||
|
||||
const popSize = getPopSize(ex);
|
||||
|
||||
try {
|
||||
return stackParser(stacktrace, popSize);
|
||||
} catch (e) {
|
||||
// no-empty
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
// Based on our own mapping pattern - https://github.com/getsentry/sentry/blob/9f08305e09866c8bd6d0c24f5b0aabdd7dd6c59c/src/sentry/lang/javascript/errormapping.py#L83-L108
|
||||
const reactMinifiedRegexp = /Minified React error #\d+;/i;
|
||||
|
||||
function getPopSize(ex) {
|
||||
if (ex) {
|
||||
if (typeof ex.framesToPop === 'number') {
|
||||
return ex.framesToPop;
|
||||
}
|
||||
|
||||
if (reactMinifiedRegexp.test(ex.message)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* There are cases where stacktrace.message is an Event object
|
||||
* https://github.com/getsentry/sentry-javascript/issues/1949
|
||||
* In this specific case we try to extract stacktrace.message.error.message
|
||||
*/
|
||||
function extractMessage(ex) {
|
||||
const message = ex && ex.message;
|
||||
if (!message) {
|
||||
return 'No error message';
|
||||
}
|
||||
if (message.error && typeof message.error.message === 'string') {
|
||||
return message.error.message;
|
||||
}
|
||||
return message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an {@link Event} from all inputs to `captureException` and non-primitive inputs to `captureMessage`.
|
||||
* @hidden
|
||||
*/
|
||||
function eventFromException(
|
||||
stackParser,
|
||||
exception,
|
||||
hint,
|
||||
attachStacktrace,
|
||||
) {
|
||||
const syntheticException = (hint && hint.syntheticException) || undefined;
|
||||
const event = eventFromUnknownInput(stackParser, exception, syntheticException, attachStacktrace);
|
||||
addExceptionMechanism(event); // defaults to { type: 'generic', handled: true }
|
||||
event.level = 'error';
|
||||
if (hint && hint.event_id) {
|
||||
event.event_id = hint.event_id;
|
||||
}
|
||||
return resolvedSyncPromise(event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds and Event from a Message
|
||||
* @hidden
|
||||
*/
|
||||
function eventFromMessage(
|
||||
stackParser,
|
||||
message,
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
level = 'info',
|
||||
hint,
|
||||
attachStacktrace,
|
||||
) {
|
||||
const syntheticException = (hint && hint.syntheticException) || undefined;
|
||||
const event = eventFromString(stackParser, message, syntheticException, attachStacktrace);
|
||||
event.level = level;
|
||||
if (hint && hint.event_id) {
|
||||
event.event_id = hint.event_id;
|
||||
}
|
||||
return resolvedSyncPromise(event);
|
||||
}
|
||||
|
||||
/**
|
||||
* @hidden
|
||||
*/
|
||||
function eventFromUnknownInput(
|
||||
stackParser,
|
||||
exception,
|
||||
syntheticException,
|
||||
attachStacktrace,
|
||||
isUnhandledRejection,
|
||||
) {
|
||||
let event;
|
||||
|
||||
if (isErrorEvent(exception ) && (exception ).error) {
|
||||
// If it is an ErrorEvent with `error` property, extract it to get actual Error
|
||||
const errorEvent = exception ;
|
||||
return eventFromError(stackParser, errorEvent.error );
|
||||
}
|
||||
|
||||
// If it is a `DOMError` (which is a legacy API, but still supported in some browsers) then we just extract the name
|
||||
// and message, as it doesn't provide anything else. According to the spec, all `DOMExceptions` should also be
|
||||
// `Error`s, but that's not the case in IE11, so in that case we treat it the same as we do a `DOMError`.
|
||||
//
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/DOMError
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/DOMException
|
||||
// https://webidl.spec.whatwg.org/#es-DOMException-specialness
|
||||
if (isDOMError(exception) || isDOMException(exception )) {
|
||||
const domException = exception ;
|
||||
|
||||
if ('stack' in (exception )) {
|
||||
event = eventFromError(stackParser, exception );
|
||||
} else {
|
||||
const name = domException.name || (isDOMError(domException) ? 'DOMError' : 'DOMException');
|
||||
const message = domException.message ? `${name}: ${domException.message}` : name;
|
||||
event = eventFromString(stackParser, message, syntheticException, attachStacktrace);
|
||||
addExceptionTypeValue(event, message);
|
||||
}
|
||||
if ('code' in domException) {
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
event.tags = { ...event.tags, 'DOMException.code': `${domException.code}` };
|
||||
}
|
||||
|
||||
return event;
|
||||
}
|
||||
if (isError(exception)) {
|
||||
// we have a real Error object, do nothing
|
||||
return eventFromError(stackParser, exception);
|
||||
}
|
||||
if (isPlainObject(exception) || isEvent(exception)) {
|
||||
// If it's a plain object or an instance of `Event` (the built-in JS kind, not this SDK's `Event` type), serialize
|
||||
// it manually. This will allow us to group events based on top-level keys which is much better than creating a new
|
||||
// group on any key/value change.
|
||||
const objectException = exception ;
|
||||
event = eventFromPlainObject(stackParser, objectException, syntheticException, isUnhandledRejection);
|
||||
addExceptionMechanism(event, {
|
||||
synthetic: true,
|
||||
});
|
||||
return event;
|
||||
}
|
||||
|
||||
// If none of previous checks were valid, then it means that it's not:
|
||||
// - an instance of DOMError
|
||||
// - an instance of DOMException
|
||||
// - an instance of Event
|
||||
// - an instance of Error
|
||||
// - a valid ErrorEvent (one with an error property)
|
||||
// - a plain Object
|
||||
//
|
||||
// So bail out and capture it as a simple message:
|
||||
event = eventFromString(stackParser, exception , syntheticException, attachStacktrace);
|
||||
addExceptionTypeValue(event, `${exception}`, undefined);
|
||||
addExceptionMechanism(event, {
|
||||
synthetic: true,
|
||||
});
|
||||
|
||||
return event;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hidden
|
||||
*/
|
||||
function eventFromString(
|
||||
stackParser,
|
||||
input,
|
||||
syntheticException,
|
||||
attachStacktrace,
|
||||
) {
|
||||
const event = {
|
||||
message: input,
|
||||
};
|
||||
|
||||
if (attachStacktrace && syntheticException) {
|
||||
const frames = parseStackFrames(stackParser, syntheticException);
|
||||
if (frames.length) {
|
||||
event.exception = {
|
||||
values: [{ value: input, stacktrace: { frames } }],
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return event;
|
||||
}
|
||||
|
||||
function getNonErrorObjectExceptionValue(
|
||||
exception,
|
||||
{ isUnhandledRejection },
|
||||
) {
|
||||
const keys = extractExceptionKeysForMessage(exception);
|
||||
const captureType = isUnhandledRejection ? 'promise rejection' : 'exception';
|
||||
|
||||
// Some ErrorEvent instances do not have an `error` property, which is why they are not handled before
|
||||
// We still want to try to get a decent message for these cases
|
||||
if (isErrorEvent(exception)) {
|
||||
return `Event \`ErrorEvent\` captured as ${captureType} with message \`${exception.message}\``;
|
||||
}
|
||||
|
||||
if (isEvent(exception)) {
|
||||
const className = getObjectClassName(exception);
|
||||
return `Event \`${className}\` (type=${exception.type}) captured as ${captureType}`;
|
||||
}
|
||||
|
||||
return `Object captured as ${captureType} with keys: ${keys}`;
|
||||
}
|
||||
|
||||
function getObjectClassName(obj) {
|
||||
try {
|
||||
const prototype = Object.getPrototypeOf(obj);
|
||||
return prototype ? prototype.constructor.name : undefined;
|
||||
} catch (e) {
|
||||
// ignore errors here
|
||||
}
|
||||
}
|
||||
|
||||
export { eventFromError, eventFromException, eventFromMessage, eventFromPlainObject, eventFromString, eventFromUnknownInput, exceptionFromError, parseStackFrames };
|
||||
//# sourceMappingURL=eventbuilder.js.map
|
||||
154
shared/logger/node_modules/@sentry/browser/esm/helpers.js
generated
vendored
Normal file
154
shared/logger/node_modules/@sentry/browser/esm/helpers.js
generated
vendored
Normal file
@@ -0,0 +1,154 @@
|
||||
import { withScope, captureException } from '@sentry/core';
|
||||
import { GLOBAL_OBJ, getOriginalFunction, markFunctionWrapped, addNonEnumerableProperty, addExceptionTypeValue, addExceptionMechanism } from '@sentry/utils';
|
||||
|
||||
const WINDOW = GLOBAL_OBJ ;
|
||||
|
||||
let ignoreOnError = 0;
|
||||
|
||||
/**
|
||||
* @hidden
|
||||
*/
|
||||
function shouldIgnoreOnError() {
|
||||
return ignoreOnError > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hidden
|
||||
*/
|
||||
function ignoreNextOnError() {
|
||||
// onerror should trigger before setTimeout
|
||||
ignoreOnError++;
|
||||
setTimeout(() => {
|
||||
ignoreOnError--;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Instruments the given function and sends an event to Sentry every time the
|
||||
* function throws an exception.
|
||||
*
|
||||
* @param fn A function to wrap. It is generally safe to pass an unbound function, because the returned wrapper always
|
||||
* has a correct `this` context.
|
||||
* @returns The wrapped function.
|
||||
* @hidden
|
||||
*/
|
||||
function wrap(
|
||||
fn,
|
||||
options
|
||||
|
||||
= {},
|
||||
before,
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
) {
|
||||
// for future readers what this does is wrap a function and then create
|
||||
// a bi-directional wrapping between them.
|
||||
//
|
||||
// example: wrapped = wrap(original);
|
||||
// original.__sentry_wrapped__ -> wrapped
|
||||
// wrapped.__sentry_original__ -> original
|
||||
|
||||
if (typeof fn !== 'function') {
|
||||
return fn;
|
||||
}
|
||||
|
||||
try {
|
||||
// if we're dealing with a function that was previously wrapped, return
|
||||
// the original wrapper.
|
||||
const wrapper = fn.__sentry_wrapped__;
|
||||
if (wrapper) {
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
// We don't wanna wrap it twice
|
||||
if (getOriginalFunction(fn)) {
|
||||
return fn;
|
||||
}
|
||||
} catch (e) {
|
||||
// Just accessing custom props in some Selenium environments
|
||||
// can cause a "Permission denied" exception (see raven-js#495).
|
||||
// Bail on wrapping and return the function as-is (defers to window.onerror).
|
||||
return fn;
|
||||
}
|
||||
|
||||
/* eslint-disable prefer-rest-params */
|
||||
// It is important that `sentryWrapped` is not an arrow function to preserve the context of `this`
|
||||
const sentryWrapped = function () {
|
||||
const args = Array.prototype.slice.call(arguments);
|
||||
|
||||
try {
|
||||
if (before && typeof before === 'function') {
|
||||
before.apply(this, arguments);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-member-access
|
||||
const wrappedArguments = args.map((arg) => wrap(arg, options));
|
||||
|
||||
// Attempt to invoke user-land function
|
||||
// NOTE: If you are a Sentry user, and you are seeing this stack frame, it
|
||||
// means the sentry.javascript SDK caught an error invoking your application code. This
|
||||
// is expected behavior and NOT indicative of a bug with sentry.javascript.
|
||||
return fn.apply(this, wrappedArguments);
|
||||
} catch (ex) {
|
||||
ignoreNextOnError();
|
||||
|
||||
withScope((scope) => {
|
||||
scope.addEventProcessor((event) => {
|
||||
if (options.mechanism) {
|
||||
addExceptionTypeValue(event, undefined, undefined);
|
||||
addExceptionMechanism(event, options.mechanism);
|
||||
}
|
||||
|
||||
event.extra = {
|
||||
...event.extra,
|
||||
arguments: args,
|
||||
};
|
||||
|
||||
return event;
|
||||
});
|
||||
|
||||
captureException(ex);
|
||||
});
|
||||
|
||||
throw ex;
|
||||
}
|
||||
};
|
||||
/* eslint-enable prefer-rest-params */
|
||||
|
||||
// Accessing some objects may throw
|
||||
// ref: https://github.com/getsentry/sentry-javascript/issues/1168
|
||||
try {
|
||||
for (const property in fn) {
|
||||
if (Object.prototype.hasOwnProperty.call(fn, property)) {
|
||||
sentryWrapped[property] = fn[property];
|
||||
}
|
||||
}
|
||||
} catch (_oO) {} // eslint-disable-line no-empty
|
||||
|
||||
// Signal that this function has been wrapped/filled already
|
||||
// for both debugging and to prevent it to being wrapped/filled twice
|
||||
markFunctionWrapped(sentryWrapped, fn);
|
||||
|
||||
addNonEnumerableProperty(fn, '__sentry_wrapped__', sentryWrapped);
|
||||
|
||||
// Restore original function name (not all browsers allow that)
|
||||
try {
|
||||
const descriptor = Object.getOwnPropertyDescriptor(sentryWrapped, 'name') ;
|
||||
if (descriptor.configurable) {
|
||||
Object.defineProperty(sentryWrapped, 'name', {
|
||||
get() {
|
||||
return fn.name;
|
||||
},
|
||||
});
|
||||
}
|
||||
// eslint-disable-next-line no-empty
|
||||
} catch (_oO) {}
|
||||
|
||||
return sentryWrapped;
|
||||
}
|
||||
|
||||
/**
|
||||
* All properties the report dialog supports
|
||||
*/
|
||||
|
||||
export { WINDOW, ignoreNextOnError, shouldIgnoreOnError, wrap };
|
||||
//# sourceMappingURL=helpers.js.map
|
||||
39
shared/logger/node_modules/@sentry/browser/esm/index.js
generated
vendored
Normal file
39
shared/logger/node_modules/@sentry/browser/esm/index.js
generated
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
import { Integrations } from '@sentry/core';
|
||||
export { FunctionToString, Hub, InboundFilters, SDK_VERSION, Scope, addBreadcrumb, addGlobalEventProcessor, addTracingExtensions, captureEvent, captureException, captureMessage, configureScope, createTransport, extractTraceparentData, getActiveTransaction, getCurrentHub, getHubFromCarrier, makeMain, makeMultiplexedTransport, setContext, setExtra, setExtras, setTag, setTags, setUser, spanStatusfromHttpCode, startTransaction, trace, withScope } from '@sentry/core';
|
||||
import { WINDOW } from './helpers.js';
|
||||
export { WINDOW } from './helpers.js';
|
||||
export { BrowserClient } from './client.js';
|
||||
export { makeFetchTransport } from './transports/fetch.js';
|
||||
export { makeXHRTransport } from './transports/xhr.js';
|
||||
export { chromeStackLineParser, defaultStackLineParsers, defaultStackParser, geckoStackLineParser, opera10StackLineParser, opera11StackLineParser, winjsStackLineParser } from './stack-parsers.js';
|
||||
export { eventFromException, eventFromMessage } from './eventbuilder.js';
|
||||
export { createUserFeedbackEnvelope } from './userfeedback.js';
|
||||
export { captureUserFeedback, close, defaultIntegrations, flush, forceLoad, init, lastEventId, onLoad, showReportDialog, wrap } from './sdk.js';
|
||||
import * as index from './integrations/index.js';
|
||||
export { Replay } from '@sentry/replay';
|
||||
export { BrowserTracing, defaultRequestInstrumentationOptions, instrumentOutgoingRequests } from '@sentry-internal/tracing';
|
||||
export { makeBrowserOfflineTransport } from './transports/offline.js';
|
||||
export { onProfilingStartRouteTransaction } from './profiling/hubextensions.js';
|
||||
export { BrowserProfilingIntegration } from './profiling/integration.js';
|
||||
export { GlobalHandlers } from './integrations/globalhandlers.js';
|
||||
export { TryCatch } from './integrations/trycatch.js';
|
||||
export { Breadcrumbs } from './integrations/breadcrumbs.js';
|
||||
export { LinkedErrors } from './integrations/linkederrors.js';
|
||||
export { HttpContext } from './integrations/httpcontext.js';
|
||||
export { Dedupe } from './integrations/dedupe.js';
|
||||
|
||||
let windowIntegrations = {};
|
||||
|
||||
// This block is needed to add compatibility with the integrations packages when used with a CDN
|
||||
if (WINDOW.Sentry && WINDOW.Sentry.Integrations) {
|
||||
windowIntegrations = WINDOW.Sentry.Integrations;
|
||||
}
|
||||
|
||||
const INTEGRATIONS = {
|
||||
...windowIntegrations,
|
||||
...Integrations,
|
||||
...index,
|
||||
};
|
||||
|
||||
export { INTEGRATIONS as Integrations };
|
||||
//# sourceMappingURL=index.js.map
|
||||
320
shared/logger/node_modules/@sentry/browser/esm/integrations/breadcrumbs.js
generated
vendored
Normal file
320
shared/logger/node_modules/@sentry/browser/esm/integrations/breadcrumbs.js
generated
vendored
Normal file
@@ -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
|
||||
211
shared/logger/node_modules/@sentry/browser/esm/integrations/dedupe.js
generated
vendored
Normal file
211
shared/logger/node_modules/@sentry/browser/esm/integrations/dedupe.js
generated
vendored
Normal file
@@ -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
|
||||
248
shared/logger/node_modules/@sentry/browser/esm/integrations/globalhandlers.js
generated
vendored
Normal file
248
shared/logger/node_modules/@sentry/browser/esm/integrations/globalhandlers.js
generated
vendored
Normal file
@@ -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
|
||||
47
shared/logger/node_modules/@sentry/browser/esm/integrations/httpcontext.js
generated
vendored
Normal file
47
shared/logger/node_modules/@sentry/browser/esm/integrations/httpcontext.js
generated
vendored
Normal file
@@ -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
|
||||
87
shared/logger/node_modules/@sentry/browser/esm/integrations/linkederrors.js
generated
vendored
Normal file
87
shared/logger/node_modules/@sentry/browser/esm/integrations/linkederrors.js
generated
vendored
Normal file
@@ -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
|
||||
281
shared/logger/node_modules/@sentry/browser/esm/integrations/trycatch.js
generated
vendored
Normal file
281
shared/logger/node_modules/@sentry/browser/esm/integrations/trycatch.js
generated
vendored
Normal file
@@ -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
|
||||
240
shared/logger/node_modules/@sentry/browser/esm/profiling/hubextensions.js
generated
vendored
Normal file
240
shared/logger/node_modules/@sentry/browser/esm/profiling/hubextensions.js
generated
vendored
Normal file
@@ -0,0 +1,240 @@
|
||||
import { getCurrentHub } from '@sentry/core';
|
||||
import { logger, uuid4 } from '@sentry/utils';
|
||||
import { WINDOW } from '../helpers.js';
|
||||
import { isValidSampleRate, addProfileToMap } from './utils.js';
|
||||
|
||||
/* eslint-disable complexity */
|
||||
|
||||
const MAX_PROFILE_DURATION_MS = 30000;
|
||||
// Keep a flag value to avoid re-initializing the profiler constructor. If it fails
|
||||
// once, it will always fail and this allows us to early return.
|
||||
let PROFILING_CONSTRUCTOR_FAILED = false;
|
||||
|
||||
/**
|
||||
* Check if profiler constructor is available.
|
||||
* @param maybeProfiler
|
||||
*/
|
||||
function isJSProfilerSupported(maybeProfiler) {
|
||||
return typeof maybeProfiler === 'function';
|
||||
}
|
||||
|
||||
/**
|
||||
* Safety wrapper for startTransaction for the unlikely case that transaction starts before tracing is imported -
|
||||
* if that happens we want to avoid throwing an error from profiling code.
|
||||
* see https://github.com/getsentry/sentry-javascript/issues/4731.
|
||||
*
|
||||
* @experimental
|
||||
*/
|
||||
function onProfilingStartRouteTransaction(transaction) {
|
||||
if (!transaction) {
|
||||
if ((typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__)) {
|
||||
logger.log('[Profiling] Transaction is undefined, skipping profiling');
|
||||
}
|
||||
return transaction;
|
||||
}
|
||||
|
||||
return wrapTransactionWithProfiling(transaction);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps startTransaction and stopTransaction with profiling related logic.
|
||||
* startProfiling is called after the call to startTransaction in order to avoid our own code from
|
||||
* being profiled. Because of that same reason, stopProfiling is called before the call to stopTransaction.
|
||||
*/
|
||||
function wrapTransactionWithProfiling(transaction) {
|
||||
// Feature support check first
|
||||
const JSProfilerConstructor = WINDOW.Profiler;
|
||||
|
||||
if (!isJSProfilerSupported(JSProfilerConstructor)) {
|
||||
if ((typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__)) {
|
||||
logger.log(
|
||||
'[Profiling] Profiling is not supported by this browser, Profiler interface missing on window object.',
|
||||
);
|
||||
}
|
||||
return transaction;
|
||||
}
|
||||
|
||||
// If constructor failed once, it will always fail, so we can early return.
|
||||
if (PROFILING_CONSTRUCTOR_FAILED) {
|
||||
if ((typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__)) {
|
||||
logger.log('[Profiling] Profiling has been disabled for the duration of the current user session.');
|
||||
}
|
||||
return transaction;
|
||||
}
|
||||
|
||||
const client = getCurrentHub().getClient();
|
||||
const options = client && client.getOptions();
|
||||
if (!options) {
|
||||
(typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && logger.log('[Profiling] Profiling disabled, no options found.');
|
||||
return transaction;
|
||||
}
|
||||
|
||||
// @ts-ignore profilesSampleRate is not part of the browser options yet
|
||||
const profilesSampleRate = options.profilesSampleRate;
|
||||
|
||||
// Since this is coming from the user (or from a function provided by the user), who knows what we might get. (The
|
||||
// only valid values are booleans or numbers between 0 and 1.)
|
||||
if (!isValidSampleRate(profilesSampleRate)) {
|
||||
(typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && logger.warn('[Profiling] Discarding profile because of invalid sample rate.');
|
||||
return transaction;
|
||||
}
|
||||
|
||||
// if the function returned 0 (or false), or if `profileSampleRate` is 0, it's a sign the profile should be dropped
|
||||
if (!profilesSampleRate) {
|
||||
(typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) &&
|
||||
logger.log(
|
||||
'[Profiling] Discarding profile because a negative sampling decision was inherited or profileSampleRate is set to 0',
|
||||
);
|
||||
return transaction;
|
||||
}
|
||||
|
||||
// Now we roll the dice. Math.random is inclusive of 0, but not of 1, so strict < is safe here. In case sampleRate is
|
||||
// a boolean, the < comparison will cause it to be automatically cast to 1 if it's true and 0 if it's false.
|
||||
const sampled = profilesSampleRate === true ? true : Math.random() < profilesSampleRate;
|
||||
// Check if we should sample this profile
|
||||
if (!sampled) {
|
||||
(typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) &&
|
||||
logger.log(
|
||||
`[Profiling] Discarding profile because it's not included in the random sample (sampling rate = ${Number(
|
||||
profilesSampleRate,
|
||||
)})`,
|
||||
);
|
||||
return transaction;
|
||||
}
|
||||
|
||||
// From initial testing, it seems that the minimum value for sampleInterval is 10ms.
|
||||
const samplingIntervalMS = 10;
|
||||
// Start the profiler
|
||||
const maxSamples = Math.floor(MAX_PROFILE_DURATION_MS / samplingIntervalMS);
|
||||
let profiler;
|
||||
|
||||
// Attempt to initialize the profiler constructor, if it fails, we disable profiling for the current user session.
|
||||
// This is likely due to a missing 'Document-Policy': 'js-profiling' header. We do not want to throw an error if this happens
|
||||
// as we risk breaking the user's application, so just disable profiling and log an error.
|
||||
try {
|
||||
profiler = new JSProfilerConstructor({ sampleInterval: samplingIntervalMS, maxBufferSize: maxSamples });
|
||||
} catch (e) {
|
||||
if ((typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__)) {
|
||||
logger.log(
|
||||
"[Profiling] Failed to initialize the Profiling constructor, this is likely due to a missing 'Document-Policy': 'js-profiling' header.",
|
||||
);
|
||||
logger.log('[Profiling] Disabling profiling for current user session.');
|
||||
}
|
||||
PROFILING_CONSTRUCTOR_FAILED = true;
|
||||
}
|
||||
|
||||
// We failed to construct the profiler, fallback to original transaction - there is no need to log
|
||||
// anything as we already did that in the try/catch block.
|
||||
if (!profiler) {
|
||||
return transaction;
|
||||
}
|
||||
|
||||
if ((typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__)) {
|
||||
logger.log(`[Profiling] started profiling transaction: ${transaction.name || transaction.description}`);
|
||||
}
|
||||
|
||||
// We create "unique" transaction names to avoid concurrent transactions with same names
|
||||
// from being ignored by the profiler. From here on, only this transaction name should be used when
|
||||
// calling the profiler methods. Note: we log the original name to the user to avoid confusion.
|
||||
const profileId = uuid4();
|
||||
|
||||
/**
|
||||
* Idempotent handler for profile stop
|
||||
*/
|
||||
async function onProfileHandler() {
|
||||
// Check if the profile exists and return it the behavior has to be idempotent as users may call transaction.finish multiple times.
|
||||
if (!transaction) {
|
||||
return null;
|
||||
}
|
||||
// Satisfy the type checker, but profiler will always be defined here.
|
||||
if (!profiler) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// This is temporary - we will use the collected span data to evaluate
|
||||
// if deferring txn.finish until profiler resolves is a viable approach.
|
||||
const stopProfilerSpan = transaction.startChild({ description: 'profiler.stop', op: 'profiler' });
|
||||
|
||||
return profiler
|
||||
.stop()
|
||||
.then((p) => {
|
||||
stopProfilerSpan.finish();
|
||||
|
||||
if (maxDurationTimeoutID) {
|
||||
WINDOW.clearTimeout(maxDurationTimeoutID);
|
||||
maxDurationTimeoutID = undefined;
|
||||
}
|
||||
|
||||
if ((typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__)) {
|
||||
logger.log(`[Profiling] stopped profiling of transaction: ${transaction.name || transaction.description}`);
|
||||
}
|
||||
|
||||
// In case of an overlapping transaction, stopProfiling may return null and silently ignore the overlapping profile.
|
||||
if (!p) {
|
||||
if ((typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__)) {
|
||||
logger.log(
|
||||
`[Profiling] profiler returned null profile for: ${transaction.name || transaction.description}`,
|
||||
'this may indicate an overlapping transaction or a call to stopProfiling with a profile title that was never started',
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
addProfileToMap(profileId, p);
|
||||
return null;
|
||||
})
|
||||
.catch(error => {
|
||||
stopProfilerSpan.finish();
|
||||
if ((typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__)) {
|
||||
logger.log('[Profiling] error while stopping profiler:', error);
|
||||
}
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
// Enqueue a timeout to prevent profiles from running over max duration.
|
||||
let maxDurationTimeoutID = WINDOW.setTimeout(() => {
|
||||
if ((typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__)) {
|
||||
logger.log(
|
||||
'[Profiling] max profile duration elapsed, stopping profiling for:',
|
||||
transaction.name || transaction.description,
|
||||
);
|
||||
}
|
||||
// If the timeout exceeds, we want to stop profiling, but not finish the transaction
|
||||
void onProfileHandler();
|
||||
}, MAX_PROFILE_DURATION_MS);
|
||||
|
||||
// We need to reference the original finish call to avoid creating an infinite loop
|
||||
const originalFinish = transaction.finish.bind(transaction);
|
||||
|
||||
/**
|
||||
* Wraps startTransaction and stopTransaction with profiling related logic.
|
||||
* startProfiling is called after the call to startTransaction in order to avoid our own code from
|
||||
* being profiled. Because of that same reason, stopProfiling is called before the call to stopTransaction.
|
||||
*/
|
||||
function profilingWrappedTransactionFinish() {
|
||||
if (!transaction) {
|
||||
return originalFinish();
|
||||
}
|
||||
// onProfileHandler should always return the same profile even if this is called multiple times.
|
||||
// Always call onProfileHandler to ensure stopProfiling is called and the timeout is cleared.
|
||||
void onProfileHandler().then(
|
||||
() => {
|
||||
transaction.setContext('profile', { profile_id: profileId });
|
||||
originalFinish();
|
||||
},
|
||||
() => {
|
||||
// If onProfileHandler fails, we still want to call the original finish method.
|
||||
originalFinish();
|
||||
},
|
||||
);
|
||||
|
||||
return transaction;
|
||||
}
|
||||
|
||||
transaction.finish = profilingWrappedTransactionFinish;
|
||||
return transaction;
|
||||
}
|
||||
|
||||
export { MAX_PROFILE_DURATION_MS, onProfilingStartRouteTransaction, wrapTransactionWithProfiling };
|
||||
//# sourceMappingURL=hubextensions.js.map
|
||||
81
shared/logger/node_modules/@sentry/browser/esm/profiling/integration.js
generated
vendored
Normal file
81
shared/logger/node_modules/@sentry/browser/esm/profiling/integration.js
generated
vendored
Normal file
@@ -0,0 +1,81 @@
|
||||
import { logger } from '@sentry/utils';
|
||||
import { wrapTransactionWithProfiling } from './hubextensions.js';
|
||||
import { PROFILE_MAP, findProfiledTransactionsFromEnvelope, createProfilingEvent, addProfilesToEnvelope } from './utils.js';
|
||||
|
||||
/**
|
||||
* Browser profiling integration. Stores any event that has contexts["profile"]["profile_id"]
|
||||
* This exists because we do not want to await async profiler.stop calls as transaction.finish is called
|
||||
* in a synchronous context. Instead, we handle sending the profile async from the promise callback and
|
||||
* rely on being able to pull the event from the cache when we need to construct the envelope. This makes the
|
||||
* integration less reliable as we might be dropping profiles when the cache is full.
|
||||
*
|
||||
* @experimental
|
||||
*/
|
||||
class BrowserProfilingIntegration {constructor() { BrowserProfilingIntegration.prototype.__init.call(this);BrowserProfilingIntegration.prototype.__init2.call(this); }
|
||||
__init() {this.name = 'BrowserProfilingIntegration';}
|
||||
__init2() {this.getCurrentHub = undefined;}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
setupOnce(addGlobalEventProcessor, getCurrentHub) {
|
||||
this.getCurrentHub = getCurrentHub;
|
||||
const client = this.getCurrentHub().getClient() ;
|
||||
|
||||
if (client && typeof client.on === 'function') {
|
||||
client.on('startTransaction', (transaction) => {
|
||||
wrapTransactionWithProfiling(transaction);
|
||||
});
|
||||
|
||||
client.on('beforeEnvelope', (envelope) => {
|
||||
// if not profiles are in queue, there is nothing to add to the envelope.
|
||||
if (!PROFILE_MAP['size']) {
|
||||
return;
|
||||
}
|
||||
|
||||
const profiledTransactionEvents = findProfiledTransactionsFromEnvelope(envelope);
|
||||
if (!profiledTransactionEvents.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
const profilesToAddToEnvelope = [];
|
||||
|
||||
for (const profiledTransaction of profiledTransactionEvents) {
|
||||
const context = profiledTransaction && profiledTransaction.contexts;
|
||||
const profile_id = context && context['profile'] && (context['profile']['profile_id'] );
|
||||
|
||||
if (!profile_id) {
|
||||
(typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) &&
|
||||
logger.log('[Profiling] cannot find profile for a transaction without a profile context');
|
||||
continue;
|
||||
}
|
||||
|
||||
// Remove the profile from the transaction context before sending, relay will take care of the rest.
|
||||
if (context && context['profile']) {
|
||||
delete context.profile;
|
||||
}
|
||||
|
||||
const profile = PROFILE_MAP.get(profile_id);
|
||||
if (!profile) {
|
||||
(typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && logger.log(`[Profiling] Could not retrieve profile for transaction: ${profile_id}`);
|
||||
continue;
|
||||
}
|
||||
|
||||
PROFILE_MAP.delete(profile_id);
|
||||
const profileEvent = createProfilingEvent(profile_id, profile, profiledTransaction );
|
||||
|
||||
if (profileEvent) {
|
||||
profilesToAddToEnvelope.push(profileEvent);
|
||||
}
|
||||
}
|
||||
|
||||
addProfilesToEnvelope(envelope, profilesToAddToEnvelope);
|
||||
});
|
||||
} else {
|
||||
logger.warn('[Profiling] Client does not support hooks, profiling will be disabled');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export { BrowserProfilingIntegration };
|
||||
//# sourceMappingURL=integration.js.map
|
||||
438
shared/logger/node_modules/@sentry/browser/esm/profiling/utils.js
generated
vendored
Normal file
438
shared/logger/node_modules/@sentry/browser/esm/profiling/utils.js
generated
vendored
Normal file
@@ -0,0 +1,438 @@
|
||||
import { DEFAULT_ENVIRONMENT, getCurrentHub } from '@sentry/core';
|
||||
import { forEachEnvelopeItem, logger, uuid4, GLOBAL_OBJ } from '@sentry/utils';
|
||||
import { WINDOW } from '../helpers.js';
|
||||
|
||||
/* eslint-disable max-lines */
|
||||
|
||||
const MS_TO_NS = 1e6;
|
||||
// Use 0 as main thread id which is identical to threadId in node:worker_threads
|
||||
// where main logs 0 and workers seem to log in increments of 1
|
||||
const THREAD_ID_STRING = String(0);
|
||||
const THREAD_NAME = 'main';
|
||||
|
||||
// Machine properties (eval only once)
|
||||
let OS_PLATFORM = '';
|
||||
let OS_PLATFORM_VERSION = '';
|
||||
let OS_ARCH = '';
|
||||
let OS_BROWSER = (WINDOW.navigator && WINDOW.navigator.userAgent) || '';
|
||||
let OS_MODEL = '';
|
||||
const OS_LOCALE =
|
||||
(WINDOW.navigator && WINDOW.navigator.language) ||
|
||||
(WINDOW.navigator && WINDOW.navigator.languages && WINDOW.navigator.languages[0]) ||
|
||||
'';
|
||||
|
||||
function isUserAgentData(data) {
|
||||
return typeof data === 'object' && data !== null && 'getHighEntropyValues' in data;
|
||||
}
|
||||
|
||||
// @ts-ignore userAgentData is not part of the navigator interface yet
|
||||
const userAgentData = WINDOW.navigator && WINDOW.navigator.userAgentData;
|
||||
|
||||
if (isUserAgentData(userAgentData)) {
|
||||
userAgentData
|
||||
.getHighEntropyValues(['architecture', 'model', 'platform', 'platformVersion', 'fullVersionList'])
|
||||
.then((ua) => {
|
||||
OS_PLATFORM = ua.platform || '';
|
||||
OS_ARCH = ua.architecture || '';
|
||||
OS_MODEL = ua.model || '';
|
||||
OS_PLATFORM_VERSION = ua.platformVersion || '';
|
||||
|
||||
if (ua.fullVersionList && ua.fullVersionList.length > 0) {
|
||||
const firstUa = ua.fullVersionList[ua.fullVersionList.length - 1];
|
||||
OS_BROWSER = `${firstUa.brand} ${firstUa.version}`;
|
||||
}
|
||||
})
|
||||
.catch(e => void e);
|
||||
}
|
||||
|
||||
function isProcessedJSSelfProfile(profile) {
|
||||
return !('thread_metadata' in profile);
|
||||
}
|
||||
|
||||
// Enriches the profile with threadId of the current thread.
|
||||
// This is done in node as we seem to not be able to get the info from C native code.
|
||||
/**
|
||||
*
|
||||
*/
|
||||
function enrichWithThreadInformation(profile) {
|
||||
if (!isProcessedJSSelfProfile(profile)) {
|
||||
return profile;
|
||||
}
|
||||
|
||||
return convertJSSelfProfileToSampledFormat(profile);
|
||||
}
|
||||
|
||||
// Profile is marked as optional because it is deleted from the metadata
|
||||
// by the integration before the event is processed by other integrations.
|
||||
|
||||
function getTraceId(event) {
|
||||
const traceId = event && event.contexts && event.contexts['trace'] && event.contexts['trace']['trace_id'];
|
||||
// Log a warning if the profile has an invalid traceId (should be uuidv4).
|
||||
// All profiles and transactions are rejected if this is the case and we want to
|
||||
// warn users that this is happening if they enable debug flag
|
||||
if (typeof traceId === 'string' && traceId.length !== 32) {
|
||||
if ((typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__)) {
|
||||
logger.log(`[Profiling] Invalid traceId: ${traceId} on profiled event`);
|
||||
}
|
||||
}
|
||||
if (typeof traceId !== 'string') {
|
||||
return '';
|
||||
}
|
||||
|
||||
return traceId;
|
||||
}
|
||||
/**
|
||||
* Creates a profiling event envelope from a Sentry event. If profile does not pass
|
||||
* validation, returns null.
|
||||
* @param event
|
||||
* @param dsn
|
||||
* @param metadata
|
||||
* @param tunnel
|
||||
* @returns {EventEnvelope | null}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Creates a profiling event envelope from a Sentry event.
|
||||
*/
|
||||
function createProfilePayload(
|
||||
event,
|
||||
processedProfile,
|
||||
profile_id,
|
||||
) {
|
||||
if (event.type !== 'transaction') {
|
||||
// createProfilingEventEnvelope should only be called for transactions,
|
||||
// we type guard this behavior with isProfiledTransactionEvent.
|
||||
throw new TypeError('Profiling events may only be attached to transactions, this should never occur.');
|
||||
}
|
||||
|
||||
if (processedProfile === undefined || processedProfile === null) {
|
||||
throw new TypeError(
|
||||
`Cannot construct profiling event envelope without a valid profile. Got ${processedProfile} instead.`,
|
||||
);
|
||||
}
|
||||
|
||||
const traceId = getTraceId(event);
|
||||
const enrichedThreadProfile = enrichWithThreadInformation(processedProfile);
|
||||
const transactionStartMs = typeof event.start_timestamp === 'number' ? event.start_timestamp * 1000 : Date.now();
|
||||
const transactionEndMs = typeof event.timestamp === 'number' ? event.timestamp * 1000 : Date.now();
|
||||
|
||||
const profile = {
|
||||
event_id: profile_id,
|
||||
timestamp: new Date(transactionStartMs).toISOString(),
|
||||
platform: 'javascript',
|
||||
version: '1',
|
||||
release: event.release || '',
|
||||
environment: event.environment || DEFAULT_ENVIRONMENT,
|
||||
runtime: {
|
||||
name: 'javascript',
|
||||
version: WINDOW.navigator.userAgent,
|
||||
},
|
||||
os: {
|
||||
name: OS_PLATFORM,
|
||||
version: OS_PLATFORM_VERSION,
|
||||
build_number: OS_BROWSER,
|
||||
},
|
||||
device: {
|
||||
locale: OS_LOCALE,
|
||||
model: OS_MODEL,
|
||||
manufacturer: OS_BROWSER,
|
||||
architecture: OS_ARCH,
|
||||
is_emulator: false,
|
||||
},
|
||||
debug_meta: {
|
||||
images: applyDebugMetadata(processedProfile.resources),
|
||||
},
|
||||
profile: enrichedThreadProfile,
|
||||
transactions: [
|
||||
{
|
||||
name: event.transaction || '',
|
||||
id: event.event_id || uuid4(),
|
||||
trace_id: traceId,
|
||||
active_thread_id: THREAD_ID_STRING,
|
||||
relative_start_ns: '0',
|
||||
relative_end_ns: ((transactionEndMs - transactionStartMs) * 1e6).toFixed(0),
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
return profile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a JSSelfProfile to a our sampled format.
|
||||
* Does not currently perform stack indexing.
|
||||
*/
|
||||
function convertJSSelfProfileToSampledFormat(input) {
|
||||
let EMPTY_STACK_ID = undefined;
|
||||
let STACK_ID = 0;
|
||||
|
||||
// Initialize the profile that we will fill with data
|
||||
const profile = {
|
||||
samples: [],
|
||||
stacks: [],
|
||||
frames: [],
|
||||
thread_metadata: {
|
||||
[THREAD_ID_STRING]: { name: THREAD_NAME },
|
||||
},
|
||||
};
|
||||
|
||||
if (!input.samples.length) {
|
||||
return profile;
|
||||
}
|
||||
|
||||
// We assert samples.length > 0 above and timestamp should always be present
|
||||
const start = input.samples[0].timestamp;
|
||||
|
||||
for (let i = 0; i < input.samples.length; i++) {
|
||||
const jsSample = input.samples[i];
|
||||
|
||||
// If sample has no stack, add an empty sample
|
||||
if (jsSample.stackId === undefined) {
|
||||
if (EMPTY_STACK_ID === undefined) {
|
||||
EMPTY_STACK_ID = STACK_ID;
|
||||
profile.stacks[EMPTY_STACK_ID] = [];
|
||||
STACK_ID++;
|
||||
}
|
||||
|
||||
profile['samples'][i] = {
|
||||
// convert ms timestamp to ns
|
||||
elapsed_since_start_ns: ((jsSample.timestamp - start) * MS_TO_NS).toFixed(0),
|
||||
stack_id: EMPTY_STACK_ID,
|
||||
thread_id: THREAD_ID_STRING,
|
||||
};
|
||||
continue;
|
||||
}
|
||||
|
||||
let stackTop = input.stacks[jsSample.stackId];
|
||||
|
||||
// Functions in top->down order (root is last)
|
||||
// We follow the stackTop.parentId trail and collect each visited frameId
|
||||
const stack = [];
|
||||
|
||||
while (stackTop) {
|
||||
stack.push(stackTop.frameId);
|
||||
|
||||
const frame = input.frames[stackTop.frameId];
|
||||
|
||||
// If our frame has not been indexed yet, index it
|
||||
if (profile.frames[stackTop.frameId] === undefined) {
|
||||
profile.frames[stackTop.frameId] = {
|
||||
function: frame.name,
|
||||
file: frame.resourceId ? input.resources[frame.resourceId] : undefined,
|
||||
line: frame.line,
|
||||
column: frame.column,
|
||||
};
|
||||
}
|
||||
|
||||
stackTop = stackTop.parentId === undefined ? undefined : input.stacks[stackTop.parentId];
|
||||
}
|
||||
|
||||
const sample = {
|
||||
// convert ms timestamp to ns
|
||||
elapsed_since_start_ns: ((jsSample.timestamp - start) * MS_TO_NS).toFixed(0),
|
||||
stack_id: STACK_ID,
|
||||
thread_id: THREAD_ID_STRING,
|
||||
};
|
||||
|
||||
profile['stacks'][STACK_ID] = stack;
|
||||
profile['samples'][i] = sample;
|
||||
STACK_ID++;
|
||||
}
|
||||
|
||||
return profile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds items to envelope if they are not already present - mutates the envelope.
|
||||
* @param envelope
|
||||
*/
|
||||
function addProfilesToEnvelope(envelope, profiles) {
|
||||
if (!profiles.length) {
|
||||
return envelope;
|
||||
}
|
||||
|
||||
for (const profile of profiles) {
|
||||
// @ts-ignore untyped envelope
|
||||
envelope[1].push([{ type: 'profile' }, profile]);
|
||||
}
|
||||
return envelope;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds transactions with profile_id context in the envelope
|
||||
* @param envelope
|
||||
* @returns
|
||||
*/
|
||||
function findProfiledTransactionsFromEnvelope(envelope) {
|
||||
const events = [];
|
||||
|
||||
forEachEnvelopeItem(envelope, (item, type) => {
|
||||
if (type !== 'transaction') {
|
||||
return;
|
||||
}
|
||||
|
||||
for (let j = 1; j < item.length; j++) {
|
||||
const event = item[j] ;
|
||||
|
||||
if (event && event.contexts && event.contexts['profile'] && event.contexts['profile']['profile_id']) {
|
||||
events.push(item[j] );
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return events;
|
||||
}
|
||||
|
||||
const debugIdStackParserCache = new WeakMap();
|
||||
/**
|
||||
* Applies debug meta data to an event from a list of paths to resources (sourcemaps)
|
||||
*/
|
||||
function applyDebugMetadata(resource_paths) {
|
||||
const debugIdMap = GLOBAL_OBJ._sentryDebugIds;
|
||||
|
||||
if (!debugIdMap) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const hub = getCurrentHub();
|
||||
if (!hub) {
|
||||
return [];
|
||||
}
|
||||
const client = hub.getClient();
|
||||
if (!client) {
|
||||
return [];
|
||||
}
|
||||
const options = client.getOptions();
|
||||
if (!options) {
|
||||
return [];
|
||||
}
|
||||
const stackParser = options.stackParser;
|
||||
if (!stackParser) {
|
||||
return [];
|
||||
}
|
||||
|
||||
let debugIdStackFramesCache;
|
||||
const cachedDebugIdStackFrameCache = debugIdStackParserCache.get(stackParser);
|
||||
if (cachedDebugIdStackFrameCache) {
|
||||
debugIdStackFramesCache = cachedDebugIdStackFrameCache;
|
||||
} else {
|
||||
debugIdStackFramesCache = new Map();
|
||||
debugIdStackParserCache.set(stackParser, debugIdStackFramesCache);
|
||||
}
|
||||
|
||||
// Build a map of filename -> debug_id
|
||||
const filenameDebugIdMap = Object.keys(debugIdMap).reduce((acc, debugIdStackTrace) => {
|
||||
let parsedStack;
|
||||
|
||||
const cachedParsedStack = debugIdStackFramesCache.get(debugIdStackTrace);
|
||||
if (cachedParsedStack) {
|
||||
parsedStack = cachedParsedStack;
|
||||
} else {
|
||||
parsedStack = stackParser(debugIdStackTrace);
|
||||
debugIdStackFramesCache.set(debugIdStackTrace, parsedStack);
|
||||
}
|
||||
|
||||
for (let i = parsedStack.length - 1; i >= 0; i--) {
|
||||
const stackFrame = parsedStack[i];
|
||||
const file = stackFrame && stackFrame.filename;
|
||||
|
||||
if (stackFrame && file) {
|
||||
acc[file] = debugIdMap[debugIdStackTrace] ;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
const images = [];
|
||||
for (const path of resource_paths) {
|
||||
if (path && filenameDebugIdMap[path]) {
|
||||
images.push({
|
||||
type: 'sourcemap',
|
||||
code_file: path,
|
||||
debug_id: filenameDebugIdMap[path] ,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return images;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the given sample rate to make sure it is valid type and value (a boolean, or a number between 0 and 1).
|
||||
*/
|
||||
function isValidSampleRate(rate) {
|
||||
// we need to check NaN explicitly because it's of type 'number' and therefore wouldn't get caught by this typecheck
|
||||
if ((typeof rate !== 'number' && typeof rate !== 'boolean') || (typeof rate === 'number' && isNaN(rate))) {
|
||||
(typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) &&
|
||||
logger.warn(
|
||||
`[Profiling] Invalid sample rate. Sample rate must be a boolean or a number between 0 and 1. Got ${JSON.stringify(
|
||||
rate,
|
||||
)} of type ${JSON.stringify(typeof rate)}.`,
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Boolean sample rates are always valid
|
||||
if (rate === true || rate === false) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// in case sampleRate is a boolean, it will get automatically cast to 1 if it's true and 0 if it's false
|
||||
if (rate < 0 || rate > 1) {
|
||||
(typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) &&
|
||||
logger.warn(`[Profiling] Invalid sample rate. Sample rate must be between 0 and 1. Got ${rate}.`);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function isValidProfile(profile) {
|
||||
if (profile.samples.length < 2) {
|
||||
if ((typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__)) {
|
||||
// Log a warning if the profile has less than 2 samples so users can know why
|
||||
// they are not seeing any profiling data and we cant avoid the back and forth
|
||||
// of asking them to provide us with a dump of the profile data.
|
||||
logger.log('[Profiling] Discarding profile because it contains less than 2 samples');
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!profile.frames.length) {
|
||||
if ((typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__)) {
|
||||
logger.log('[Profiling] Discarding profile because it contains no frames');
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a profiling envelope item, if the profile does not pass validation, returns null.
|
||||
* @param event
|
||||
* @returns {Profile | null}
|
||||
*/
|
||||
function createProfilingEvent(profile_id, profile, event) {
|
||||
if (!isValidProfile(profile)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return createProfilePayload(event, profile, profile_id);
|
||||
}
|
||||
|
||||
const PROFILE_MAP = new Map();
|
||||
/**
|
||||
*
|
||||
*/
|
||||
function addProfileToMap(profile_id, profile) {
|
||||
PROFILE_MAP.set(profile_id, profile);
|
||||
|
||||
if (PROFILE_MAP.size > 30) {
|
||||
const last = PROFILE_MAP.keys().next().value;
|
||||
PROFILE_MAP.delete(last);
|
||||
}
|
||||
}
|
||||
|
||||
export { PROFILE_MAP, addProfileToMap, addProfilesToEnvelope, applyDebugMetadata, convertJSSelfProfileToSampledFormat, createProfilePayload, createProfilingEvent, enrichWithThreadInformation, findProfiledTransactionsFromEnvelope, isValidSampleRate };
|
||||
//# sourceMappingURL=utils.js.map
|
||||
293
shared/logger/node_modules/@sentry/browser/esm/sdk.js
generated
vendored
Normal file
293
shared/logger/node_modules/@sentry/browser/esm/sdk.js
generated
vendored
Normal file
@@ -0,0 +1,293 @@
|
||||
import { Integrations, getIntegrationsToSetup, initAndBind, getReportDialogEndpoint, getCurrentHub } from '@sentry/core';
|
||||
import { stackParserFromStackParserOptions, supportsFetch, logger, resolvedSyncPromise, addInstrumentationHandler } from '@sentry/utils';
|
||||
import { BrowserClient } from './client.js';
|
||||
import { WINDOW, wrap as wrap$1 } from './helpers.js';
|
||||
import { GlobalHandlers } from './integrations/globalhandlers.js';
|
||||
import { TryCatch } from './integrations/trycatch.js';
|
||||
import { Breadcrumbs } from './integrations/breadcrumbs.js';
|
||||
import { LinkedErrors } from './integrations/linkederrors.js';
|
||||
import { HttpContext } from './integrations/httpcontext.js';
|
||||
import { Dedupe } from './integrations/dedupe.js';
|
||||
import { defaultStackParser } from './stack-parsers.js';
|
||||
import { makeFetchTransport } from './transports/fetch.js';
|
||||
import { makeXHRTransport } from './transports/xhr.js';
|
||||
|
||||
const defaultIntegrations = [
|
||||
new Integrations.InboundFilters(),
|
||||
new Integrations.FunctionToString(),
|
||||
new TryCatch(),
|
||||
new Breadcrumbs(),
|
||||
new GlobalHandlers(),
|
||||
new LinkedErrors(),
|
||||
new Dedupe(),
|
||||
new HttpContext(),
|
||||
];
|
||||
|
||||
/**
|
||||
* A magic string that build tooling can leverage in order to inject a release value into the SDK.
|
||||
*/
|
||||
|
||||
/**
|
||||
* The Sentry Browser SDK Client.
|
||||
*
|
||||
* To use this SDK, call the {@link init} function as early as possible when
|
||||
* loading the web page. To set context information or send manual events, use
|
||||
* the provided methods.
|
||||
*
|
||||
* @example
|
||||
*
|
||||
* ```
|
||||
*
|
||||
* import { init } from '@sentry/browser';
|
||||
*
|
||||
* init({
|
||||
* dsn: '__DSN__',
|
||||
* // ...
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* @example
|
||||
* ```
|
||||
*
|
||||
* import { configureScope } from '@sentry/browser';
|
||||
* configureScope((scope: Scope) => {
|
||||
* scope.setExtra({ battery: 0.7 });
|
||||
* scope.setTag({ user_mode: 'admin' });
|
||||
* scope.setUser({ id: '4711' });
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* @example
|
||||
* ```
|
||||
*
|
||||
* import { addBreadcrumb } from '@sentry/browser';
|
||||
* addBreadcrumb({
|
||||
* message: 'My Breadcrumb',
|
||||
* // ...
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* @example
|
||||
*
|
||||
* ```
|
||||
*
|
||||
* import * as Sentry from '@sentry/browser';
|
||||
* Sentry.captureMessage('Hello, world!');
|
||||
* Sentry.captureException(new Error('Good bye'));
|
||||
* Sentry.captureEvent({
|
||||
* message: 'Manual',
|
||||
* stacktrace: [
|
||||
* // ...
|
||||
* ],
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* @see {@link BrowserOptions} for documentation on configuration options.
|
||||
*/
|
||||
function init(options = {}) {
|
||||
if (options.defaultIntegrations === undefined) {
|
||||
options.defaultIntegrations = defaultIntegrations;
|
||||
}
|
||||
if (options.release === undefined) {
|
||||
// This allows build tooling to find-and-replace __SENTRY_RELEASE__ to inject a release value
|
||||
if (typeof __SENTRY_RELEASE__ === 'string') {
|
||||
options.release = __SENTRY_RELEASE__;
|
||||
}
|
||||
|
||||
// This supports the variable that sentry-webpack-plugin injects
|
||||
if (WINDOW.SENTRY_RELEASE && WINDOW.SENTRY_RELEASE.id) {
|
||||
options.release = WINDOW.SENTRY_RELEASE.id;
|
||||
}
|
||||
}
|
||||
if (options.autoSessionTracking === undefined) {
|
||||
options.autoSessionTracking = true;
|
||||
}
|
||||
if (options.sendClientReports === undefined) {
|
||||
options.sendClientReports = true;
|
||||
}
|
||||
|
||||
const clientOptions = {
|
||||
...options,
|
||||
stackParser: stackParserFromStackParserOptions(options.stackParser || defaultStackParser),
|
||||
integrations: getIntegrationsToSetup(options),
|
||||
transport: options.transport || (supportsFetch() ? makeFetchTransport : makeXHRTransport),
|
||||
};
|
||||
|
||||
initAndBind(BrowserClient, clientOptions);
|
||||
|
||||
if (options.autoSessionTracking) {
|
||||
startSessionTracking();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Present the user with a report dialog.
|
||||
*
|
||||
* @param options Everything is optional, we try to fetch all info need from the global scope.
|
||||
*/
|
||||
function showReportDialog(options = {}, hub = getCurrentHub()) {
|
||||
// doesn't work without a document (React Native)
|
||||
if (!WINDOW.document) {
|
||||
(typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && logger.error('Global document not defined in showReportDialog call');
|
||||
return;
|
||||
}
|
||||
|
||||
const { client, scope } = hub.getStackTop();
|
||||
const dsn = options.dsn || (client && client.getDsn());
|
||||
if (!dsn) {
|
||||
(typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && logger.error('DSN not configured for showReportDialog call');
|
||||
return;
|
||||
}
|
||||
|
||||
if (scope) {
|
||||
options.user = {
|
||||
...scope.getUser(),
|
||||
...options.user,
|
||||
};
|
||||
}
|
||||
|
||||
if (!options.eventId) {
|
||||
options.eventId = hub.lastEventId();
|
||||
}
|
||||
|
||||
const script = WINDOW.document.createElement('script');
|
||||
script.async = true;
|
||||
script.src = getReportDialogEndpoint(dsn, options);
|
||||
|
||||
if (options.onLoad) {
|
||||
script.onload = options.onLoad;
|
||||
}
|
||||
|
||||
const injectionPoint = WINDOW.document.head || WINDOW.document.body;
|
||||
if (injectionPoint) {
|
||||
injectionPoint.appendChild(script);
|
||||
} else {
|
||||
(typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && logger.error('Not injecting report dialog. No injection point found in HTML');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the getter for lastEventId.
|
||||
*
|
||||
* @returns The last event id of a captured event.
|
||||
*/
|
||||
function lastEventId() {
|
||||
return getCurrentHub().lastEventId();
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is here to be API compatible with the loader.
|
||||
* @hidden
|
||||
*/
|
||||
function forceLoad() {
|
||||
// Noop
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is here to be API compatible with the loader.
|
||||
* @hidden
|
||||
*/
|
||||
function onLoad(callback) {
|
||||
callback();
|
||||
}
|
||||
|
||||
/**
|
||||
* Call `flush()` on the current client, if there is one. See {@link Client.flush}.
|
||||
*
|
||||
* @param timeout Maximum time in ms the client should wait to flush its event queue. Omitting this parameter will cause
|
||||
* the client to wait until all events are sent before resolving the promise.
|
||||
* @returns A promise which resolves to `true` if the queue successfully drains before the timeout, or `false` if it
|
||||
* doesn't (or if there's no client defined).
|
||||
*/
|
||||
function flush(timeout) {
|
||||
const client = getCurrentHub().getClient();
|
||||
if (client) {
|
||||
return client.flush(timeout);
|
||||
}
|
||||
(typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && logger.warn('Cannot flush events. No client defined.');
|
||||
return resolvedSyncPromise(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Call `close()` on the current client, if there is one. See {@link Client.close}.
|
||||
*
|
||||
* @param timeout Maximum time in ms the client should wait to flush its event queue before shutting down. Omitting this
|
||||
* parameter will cause the client to wait until all events are sent before disabling itself.
|
||||
* @returns A promise which resolves to `true` if the queue successfully drains before the timeout, or `false` if it
|
||||
* doesn't (or if there's no client defined).
|
||||
*/
|
||||
function close(timeout) {
|
||||
const client = getCurrentHub().getClient();
|
||||
if (client) {
|
||||
return client.close(timeout);
|
||||
}
|
||||
(typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && logger.warn('Cannot flush events and disable SDK. No client defined.');
|
||||
return resolvedSyncPromise(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap code within a try/catch block so the SDK is able to capture errors.
|
||||
*
|
||||
* @param fn A function to wrap.
|
||||
*
|
||||
* @returns The result of wrapped function call.
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
function wrap(fn) {
|
||||
return wrap$1(fn)();
|
||||
}
|
||||
|
||||
function startSessionOnHub(hub) {
|
||||
hub.startSession({ ignoreDuration: true });
|
||||
hub.captureSession();
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable automatic Session Tracking for the initial page load.
|
||||
*/
|
||||
function startSessionTracking() {
|
||||
if (typeof WINDOW.document === 'undefined') {
|
||||
(typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) &&
|
||||
logger.warn('Session tracking in non-browser environment with @sentry/browser is not supported.');
|
||||
return;
|
||||
}
|
||||
|
||||
const hub = getCurrentHub();
|
||||
|
||||
// The only way for this to be false is for there to be a version mismatch between @sentry/browser (>= 6.0.0) and
|
||||
// @sentry/hub (< 5.27.0). In the simple case, there won't ever be such a mismatch, because the two packages are
|
||||
// pinned at the same version in package.json, but there are edge cases where it's possible. See
|
||||
// https://github.com/getsentry/sentry-javascript/issues/3207 and
|
||||
// https://github.com/getsentry/sentry-javascript/issues/3234 and
|
||||
// https://github.com/getsentry/sentry-javascript/issues/3278.
|
||||
if (!hub.captureSession) {
|
||||
return;
|
||||
}
|
||||
|
||||
// The session duration for browser sessions does not track a meaningful
|
||||
// concept that can be used as a metric.
|
||||
// Automatically captured sessions are akin to page views, and thus we
|
||||
// discard their duration.
|
||||
startSessionOnHub(hub);
|
||||
|
||||
// We want to create a session for every navigation as well
|
||||
addInstrumentationHandler('history', ({ from, to }) => {
|
||||
// Don't create an additional session for the initial route or if the location did not change
|
||||
if (!(from === undefined || from === to)) {
|
||||
startSessionOnHub(getCurrentHub());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Captures user feedback and sends it to Sentry.
|
||||
*/
|
||||
function captureUserFeedback(feedback) {
|
||||
const client = getCurrentHub().getClient();
|
||||
if (client) {
|
||||
client.captureUserFeedback(feedback);
|
||||
}
|
||||
}
|
||||
|
||||
export { captureUserFeedback, close, defaultIntegrations, flush, forceLoad, init, lastEventId, onLoad, showReportDialog, wrap };
|
||||
//# sourceMappingURL=sdk.js.map
|
||||
168
shared/logger/node_modules/@sentry/browser/esm/stack-parsers.js
generated
vendored
Normal file
168
shared/logger/node_modules/@sentry/browser/esm/stack-parsers.js
generated
vendored
Normal file
@@ -0,0 +1,168 @@
|
||||
import { createStackParser } from '@sentry/utils';
|
||||
|
||||
// global reference to slice
|
||||
const UNKNOWN_FUNCTION = '?';
|
||||
|
||||
const OPERA10_PRIORITY = 10;
|
||||
const OPERA11_PRIORITY = 20;
|
||||
const CHROME_PRIORITY = 30;
|
||||
const WINJS_PRIORITY = 40;
|
||||
const GECKO_PRIORITY = 50;
|
||||
|
||||
function createFrame(filename, func, lineno, colno) {
|
||||
const frame = {
|
||||
filename,
|
||||
function: func,
|
||||
in_app: true, // All browser frames are considered in_app
|
||||
};
|
||||
|
||||
if (lineno !== undefined) {
|
||||
frame.lineno = lineno;
|
||||
}
|
||||
|
||||
if (colno !== undefined) {
|
||||
frame.colno = colno;
|
||||
}
|
||||
|
||||
return frame;
|
||||
}
|
||||
|
||||
// Chromium based browsers: Chrome, Brave, new Opera, new Edge
|
||||
const chromeRegex =
|
||||
/^\s*at (?:(.+?\)(?: \[.+\])?|.*?) ?\((?:address at )?)?(?:async )?((?:<anonymous>|[-a-z]+:|.*bundle|\/)?.*?)(?::(\d+))?(?::(\d+))?\)?\s*$/i;
|
||||
const chromeEvalRegex = /\((\S*)(?::(\d+))(?::(\d+))\)/;
|
||||
|
||||
const chrome = line => {
|
||||
const parts = chromeRegex.exec(line);
|
||||
|
||||
if (parts) {
|
||||
const isEval = parts[2] && parts[2].indexOf('eval') === 0; // start of line
|
||||
|
||||
if (isEval) {
|
||||
const subMatch = chromeEvalRegex.exec(parts[2]);
|
||||
|
||||
if (subMatch) {
|
||||
// throw out eval line/column and use top-most line/column number
|
||||
parts[2] = subMatch[1]; // url
|
||||
parts[3] = subMatch[2]; // line
|
||||
parts[4] = subMatch[3]; // column
|
||||
}
|
||||
}
|
||||
|
||||
// Kamil: One more hack won't hurt us right? Understanding and adding more rules on top of these regexps right now
|
||||
// would be way too time consuming. (TODO: Rewrite whole RegExp to be more readable)
|
||||
const [func, filename] = extractSafariExtensionDetails(parts[1] || UNKNOWN_FUNCTION, parts[2]);
|
||||
|
||||
return createFrame(filename, func, parts[3] ? +parts[3] : undefined, parts[4] ? +parts[4] : undefined);
|
||||
}
|
||||
|
||||
return;
|
||||
};
|
||||
|
||||
const chromeStackLineParser = [CHROME_PRIORITY, chrome];
|
||||
|
||||
// gecko regex: `(?:bundle|\d+\.js)`: `bundle` is for react native, `\d+\.js` also but specifically for ram bundles because it
|
||||
// generates filenames without a prefix like `file://` the filenames in the stacktrace are just 42.js
|
||||
// We need this specific case for now because we want no other regex to match.
|
||||
const geckoREgex =
|
||||
/^\s*(.*?)(?:\((.*?)\))?(?:^|@)?((?:[-a-z]+)?:\/.*?|\[native code\]|[^@]*(?:bundle|\d+\.js)|\/[\w\-. /=]+)(?::(\d+))?(?::(\d+))?\s*$/i;
|
||||
const geckoEvalRegex = /(\S+) line (\d+)(?: > eval line \d+)* > eval/i;
|
||||
|
||||
const gecko = line => {
|
||||
const parts = geckoREgex.exec(line);
|
||||
|
||||
if (parts) {
|
||||
const isEval = parts[3] && parts[3].indexOf(' > eval') > -1;
|
||||
if (isEval) {
|
||||
const subMatch = geckoEvalRegex.exec(parts[3]);
|
||||
|
||||
if (subMatch) {
|
||||
// throw out eval line/column and use top-most line number
|
||||
parts[1] = parts[1] || 'eval';
|
||||
parts[3] = subMatch[1];
|
||||
parts[4] = subMatch[2];
|
||||
parts[5] = ''; // no column when eval
|
||||
}
|
||||
}
|
||||
|
||||
let filename = parts[3];
|
||||
let func = parts[1] || UNKNOWN_FUNCTION;
|
||||
[func, filename] = extractSafariExtensionDetails(func, filename);
|
||||
|
||||
return createFrame(filename, func, parts[4] ? +parts[4] : undefined, parts[5] ? +parts[5] : undefined);
|
||||
}
|
||||
|
||||
return;
|
||||
};
|
||||
|
||||
const geckoStackLineParser = [GECKO_PRIORITY, gecko];
|
||||
|
||||
const winjsRegex = /^\s*at (?:((?:\[object object\])?.+) )?\(?((?:[-a-z]+):.*?):(\d+)(?::(\d+))?\)?\s*$/i;
|
||||
|
||||
const winjs = line => {
|
||||
const parts = winjsRegex.exec(line);
|
||||
|
||||
return parts
|
||||
? createFrame(parts[2], parts[1] || UNKNOWN_FUNCTION, +parts[3], parts[4] ? +parts[4] : undefined)
|
||||
: undefined;
|
||||
};
|
||||
|
||||
const winjsStackLineParser = [WINJS_PRIORITY, winjs];
|
||||
|
||||
const opera10Regex = / line (\d+).*script (?:in )?(\S+)(?:: in function (\S+))?$/i;
|
||||
|
||||
const opera10 = line => {
|
||||
const parts = opera10Regex.exec(line);
|
||||
return parts ? createFrame(parts[2], parts[3] || UNKNOWN_FUNCTION, +parts[1]) : undefined;
|
||||
};
|
||||
|
||||
const opera10StackLineParser = [OPERA10_PRIORITY, opera10];
|
||||
|
||||
const opera11Regex =
|
||||
/ line (\d+), column (\d+)\s*(?:in (?:<anonymous function: ([^>]+)>|([^)]+))\(.*\))? in (.*):\s*$/i;
|
||||
|
||||
const opera11 = line => {
|
||||
const parts = opera11Regex.exec(line);
|
||||
return parts ? createFrame(parts[5], parts[3] || parts[4] || UNKNOWN_FUNCTION, +parts[1], +parts[2]) : undefined;
|
||||
};
|
||||
|
||||
const opera11StackLineParser = [OPERA11_PRIORITY, opera11];
|
||||
|
||||
const defaultStackLineParsers = [chromeStackLineParser, geckoStackLineParser, winjsStackLineParser];
|
||||
|
||||
const defaultStackParser = createStackParser(...defaultStackLineParsers);
|
||||
|
||||
/**
|
||||
* Safari web extensions, starting version unknown, can produce "frames-only" stacktraces.
|
||||
* What it means, is that instead of format like:
|
||||
*
|
||||
* Error: wat
|
||||
* at function@url:row:col
|
||||
* at function@url:row:col
|
||||
* at function@url:row:col
|
||||
*
|
||||
* it produces something like:
|
||||
*
|
||||
* function@url:row:col
|
||||
* function@url:row:col
|
||||
* function@url:row:col
|
||||
*
|
||||
* Because of that, it won't be captured by `chrome` RegExp and will fall into `Gecko` branch.
|
||||
* This function is extracted so that we can use it in both places without duplicating the logic.
|
||||
* Unfortunately "just" changing RegExp is too complicated now and making it pass all tests
|
||||
* and fix this case seems like an impossible, or at least way too time-consuming task.
|
||||
*/
|
||||
const extractSafariExtensionDetails = (func, filename) => {
|
||||
const isSafariExtension = func.indexOf('safari-extension') !== -1;
|
||||
const isSafariWebExtension = func.indexOf('safari-web-extension') !== -1;
|
||||
|
||||
return isSafariExtension || isSafariWebExtension
|
||||
? [
|
||||
func.indexOf('@') !== -1 ? func.split('@')[0] : UNKNOWN_FUNCTION,
|
||||
isSafariExtension ? `safari-extension:${filename}` : `safari-web-extension:${filename}`,
|
||||
]
|
||||
: [func, filename];
|
||||
};
|
||||
|
||||
export { chromeStackLineParser, defaultStackLineParsers, defaultStackParser, geckoStackLineParser, opera10StackLineParser, opera11StackLineParser, winjsStackLineParser };
|
||||
//# sourceMappingURL=stack-parsers.js.map
|
||||
64
shared/logger/node_modules/@sentry/browser/esm/transports/fetch.js
generated
vendored
Normal file
64
shared/logger/node_modules/@sentry/browser/esm/transports/fetch.js
generated
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
import { createTransport } from '@sentry/core';
|
||||
import { rejectedSyncPromise } from '@sentry/utils';
|
||||
import { getNativeFetchImplementation, clearCachedFetchImplementation } from './utils.js';
|
||||
|
||||
/**
|
||||
* Creates a Transport that uses the Fetch API to send events to Sentry.
|
||||
*/
|
||||
function makeFetchTransport(
|
||||
options,
|
||||
nativeFetch = getNativeFetchImplementation(),
|
||||
) {
|
||||
let pendingBodySize = 0;
|
||||
let pendingCount = 0;
|
||||
|
||||
function makeRequest(request) {
|
||||
const requestSize = request.body.length;
|
||||
pendingBodySize += requestSize;
|
||||
pendingCount++;
|
||||
|
||||
const requestOptions = {
|
||||
body: request.body,
|
||||
method: 'POST',
|
||||
referrerPolicy: 'origin',
|
||||
headers: options.headers,
|
||||
// Outgoing requests are usually cancelled when navigating to a different page, causing a "TypeError: Failed to
|
||||
// fetch" error and sending a "network_error" client-outcome - in Chrome, the request status shows "(cancelled)".
|
||||
// The `keepalive` flag keeps outgoing requests alive, even when switching pages. We want this since we're
|
||||
// frequently sending events right before the user is switching pages (eg. whenfinishing navigation transactions).
|
||||
// Gotchas:
|
||||
// - `keepalive` isn't supported by Firefox
|
||||
// - As per spec (https://fetch.spec.whatwg.org/#http-network-or-cache-fetch):
|
||||
// If the sum of contentLength and inflightKeepaliveBytes is greater than 64 kibibytes, then return a network error.
|
||||
// We will therefore only activate the flag when we're below that limit.
|
||||
// There is also a limit of requests that can be open at the same time, so we also limit this to 15
|
||||
// See https://github.com/getsentry/sentry-javascript/pull/7553 for details
|
||||
keepalive: pendingBodySize <= 60000 && pendingCount < 15,
|
||||
...options.fetchOptions,
|
||||
};
|
||||
|
||||
try {
|
||||
return nativeFetch(options.url, requestOptions).then(response => {
|
||||
pendingBodySize -= requestSize;
|
||||
pendingCount--;
|
||||
return {
|
||||
statusCode: response.status,
|
||||
headers: {
|
||||
'x-sentry-rate-limits': response.headers.get('X-Sentry-Rate-Limits'),
|
||||
'retry-after': response.headers.get('Retry-After'),
|
||||
},
|
||||
};
|
||||
});
|
||||
} catch (e) {
|
||||
clearCachedFetchImplementation();
|
||||
pendingBodySize -= requestSize;
|
||||
pendingCount--;
|
||||
return rejectedSyncPromise(e);
|
||||
}
|
||||
}
|
||||
|
||||
return createTransport(options, makeRequest);
|
||||
}
|
||||
|
||||
export { makeFetchTransport };
|
||||
//# sourceMappingURL=fetch.js.map
|
||||
133
shared/logger/node_modules/@sentry/browser/esm/transports/offline.js
generated
vendored
Normal file
133
shared/logger/node_modules/@sentry/browser/esm/transports/offline.js
generated
vendored
Normal file
@@ -0,0 +1,133 @@
|
||||
import { makeOfflineTransport } from '@sentry/core';
|
||||
import { serializeEnvelope, parseEnvelope } from '@sentry/utils';
|
||||
|
||||
// 'Store', 'promisifyRequest' and 'createStore' were originally copied from the 'idb-keyval' package before being
|
||||
// modified and simplified: https://github.com/jakearchibald/idb-keyval
|
||||
//
|
||||
// At commit: 0420a704fd6cbb4225429c536b1f61112d012fca
|
||||
// Original licence:
|
||||
|
||||
// Copyright 2016, Jake Archibald
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
function promisifyRequest(request) {
|
||||
return new Promise((resolve, reject) => {
|
||||
// @ts-ignore - file size hacks
|
||||
request.oncomplete = request.onsuccess = () => resolve(request.result);
|
||||
// @ts-ignore - file size hacks
|
||||
request.onabort = request.onerror = () => reject(request.error);
|
||||
});
|
||||
}
|
||||
|
||||
/** Create or open an IndexedDb store */
|
||||
function createStore(dbName, storeName) {
|
||||
const request = indexedDB.open(dbName);
|
||||
request.onupgradeneeded = () => request.result.createObjectStore(storeName);
|
||||
const dbp = promisifyRequest(request);
|
||||
|
||||
return callback => dbp.then(db => callback(db.transaction(storeName, 'readwrite').objectStore(storeName)));
|
||||
}
|
||||
|
||||
function keys(store) {
|
||||
return promisifyRequest(store.getAllKeys() );
|
||||
}
|
||||
|
||||
/** Insert into the store */
|
||||
function insert(store, value, maxQueueSize) {
|
||||
return store(store => {
|
||||
return keys(store).then(keys => {
|
||||
if (keys.length >= maxQueueSize) {
|
||||
return;
|
||||
}
|
||||
|
||||
// We insert with an incremented key so that the entries are popped in order
|
||||
store.put(value, Math.max(...keys, 0) + 1);
|
||||
return promisifyRequest(store.transaction);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/** Pop the oldest value from the store */
|
||||
function pop(store) {
|
||||
return store(store => {
|
||||
return keys(store).then(keys => {
|
||||
if (keys.length === 0) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return promisifyRequest(store.get(keys[0])).then(value => {
|
||||
store.delete(keys[0]);
|
||||
return promisifyRequest(store.transaction).then(() => value);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function createIndexedDbStore(options) {
|
||||
let store;
|
||||
|
||||
// Lazily create the store only when it's needed
|
||||
function getStore() {
|
||||
if (store == undefined) {
|
||||
store = createStore(options.dbName || 'sentry-offline', options.storeName || 'queue');
|
||||
}
|
||||
|
||||
return store;
|
||||
}
|
||||
|
||||
return {
|
||||
insert: async (env) => {
|
||||
try {
|
||||
const serialized = await serializeEnvelope(env, options.textEncoder);
|
||||
await insert(getStore(), serialized, options.maxQueueSize || 30);
|
||||
} catch (_) {
|
||||
//
|
||||
}
|
||||
},
|
||||
pop: async () => {
|
||||
try {
|
||||
const deserialized = await pop(getStore());
|
||||
if (deserialized) {
|
||||
return parseEnvelope(
|
||||
deserialized,
|
||||
options.textEncoder || new TextEncoder(),
|
||||
options.textDecoder || new TextDecoder(),
|
||||
);
|
||||
}
|
||||
} catch (_) {
|
||||
//
|
||||
}
|
||||
|
||||
return undefined;
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function makeIndexedDbOfflineTransport(
|
||||
createTransport,
|
||||
) {
|
||||
return options => createTransport({ ...options, createStore: createIndexedDbStore });
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a transport that uses IndexedDb to store events when offline.
|
||||
*/
|
||||
function makeBrowserOfflineTransport(
|
||||
createTransport,
|
||||
) {
|
||||
return makeIndexedDbOfflineTransport(makeOfflineTransport(createTransport));
|
||||
}
|
||||
|
||||
export { createStore, insert, makeBrowserOfflineTransport, pop };
|
||||
//# sourceMappingURL=offline.js.map
|
||||
85
shared/logger/node_modules/@sentry/browser/esm/transports/utils.js
generated
vendored
Normal file
85
shared/logger/node_modules/@sentry/browser/esm/transports/utils.js
generated
vendored
Normal file
@@ -0,0 +1,85 @@
|
||||
import { isNativeFetch, logger } from '@sentry/utils';
|
||||
import { WINDOW } from '../helpers.js';
|
||||
|
||||
let cachedFetchImpl = undefined;
|
||||
|
||||
/**
|
||||
* A special usecase for incorrectly wrapped Fetch APIs in conjunction with ad-blockers.
|
||||
* Whenever someone wraps the Fetch API and returns the wrong promise chain,
|
||||
* this chain becomes orphaned and there is no possible way to capture it's rejections
|
||||
* other than allowing it bubble up to this very handler. eg.
|
||||
*
|
||||
* const f = window.fetch;
|
||||
* window.fetch = function () {
|
||||
* const p = f.apply(this, arguments);
|
||||
*
|
||||
* p.then(function() {
|
||||
* console.log('hi.');
|
||||
* });
|
||||
*
|
||||
* return p;
|
||||
* }
|
||||
*
|
||||
* `p.then(function () { ... })` is producing a completely separate promise chain,
|
||||
* however, what's returned is `p` - the result of original `fetch` call.
|
||||
*
|
||||
* This mean, that whenever we use the Fetch API to send our own requests, _and_
|
||||
* some ad-blocker blocks it, this orphaned chain will _always_ reject,
|
||||
* effectively causing another event to be captured.
|
||||
* This makes a whole process become an infinite loop, which we need to somehow
|
||||
* deal with, and break it in one way or another.
|
||||
*
|
||||
* To deal with this issue, we are making sure that we _always_ use the real
|
||||
* browser Fetch API, instead of relying on what `window.fetch` exposes.
|
||||
* The only downside to this would be missing our own requests as breadcrumbs,
|
||||
* but because we are already not doing this, it should be just fine.
|
||||
*
|
||||
* Possible failed fetch error messages per-browser:
|
||||
*
|
||||
* Chrome: Failed to fetch
|
||||
* Edge: Failed to Fetch
|
||||
* Firefox: NetworkError when attempting to fetch resource
|
||||
* Safari: resource blocked by content blocker
|
||||
*/
|
||||
function getNativeFetchImplementation() {
|
||||
if (cachedFetchImpl) {
|
||||
return cachedFetchImpl;
|
||||
}
|
||||
|
||||
/* eslint-disable @typescript-eslint/unbound-method */
|
||||
|
||||
// Fast path to avoid DOM I/O
|
||||
if (isNativeFetch(WINDOW.fetch)) {
|
||||
return (cachedFetchImpl = WINDOW.fetch.bind(WINDOW));
|
||||
}
|
||||
|
||||
const document = WINDOW.document;
|
||||
let fetchImpl = WINDOW.fetch;
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
if (document && typeof document.createElement === 'function') {
|
||||
try {
|
||||
const sandbox = document.createElement('iframe');
|
||||
sandbox.hidden = true;
|
||||
document.head.appendChild(sandbox);
|
||||
const contentWindow = sandbox.contentWindow;
|
||||
if (contentWindow && contentWindow.fetch) {
|
||||
fetchImpl = contentWindow.fetch;
|
||||
}
|
||||
document.head.removeChild(sandbox);
|
||||
} catch (e) {
|
||||
(typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) &&
|
||||
logger.warn('Could not create sandbox iframe for pure fetch check, bailing to window.fetch: ', e);
|
||||
}
|
||||
}
|
||||
|
||||
return (cachedFetchImpl = fetchImpl.bind(WINDOW));
|
||||
/* eslint-enable @typescript-eslint/unbound-method */
|
||||
}
|
||||
|
||||
/** Clears cached fetch impl */
|
||||
function clearCachedFetchImplementation() {
|
||||
cachedFetchImpl = undefined;
|
||||
}
|
||||
|
||||
export { clearCachedFetchImplementation, getNativeFetchImplementation };
|
||||
//# sourceMappingURL=utils.js.map
|
||||
52
shared/logger/node_modules/@sentry/browser/esm/transports/xhr.js
generated
vendored
Normal file
52
shared/logger/node_modules/@sentry/browser/esm/transports/xhr.js
generated
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
import { createTransport } from '@sentry/core';
|
||||
import { SyncPromise } from '@sentry/utils';
|
||||
|
||||
/**
|
||||
* The DONE ready state for XmlHttpRequest
|
||||
*
|
||||
* Defining it here as a constant b/c XMLHttpRequest.DONE is not always defined
|
||||
* (e.g. during testing, it is `undefined`)
|
||||
*
|
||||
* @see {@link https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/readyState}
|
||||
*/
|
||||
const XHR_READYSTATE_DONE = 4;
|
||||
|
||||
/**
|
||||
* Creates a Transport that uses the XMLHttpRequest API to send events to Sentry.
|
||||
*/
|
||||
function makeXHRTransport(options) {
|
||||
function makeRequest(request) {
|
||||
return new SyncPromise((resolve, reject) => {
|
||||
const xhr = new XMLHttpRequest();
|
||||
|
||||
xhr.onerror = reject;
|
||||
|
||||
xhr.onreadystatechange = () => {
|
||||
if (xhr.readyState === XHR_READYSTATE_DONE) {
|
||||
resolve({
|
||||
statusCode: xhr.status,
|
||||
headers: {
|
||||
'x-sentry-rate-limits': xhr.getResponseHeader('X-Sentry-Rate-Limits'),
|
||||
'retry-after': xhr.getResponseHeader('Retry-After'),
|
||||
},
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
xhr.open('POST', options.url);
|
||||
|
||||
for (const header in options.headers) {
|
||||
if (Object.prototype.hasOwnProperty.call(options.headers, header)) {
|
||||
xhr.setRequestHeader(header, options.headers[header]);
|
||||
}
|
||||
}
|
||||
|
||||
xhr.send(request.body);
|
||||
});
|
||||
}
|
||||
|
||||
return createTransport(options, makeRequest);
|
||||
}
|
||||
|
||||
export { makeXHRTransport };
|
||||
//# sourceMappingURL=xhr.js.map
|
||||
41
shared/logger/node_modules/@sentry/browser/esm/userfeedback.js
generated
vendored
Normal file
41
shared/logger/node_modules/@sentry/browser/esm/userfeedback.js
generated
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
import { dsnToString, createEnvelope } from '@sentry/utils';
|
||||
|
||||
/**
|
||||
* Creates an envelope from a user feedback.
|
||||
*/
|
||||
function createUserFeedbackEnvelope(
|
||||
feedback,
|
||||
{
|
||||
metadata,
|
||||
tunnel,
|
||||
dsn,
|
||||
}
|
||||
|
||||
,
|
||||
) {
|
||||
const headers = {
|
||||
event_id: feedback.event_id,
|
||||
sent_at: new Date().toISOString(),
|
||||
...(metadata &&
|
||||
metadata.sdk && {
|
||||
sdk: {
|
||||
name: metadata.sdk.name,
|
||||
version: metadata.sdk.version,
|
||||
},
|
||||
}),
|
||||
...(!!tunnel && !!dsn && { dsn: dsnToString(dsn) }),
|
||||
};
|
||||
const item = createUserFeedbackEnvelopeItem(feedback);
|
||||
|
||||
return createEnvelope(headers, [item]);
|
||||
}
|
||||
|
||||
function createUserFeedbackEnvelopeItem(feedback) {
|
||||
const feedbackHeaders = {
|
||||
type: 'user_report',
|
||||
};
|
||||
return [feedbackHeaders, feedback];
|
||||
}
|
||||
|
||||
export { createUserFeedbackEnvelope };
|
||||
//# sourceMappingURL=userfeedback.js.map
|
||||
Reference in New Issue
Block a user