mirror of
https://github.com/MarSeventh/CloudFlare-ImgBed.git
synced 2026-04-30 00:46:28 +00:00
init
This commit is contained in:
39
node_modules/@sentry-internal/tracing/esm/browser/backgroundtab.js
generated
vendored
Normal file
39
node_modules/@sentry-internal/tracing/esm/browser/backgroundtab.js
generated
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
import { getActiveTransaction, spanToJSON } from '@sentry/core';
|
||||
import { logger } from '@sentry/utils';
|
||||
import { DEBUG_BUILD } from '../common/debug-build.js';
|
||||
import { WINDOW } from './types.js';
|
||||
|
||||
/**
|
||||
* Add a listener that cancels and finishes a transaction when the global
|
||||
* document is hidden.
|
||||
*/
|
||||
function registerBackgroundTabDetection() {
|
||||
if (WINDOW.document) {
|
||||
WINDOW.document.addEventListener('visibilitychange', () => {
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
const activeTransaction = getActiveTransaction() ;
|
||||
if (WINDOW.document.hidden && activeTransaction) {
|
||||
const statusType = 'cancelled';
|
||||
|
||||
const { op, status } = spanToJSON(activeTransaction);
|
||||
|
||||
DEBUG_BUILD &&
|
||||
logger.log(`[Tracing] Transaction: ${statusType} -> since tab moved to the background, op: ${op}`);
|
||||
// We should not set status if it is already set, this prevent important statuses like
|
||||
// error or data loss from being overwritten on transaction.
|
||||
if (!status) {
|
||||
activeTransaction.setStatus(statusType);
|
||||
}
|
||||
// TODO: Can we rewrite this to an attribute?
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
activeTransaction.setTag('visibilitychange', 'document.hidden');
|
||||
activeTransaction.end();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
DEBUG_BUILD && logger.warn('[Tracing] Could not set up background tab detection due to lack of global document');
|
||||
}
|
||||
}
|
||||
|
||||
export { registerBackgroundTabDetection };
|
||||
//# sourceMappingURL=backgroundtab.js.map
|
||||
1
node_modules/@sentry-internal/tracing/esm/browser/backgroundtab.js.map
generated
vendored
Normal file
1
node_modules/@sentry-internal/tracing/esm/browser/backgroundtab.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"backgroundtab.js","sources":["../../../src/browser/backgroundtab.ts"],"sourcesContent":["import type { IdleTransaction, SpanStatusType } from '@sentry/core';\nimport { getActiveTransaction, spanToJSON } from '@sentry/core';\nimport { logger } from '@sentry/utils';\n\nimport { DEBUG_BUILD } from '../common/debug-build';\nimport { WINDOW } from './types';\n\n/**\n * Add a listener that cancels and finishes a transaction when the global\n * document is hidden.\n */\nexport function registerBackgroundTabDetection(): void {\n if (WINDOW.document) {\n WINDOW.document.addEventListener('visibilitychange', () => {\n // eslint-disable-next-line deprecation/deprecation\n const activeTransaction = getActiveTransaction() as IdleTransaction;\n if (WINDOW.document!.hidden && activeTransaction) {\n const statusType: SpanStatusType = 'cancelled';\n\n const { op, status } = spanToJSON(activeTransaction);\n\n DEBUG_BUILD &&\n logger.log(`[Tracing] Transaction: ${statusType} -> since tab moved to the background, op: ${op}`);\n // We should not set status if it is already set, this prevent important statuses like\n // error or data loss from being overwritten on transaction.\n if (!status) {\n activeTransaction.setStatus(statusType);\n }\n // TODO: Can we rewrite this to an attribute?\n // eslint-disable-next-line deprecation/deprecation\n activeTransaction.setTag('visibilitychange', 'document.hidden');\n activeTransaction.end();\n }\n });\n } else {\n DEBUG_BUILD && logger.warn('[Tracing] Could not set up background tab detection due to lack of global document');\n }\n}\n"],"names":[],"mappings":";;;;;AAOA;AACA;AACA;AACA;AACO,SAAS,8BAA8B,GAAS;AACvD,EAAE,IAAI,MAAM,CAAC,QAAQ,EAAE;AACvB,IAAI,MAAM,CAAC,QAAQ,CAAC,gBAAgB,CAAC,kBAAkB,EAAE,MAAM;AAC/D;AACA,MAAM,MAAM,iBAAA,GAAoB,oBAAoB,EAAG,EAAA;AACvD,MAAM,IAAI,MAAM,CAAC,QAAQ,CAAE,MAAA,IAAU,iBAAiB,EAAE;AACxD,QAAQ,MAAM,UAAU,GAAmB,WAAW,CAAA;AACtD;AACA,QAAQ,MAAM,EAAE,EAAE,EAAE,MAAA,KAAW,UAAU,CAAC,iBAAiB,CAAC,CAAA;AAC5D;AACA,QAAQ,WAAY;AACpB,UAAU,MAAM,CAAC,GAAG,CAAC,CAAC,uBAAuB,EAAE,UAAU,CAAC,2CAA2C,EAAE,EAAE,CAAC,CAAA,CAAA,CAAA;AACA;AACA;AACA,QAAA,IAAA,CAAA,MAAA,EAAA;AACA,UAAA,iBAAA,CAAA,SAAA,CAAA,UAAA,CAAA,CAAA;AACA,SAAA;AACA;AACA;AACA,QAAA,iBAAA,CAAA,MAAA,CAAA,kBAAA,EAAA,iBAAA,CAAA,CAAA;AACA,QAAA,iBAAA,CAAA,GAAA,EAAA,CAAA;AACA,OAAA;AACA,KAAA,CAAA,CAAA;AACA,GAAA,MAAA;AACA,IAAA,WAAA,IAAA,MAAA,CAAA,IAAA,CAAA,oFAAA,CAAA,CAAA;AACA,GAAA;AACA;;;;"}
|
||||
506
node_modules/@sentry-internal/tracing/esm/browser/browserTracingIntegration.js
generated
vendored
Normal file
506
node_modules/@sentry-internal/tracing/esm/browser/browserTracingIntegration.js
generated
vendored
Normal file
@@ -0,0 +1,506 @@
|
||||
import { TRACING_DEFAULTS, addTracingExtensions, spanToJSON, SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, getActiveSpan, getCurrentHub, startIdleTransaction, getActiveTransaction, getClient, getCurrentScope } from '@sentry/core';
|
||||
import { logger, browserPerformanceTimeOrigin, addHistoryInstrumentationHandler, propagationContextFromHeaders, getDomElement } from '@sentry/utils';
|
||||
import { DEBUG_BUILD } from '../common/debug-build.js';
|
||||
import { registerBackgroundTabDetection } from './backgroundtab.js';
|
||||
import { addPerformanceInstrumentationHandler } from './instrument.js';
|
||||
import { startTrackingWebVitals, startTrackingINP, startTrackingLongTasks, startTrackingInteractions, addPerformanceEntries } from './metrics/index.js';
|
||||
import { defaultRequestInstrumentationOptions, instrumentOutgoingRequests } from './request.js';
|
||||
import { WINDOW } from './types.js';
|
||||
|
||||
const BROWSER_TRACING_INTEGRATION_ID = 'BrowserTracing';
|
||||
|
||||
/** Options for Browser Tracing integration */
|
||||
|
||||
const DEFAULT_BROWSER_TRACING_OPTIONS = {
|
||||
...TRACING_DEFAULTS,
|
||||
instrumentNavigation: true,
|
||||
instrumentPageLoad: true,
|
||||
markBackgroundSpan: true,
|
||||
enableLongTask: true,
|
||||
enableInp: false,
|
||||
interactionsSampleRate: 1,
|
||||
_experiments: {},
|
||||
...defaultRequestInstrumentationOptions,
|
||||
};
|
||||
|
||||
/**
|
||||
* The Browser Tracing integration automatically instruments browser pageload/navigation
|
||||
* actions as transactions, and captures requests, metrics and errors as spans.
|
||||
*
|
||||
* The integration can be configured with a variety of options, and can be extended to use
|
||||
* any routing library. This integration uses {@see IdleTransaction} to create transactions.
|
||||
*
|
||||
* We explicitly export the proper type here, as this has to be extended in some cases.
|
||||
*/
|
||||
const browserTracingIntegration = ((_options = {}) => {
|
||||
const _hasSetTracePropagationTargets = DEBUG_BUILD
|
||||
? !!(
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
(_options.tracePropagationTargets || _options.tracingOrigins)
|
||||
)
|
||||
: false;
|
||||
|
||||
addTracingExtensions();
|
||||
|
||||
// TODO (v8): remove this block after tracingOrigins is removed
|
||||
// Set tracePropagationTargets to tracingOrigins if specified by the user
|
||||
// In case both are specified, tracePropagationTargets takes precedence
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
if (!_options.tracePropagationTargets && _options.tracingOrigins) {
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
_options.tracePropagationTargets = _options.tracingOrigins;
|
||||
}
|
||||
|
||||
const options = {
|
||||
...DEFAULT_BROWSER_TRACING_OPTIONS,
|
||||
..._options,
|
||||
};
|
||||
|
||||
const _collectWebVitals = startTrackingWebVitals();
|
||||
|
||||
/** Stores a mapping of interactionIds from PerformanceEventTimings to the origin interaction path */
|
||||
const interactionIdToRouteNameMapping = {};
|
||||
if (options.enableInp) {
|
||||
startTrackingINP(interactionIdToRouteNameMapping, options.interactionsSampleRate);
|
||||
}
|
||||
|
||||
if (options.enableLongTask) {
|
||||
startTrackingLongTasks();
|
||||
}
|
||||
if (options._experiments.enableInteractions) {
|
||||
startTrackingInteractions();
|
||||
}
|
||||
|
||||
const latestRoute
|
||||
|
||||
= {
|
||||
name: undefined,
|
||||
context: undefined,
|
||||
};
|
||||
|
||||
/** Create routing idle transaction. */
|
||||
function _createRouteTransaction(context) {
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
const hub = getCurrentHub();
|
||||
|
||||
const { beforeStartSpan, idleTimeout, finalTimeout, heartbeatInterval } = options;
|
||||
|
||||
const isPageloadTransaction = context.op === 'pageload';
|
||||
|
||||
let expandedContext;
|
||||
if (isPageloadTransaction) {
|
||||
const sentryTrace = isPageloadTransaction ? getMetaContent('sentry-trace') : '';
|
||||
const baggage = isPageloadTransaction ? getMetaContent('baggage') : undefined;
|
||||
const { traceId, dsc, parentSpanId, sampled } = propagationContextFromHeaders(sentryTrace, baggage);
|
||||
expandedContext = {
|
||||
traceId,
|
||||
parentSpanId,
|
||||
parentSampled: sampled,
|
||||
...context,
|
||||
metadata: {
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
...context.metadata,
|
||||
dynamicSamplingContext: dsc,
|
||||
},
|
||||
trimEnd: true,
|
||||
};
|
||||
} else {
|
||||
expandedContext = {
|
||||
trimEnd: true,
|
||||
...context,
|
||||
};
|
||||
}
|
||||
|
||||
const finalContext = beforeStartSpan ? beforeStartSpan(expandedContext) : expandedContext;
|
||||
|
||||
// If `beforeStartSpan` set a custom name, record that fact
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
finalContext.metadata =
|
||||
finalContext.name !== expandedContext.name
|
||||
? // eslint-disable-next-line deprecation/deprecation
|
||||
{ ...finalContext.metadata, source: 'custom' }
|
||||
: // eslint-disable-next-line deprecation/deprecation
|
||||
finalContext.metadata;
|
||||
|
||||
latestRoute.name = finalContext.name;
|
||||
latestRoute.context = finalContext;
|
||||
|
||||
if (finalContext.sampled === false) {
|
||||
DEBUG_BUILD && logger.log(`[Tracing] Will not send ${finalContext.op} transaction because of beforeNavigate.`);
|
||||
}
|
||||
|
||||
DEBUG_BUILD && logger.log(`[Tracing] Starting ${finalContext.op} transaction on scope`);
|
||||
|
||||
const { location } = WINDOW;
|
||||
|
||||
const idleTransaction = startIdleTransaction(
|
||||
hub,
|
||||
finalContext,
|
||||
idleTimeout,
|
||||
finalTimeout,
|
||||
true,
|
||||
{ location }, // for use in the tracesSampler
|
||||
heartbeatInterval,
|
||||
isPageloadTransaction, // should wait for finish signal if it's a pageload transaction
|
||||
);
|
||||
|
||||
if (isPageloadTransaction && WINDOW.document) {
|
||||
WINDOW.document.addEventListener('readystatechange', () => {
|
||||
if (['interactive', 'complete'].includes(WINDOW.document.readyState)) {
|
||||
idleTransaction.sendAutoFinishSignal();
|
||||
}
|
||||
});
|
||||
|
||||
if (['interactive', 'complete'].includes(WINDOW.document.readyState)) {
|
||||
idleTransaction.sendAutoFinishSignal();
|
||||
}
|
||||
}
|
||||
|
||||
idleTransaction.registerBeforeFinishCallback(transaction => {
|
||||
_collectWebVitals();
|
||||
addPerformanceEntries(transaction);
|
||||
});
|
||||
|
||||
return idleTransaction ;
|
||||
}
|
||||
|
||||
return {
|
||||
name: BROWSER_TRACING_INTEGRATION_ID,
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||
setupOnce: () => {},
|
||||
afterAllSetup(client) {
|
||||
const clientOptions = client.getOptions();
|
||||
|
||||
const { markBackgroundSpan, traceFetch, traceXHR, shouldCreateSpanForRequest, enableHTTPTimings, _experiments } =
|
||||
options;
|
||||
|
||||
const clientOptionsTracePropagationTargets = clientOptions && clientOptions.tracePropagationTargets;
|
||||
// There are three ways to configure tracePropagationTargets:
|
||||
// 1. via top level client option `tracePropagationTargets`
|
||||
// 2. via BrowserTracing option `tracePropagationTargets`
|
||||
// 3. via BrowserTracing option `tracingOrigins` (deprecated)
|
||||
//
|
||||
// To avoid confusion, favour top level client option `tracePropagationTargets`, and fallback to
|
||||
// BrowserTracing option `tracePropagationTargets` and then `tracingOrigins` (deprecated).
|
||||
// This is done as it minimizes bundle size (we don't have to have undefined checks).
|
||||
//
|
||||
// If both 1 and either one of 2 or 3 are set (from above), we log out a warning.
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
const tracePropagationTargets = clientOptionsTracePropagationTargets || options.tracePropagationTargets;
|
||||
if (DEBUG_BUILD && _hasSetTracePropagationTargets && clientOptionsTracePropagationTargets) {
|
||||
logger.warn(
|
||||
'[Tracing] The `tracePropagationTargets` option was set in the BrowserTracing integration and top level `Sentry.init`. The top level `Sentry.init` value is being used.',
|
||||
);
|
||||
}
|
||||
|
||||
let activeSpan;
|
||||
let startingUrl = WINDOW.location && WINDOW.location.href;
|
||||
|
||||
if (client.on) {
|
||||
client.on('startNavigationSpan', (context) => {
|
||||
if (activeSpan) {
|
||||
DEBUG_BUILD && logger.log(`[Tracing] Finishing current transaction with op: ${spanToJSON(activeSpan).op}`);
|
||||
// If there's an open transaction on the scope, we need to finish it before creating an new one.
|
||||
activeSpan.end();
|
||||
}
|
||||
activeSpan = _createRouteTransaction({
|
||||
op: 'navigation',
|
||||
...context,
|
||||
});
|
||||
});
|
||||
|
||||
client.on('startPageLoadSpan', (context) => {
|
||||
if (activeSpan) {
|
||||
DEBUG_BUILD && logger.log(`[Tracing] Finishing current transaction with op: ${spanToJSON(activeSpan).op}`);
|
||||
// If there's an open transaction on the scope, we need to finish it before creating an new one.
|
||||
activeSpan.end();
|
||||
}
|
||||
activeSpan = _createRouteTransaction({
|
||||
op: 'pageload',
|
||||
...context,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if (options.instrumentPageLoad && client.emit && WINDOW.location) {
|
||||
const context = {
|
||||
name: WINDOW.location.pathname,
|
||||
// pageload should always start at timeOrigin (and needs to be in s, not ms)
|
||||
startTimestamp: browserPerformanceTimeOrigin ? browserPerformanceTimeOrigin / 1000 : undefined,
|
||||
origin: 'auto.pageload.browser',
|
||||
attributes: {
|
||||
[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'url',
|
||||
},
|
||||
};
|
||||
startBrowserTracingPageLoadSpan(client, context);
|
||||
}
|
||||
|
||||
if (options.instrumentNavigation && client.emit && WINDOW.location) {
|
||||
addHistoryInstrumentationHandler(({ to, from }) => {
|
||||
/**
|
||||
* This early return is there to account for some cases where a navigation transaction starts right after
|
||||
* long-running pageload. We make sure that if `from` is undefined and a valid `startingURL` exists, we don't
|
||||
* create an uneccessary navigation transaction.
|
||||
*
|
||||
* This was hard to duplicate, but this behavior stopped as soon as this fix was applied. This issue might also
|
||||
* only be caused in certain development environments where the usage of a hot module reloader is causing
|
||||
* errors.
|
||||
*/
|
||||
if (from === undefined && startingUrl && startingUrl.indexOf(to) !== -1) {
|
||||
startingUrl = undefined;
|
||||
return;
|
||||
}
|
||||
|
||||
if (from !== to) {
|
||||
startingUrl = undefined;
|
||||
const context = {
|
||||
name: WINDOW.location.pathname,
|
||||
origin: 'auto.navigation.browser',
|
||||
attributes: {
|
||||
[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'url',
|
||||
},
|
||||
};
|
||||
|
||||
startBrowserTracingNavigationSpan(client, context);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (markBackgroundSpan) {
|
||||
registerBackgroundTabDetection();
|
||||
}
|
||||
|
||||
if (_experiments.enableInteractions) {
|
||||
registerInteractionListener(options, latestRoute);
|
||||
}
|
||||
|
||||
if (options.enableInp) {
|
||||
registerInpInteractionListener(interactionIdToRouteNameMapping, latestRoute);
|
||||
}
|
||||
|
||||
instrumentOutgoingRequests({
|
||||
traceFetch,
|
||||
traceXHR,
|
||||
tracePropagationTargets,
|
||||
shouldCreateSpanForRequest,
|
||||
enableHTTPTimings,
|
||||
});
|
||||
},
|
||||
// TODO v8: Remove this again
|
||||
// This is private API that we use to fix converted BrowserTracing integrations in Next.js & SvelteKit
|
||||
options,
|
||||
};
|
||||
}) ;
|
||||
|
||||
/**
|
||||
* Manually start a page load span.
|
||||
* This will only do something if the BrowserTracing integration has been setup.
|
||||
*/
|
||||
function startBrowserTracingPageLoadSpan(client, spanOptions) {
|
||||
if (!client.emit) {
|
||||
return;
|
||||
}
|
||||
|
||||
client.emit('startPageLoadSpan', spanOptions);
|
||||
|
||||
const span = getActiveSpan();
|
||||
const op = span && spanToJSON(span).op;
|
||||
return op === 'pageload' ? span : undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Manually start a navigation span.
|
||||
* This will only do something if the BrowserTracing integration has been setup.
|
||||
*/
|
||||
function startBrowserTracingNavigationSpan(client, spanOptions) {
|
||||
if (!client.emit) {
|
||||
return;
|
||||
}
|
||||
|
||||
client.emit('startNavigationSpan', spanOptions);
|
||||
|
||||
const span = getActiveSpan();
|
||||
const op = span && spanToJSON(span).op;
|
||||
return op === 'navigation' ? span : undefined;
|
||||
}
|
||||
|
||||
/** Returns the value of a meta tag */
|
||||
function getMetaContent(metaName) {
|
||||
// Can't specify generic to `getDomElement` because tracing can be used
|
||||
// in a variety of environments, have to disable `no-unsafe-member-access`
|
||||
// as a result.
|
||||
const metaTag = getDomElement(`meta[name=${metaName}]`);
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
||||
return metaTag ? metaTag.getAttribute('content') : undefined;
|
||||
}
|
||||
|
||||
/** Start listener for interaction transactions */
|
||||
function registerInteractionListener(
|
||||
options,
|
||||
latestRoute
|
||||
|
||||
,
|
||||
) {
|
||||
let inflightInteractionTransaction;
|
||||
const registerInteractionTransaction = () => {
|
||||
const { idleTimeout, finalTimeout, heartbeatInterval } = options;
|
||||
const op = 'ui.action.click';
|
||||
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
const currentTransaction = getActiveTransaction();
|
||||
if (currentTransaction && currentTransaction.op && ['navigation', 'pageload'].includes(currentTransaction.op)) {
|
||||
DEBUG_BUILD &&
|
||||
logger.warn(
|
||||
`[Tracing] Did not create ${op} transaction because a pageload or navigation transaction is in progress.`,
|
||||
);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (inflightInteractionTransaction) {
|
||||
inflightInteractionTransaction.setFinishReason('interactionInterrupted');
|
||||
inflightInteractionTransaction.end();
|
||||
inflightInteractionTransaction = undefined;
|
||||
}
|
||||
|
||||
if (!latestRoute.name) {
|
||||
DEBUG_BUILD && logger.warn(`[Tracing] Did not create ${op} transaction because _latestRouteName is missing.`);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const { location } = WINDOW;
|
||||
|
||||
const context = {
|
||||
name: latestRoute.name,
|
||||
op,
|
||||
trimEnd: true,
|
||||
data: {
|
||||
[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: latestRoute.context ? getSource(latestRoute.context) : 'url',
|
||||
},
|
||||
};
|
||||
|
||||
inflightInteractionTransaction = startIdleTransaction(
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
getCurrentHub(),
|
||||
context,
|
||||
idleTimeout,
|
||||
finalTimeout,
|
||||
true,
|
||||
{ location }, // for use in the tracesSampler
|
||||
heartbeatInterval,
|
||||
);
|
||||
};
|
||||
|
||||
['click'].forEach(type => {
|
||||
if (WINDOW.document) {
|
||||
addEventListener(type, registerInteractionTransaction, { once: false, capture: true });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function isPerformanceEventTiming(entry) {
|
||||
return 'duration' in entry;
|
||||
}
|
||||
|
||||
/** We store up to 10 interaction candidates max to cap memory usage. This is the same cap as getINP from web-vitals */
|
||||
const MAX_INTERACTIONS = 10;
|
||||
|
||||
/** Creates a listener on interaction entries, and maps interactionIds to the origin path of the interaction */
|
||||
function registerInpInteractionListener(
|
||||
interactionIdToRouteNameMapping,
|
||||
latestRoute
|
||||
|
||||
,
|
||||
) {
|
||||
const handleEntries = ({ entries }) => {
|
||||
const client = getClient();
|
||||
// We need to get the replay, user, and activeTransaction from the current scope
|
||||
// so that we can associate replay id, profile id, and a user display to the span
|
||||
const replay =
|
||||
client !== undefined && client.getIntegrationByName !== undefined
|
||||
? (client.getIntegrationByName('Replay') )
|
||||
: undefined;
|
||||
const replayId = replay !== undefined ? replay.getReplayId() : undefined;
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
const activeTransaction = getActiveTransaction();
|
||||
const currentScope = getCurrentScope();
|
||||
const user = currentScope !== undefined ? currentScope.getUser() : undefined;
|
||||
entries.forEach(entry => {
|
||||
if (isPerformanceEventTiming(entry)) {
|
||||
const interactionId = entry.interactionId;
|
||||
if (interactionId === undefined) {
|
||||
return;
|
||||
}
|
||||
const existingInteraction = interactionIdToRouteNameMapping[interactionId];
|
||||
const duration = entry.duration;
|
||||
const startTime = entry.startTime;
|
||||
const keys = Object.keys(interactionIdToRouteNameMapping);
|
||||
const minInteractionId =
|
||||
keys.length > 0
|
||||
? keys.reduce((a, b) => {
|
||||
return interactionIdToRouteNameMapping[a].duration < interactionIdToRouteNameMapping[b].duration
|
||||
? a
|
||||
: b;
|
||||
})
|
||||
: undefined;
|
||||
// For a first input event to be considered, we must check that an interaction event does not already exist with the same duration and start time.
|
||||
// This is also checked in the web-vitals library.
|
||||
if (entry.entryType === 'first-input') {
|
||||
const matchingEntry = keys
|
||||
.map(key => interactionIdToRouteNameMapping[key])
|
||||
.some(interaction => {
|
||||
return interaction.duration === duration && interaction.startTime === startTime;
|
||||
});
|
||||
if (matchingEntry) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Interactions with an id of 0 and are not first-input are not valid.
|
||||
if (!interactionId) {
|
||||
return;
|
||||
}
|
||||
// If the interaction already exists, we want to use the duration of the longest entry, since that is what the INP metric uses.
|
||||
if (existingInteraction) {
|
||||
existingInteraction.duration = Math.max(existingInteraction.duration, duration);
|
||||
} else if (
|
||||
keys.length < MAX_INTERACTIONS ||
|
||||
minInteractionId === undefined ||
|
||||
duration > interactionIdToRouteNameMapping[minInteractionId].duration
|
||||
) {
|
||||
// If the interaction does not exist, we want to add it to the mapping if there is space, or if the duration is longer than the shortest entry.
|
||||
const routeName = latestRoute.name;
|
||||
const parentContext = latestRoute.context;
|
||||
if (routeName && parentContext) {
|
||||
if (minInteractionId && Object.keys(interactionIdToRouteNameMapping).length >= MAX_INTERACTIONS) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
|
||||
delete interactionIdToRouteNameMapping[minInteractionId];
|
||||
}
|
||||
interactionIdToRouteNameMapping[interactionId] = {
|
||||
routeName,
|
||||
duration,
|
||||
parentContext,
|
||||
user,
|
||||
activeTransaction,
|
||||
replayId,
|
||||
startTime,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
addPerformanceInstrumentationHandler('event', handleEntries);
|
||||
addPerformanceInstrumentationHandler('first-input', handleEntries);
|
||||
}
|
||||
|
||||
function getSource(context) {
|
||||
const sourceFromAttributes = context.attributes && context.attributes[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE];
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
const sourceFromData = context.data && context.data[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE];
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
const sourceFromMetadata = context.metadata && context.metadata.source;
|
||||
|
||||
return sourceFromAttributes || sourceFromData || sourceFromMetadata;
|
||||
}
|
||||
|
||||
export { BROWSER_TRACING_INTEGRATION_ID, browserTracingIntegration, getMetaContent, startBrowserTracingNavigationSpan, startBrowserTracingPageLoadSpan };
|
||||
//# sourceMappingURL=browserTracingIntegration.js.map
|
||||
1
node_modules/@sentry-internal/tracing/esm/browser/browserTracingIntegration.js.map
generated
vendored
Normal file
1
node_modules/@sentry-internal/tracing/esm/browser/browserTracingIntegration.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
457
node_modules/@sentry-internal/tracing/esm/browser/browsertracing.js
generated
vendored
Normal file
457
node_modules/@sentry-internal/tracing/esm/browser/browsertracing.js
generated
vendored
Normal file
@@ -0,0 +1,457 @@
|
||||
import { TRACING_DEFAULTS, addTracingExtensions, startIdleTransaction, getActiveTransaction, SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, getClient, getCurrentScope } from '@sentry/core';
|
||||
import { logger, propagationContextFromHeaders, getDomElement } from '@sentry/utils';
|
||||
import { DEBUG_BUILD } from '../common/debug-build.js';
|
||||
import { registerBackgroundTabDetection } from './backgroundtab.js';
|
||||
import { addPerformanceInstrumentationHandler } from './instrument.js';
|
||||
import { startTrackingWebVitals, startTrackingINP, startTrackingLongTasks, startTrackingInteractions, addPerformanceEntries } from './metrics/index.js';
|
||||
import { defaultRequestInstrumentationOptions, instrumentOutgoingRequests } from './request.js';
|
||||
import { instrumentRoutingWithDefaults } from './router.js';
|
||||
import { WINDOW } from './types.js';
|
||||
|
||||
const BROWSER_TRACING_INTEGRATION_ID = 'BrowserTracing';
|
||||
|
||||
/** Options for Browser Tracing integration */
|
||||
|
||||
const DEFAULT_BROWSER_TRACING_OPTIONS = {
|
||||
...TRACING_DEFAULTS,
|
||||
markBackgroundTransactions: true,
|
||||
routingInstrumentation: instrumentRoutingWithDefaults,
|
||||
startTransactionOnLocationChange: true,
|
||||
startTransactionOnPageLoad: true,
|
||||
enableLongTask: true,
|
||||
enableInp: false,
|
||||
interactionsSampleRate: 1,
|
||||
_experiments: {},
|
||||
...defaultRequestInstrumentationOptions,
|
||||
};
|
||||
|
||||
/** We store up to 10 interaction candidates max to cap memory usage. This is the same cap as getINP from web-vitals */
|
||||
const MAX_INTERACTIONS = 10;
|
||||
|
||||
/**
|
||||
* The Browser Tracing integration automatically instruments browser pageload/navigation
|
||||
* actions as transactions, and captures requests, metrics and errors as spans.
|
||||
*
|
||||
* The integration can be configured with a variety of options, and can be extended to use
|
||||
* any routing library. This integration uses {@see IdleTransaction} to create transactions.
|
||||
*
|
||||
* @deprecated Use `browserTracingIntegration()` instead.
|
||||
*/
|
||||
class BrowserTracing {
|
||||
// This class currently doesn't have a static `id` field like the other integration classes, because it prevented
|
||||
// @sentry/tracing from being treeshaken. Tree shakers do not like static fields, because they behave like side effects.
|
||||
// TODO: Come up with a better plan, than using static fields on integration classes, and use that plan on all
|
||||
// integrations.
|
||||
|
||||
/** Browser Tracing integration options */
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
|
||||
constructor(_options) {
|
||||
this.name = BROWSER_TRACING_INTEGRATION_ID;
|
||||
this._hasSetTracePropagationTargets = false;
|
||||
|
||||
addTracingExtensions();
|
||||
|
||||
if (DEBUG_BUILD) {
|
||||
this._hasSetTracePropagationTargets = !!(
|
||||
_options &&
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
(_options.tracePropagationTargets || _options.tracingOrigins)
|
||||
);
|
||||
}
|
||||
|
||||
this.options = {
|
||||
...DEFAULT_BROWSER_TRACING_OPTIONS,
|
||||
..._options,
|
||||
};
|
||||
|
||||
// Special case: enableLongTask can be set in _experiments
|
||||
// TODO (v8): Remove this in v8
|
||||
if (this.options._experiments.enableLongTask !== undefined) {
|
||||
this.options.enableLongTask = this.options._experiments.enableLongTask;
|
||||
}
|
||||
|
||||
// TODO (v8): remove this block after tracingOrigins is removed
|
||||
// Set tracePropagationTargets to tracingOrigins if specified by the user
|
||||
// In case both are specified, tracePropagationTargets takes precedence
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
if (_options && !_options.tracePropagationTargets && _options.tracingOrigins) {
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
this.options.tracePropagationTargets = _options.tracingOrigins;
|
||||
}
|
||||
|
||||
this._collectWebVitals = startTrackingWebVitals();
|
||||
/** Stores a mapping of interactionIds from PerformanceEventTimings to the origin interaction path */
|
||||
this._interactionIdToRouteNameMapping = {};
|
||||
|
||||
if (this.options.enableInp) {
|
||||
startTrackingINP(this._interactionIdToRouteNameMapping, this.options.interactionsSampleRate);
|
||||
}
|
||||
if (this.options.enableLongTask) {
|
||||
startTrackingLongTasks();
|
||||
}
|
||||
if (this.options._experiments.enableInteractions) {
|
||||
startTrackingInteractions();
|
||||
}
|
||||
|
||||
this._latestRoute = {
|
||||
name: undefined,
|
||||
context: undefined,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
setupOnce(_, getCurrentHub) {
|
||||
this._getCurrentHub = getCurrentHub;
|
||||
const hub = getCurrentHub();
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
const client = hub.getClient();
|
||||
const clientOptions = client && client.getOptions();
|
||||
|
||||
const {
|
||||
routingInstrumentation: instrumentRouting,
|
||||
startTransactionOnLocationChange,
|
||||
startTransactionOnPageLoad,
|
||||
markBackgroundTransactions,
|
||||
traceFetch,
|
||||
traceXHR,
|
||||
shouldCreateSpanForRequest,
|
||||
enableHTTPTimings,
|
||||
_experiments,
|
||||
} = this.options;
|
||||
|
||||
const clientOptionsTracePropagationTargets = clientOptions && clientOptions.tracePropagationTargets;
|
||||
// There are three ways to configure tracePropagationTargets:
|
||||
// 1. via top level client option `tracePropagationTargets`
|
||||
// 2. via BrowserTracing option `tracePropagationTargets`
|
||||
// 3. via BrowserTracing option `tracingOrigins` (deprecated)
|
||||
//
|
||||
// To avoid confusion, favour top level client option `tracePropagationTargets`, and fallback to
|
||||
// BrowserTracing option `tracePropagationTargets` and then `tracingOrigins` (deprecated).
|
||||
// This is done as it minimizes bundle size (we don't have to have undefined checks).
|
||||
//
|
||||
// If both 1 and either one of 2 or 3 are set (from above), we log out a warning.
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
const tracePropagationTargets = clientOptionsTracePropagationTargets || this.options.tracePropagationTargets;
|
||||
if (DEBUG_BUILD && this._hasSetTracePropagationTargets && clientOptionsTracePropagationTargets) {
|
||||
logger.warn(
|
||||
'[Tracing] The `tracePropagationTargets` option was set in the BrowserTracing integration and top level `Sentry.init`. The top level `Sentry.init` value is being used.',
|
||||
);
|
||||
}
|
||||
|
||||
instrumentRouting(
|
||||
(context) => {
|
||||
const transaction = this._createRouteTransaction(context);
|
||||
|
||||
this.options._experiments.onStartRouteTransaction &&
|
||||
this.options._experiments.onStartRouteTransaction(transaction, context, getCurrentHub);
|
||||
|
||||
return transaction;
|
||||
},
|
||||
startTransactionOnPageLoad,
|
||||
startTransactionOnLocationChange,
|
||||
);
|
||||
|
||||
if (markBackgroundTransactions) {
|
||||
registerBackgroundTabDetection();
|
||||
}
|
||||
|
||||
if (_experiments.enableInteractions) {
|
||||
this._registerInteractionListener();
|
||||
}
|
||||
|
||||
if (this.options.enableInp) {
|
||||
this._registerInpInteractionListener();
|
||||
}
|
||||
|
||||
instrumentOutgoingRequests({
|
||||
traceFetch,
|
||||
traceXHR,
|
||||
tracePropagationTargets,
|
||||
shouldCreateSpanForRequest,
|
||||
enableHTTPTimings,
|
||||
});
|
||||
}
|
||||
|
||||
/** Create routing idle transaction. */
|
||||
_createRouteTransaction(context) {
|
||||
if (!this._getCurrentHub) {
|
||||
DEBUG_BUILD &&
|
||||
logger.warn(`[Tracing] Did not create ${context.op} transaction because _getCurrentHub is invalid.`);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const hub = this._getCurrentHub();
|
||||
|
||||
const { beforeNavigate, idleTimeout, finalTimeout, heartbeatInterval } = this.options;
|
||||
|
||||
const isPageloadTransaction = context.op === 'pageload';
|
||||
|
||||
let expandedContext;
|
||||
if (isPageloadTransaction) {
|
||||
const sentryTrace = isPageloadTransaction ? getMetaContent('sentry-trace') : '';
|
||||
const baggage = isPageloadTransaction ? getMetaContent('baggage') : undefined;
|
||||
const { traceId, dsc, parentSpanId, sampled } = propagationContextFromHeaders(sentryTrace, baggage);
|
||||
expandedContext = {
|
||||
traceId,
|
||||
parentSpanId,
|
||||
parentSampled: sampled,
|
||||
...context,
|
||||
metadata: {
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
...context.metadata,
|
||||
dynamicSamplingContext: dsc,
|
||||
},
|
||||
trimEnd: true,
|
||||
};
|
||||
} else {
|
||||
expandedContext = {
|
||||
trimEnd: true,
|
||||
...context,
|
||||
};
|
||||
}
|
||||
|
||||
const modifiedContext = typeof beforeNavigate === 'function' ? beforeNavigate(expandedContext) : expandedContext;
|
||||
|
||||
// For backwards compatibility reasons, beforeNavigate can return undefined to "drop" the transaction (prevent it
|
||||
// from being sent to Sentry).
|
||||
const finalContext = modifiedContext === undefined ? { ...expandedContext, sampled: false } : modifiedContext;
|
||||
|
||||
// If `beforeNavigate` set a custom name, record that fact
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
finalContext.metadata =
|
||||
finalContext.name !== expandedContext.name
|
||||
? // eslint-disable-next-line deprecation/deprecation
|
||||
{ ...finalContext.metadata, source: 'custom' }
|
||||
: // eslint-disable-next-line deprecation/deprecation
|
||||
finalContext.metadata;
|
||||
|
||||
this._latestRoute.name = finalContext.name;
|
||||
this._latestRoute.context = finalContext;
|
||||
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
if (finalContext.sampled === false) {
|
||||
DEBUG_BUILD && logger.log(`[Tracing] Will not send ${finalContext.op} transaction because of beforeNavigate.`);
|
||||
}
|
||||
|
||||
DEBUG_BUILD && logger.log(`[Tracing] Starting ${finalContext.op} transaction on scope`);
|
||||
|
||||
const { location } = WINDOW;
|
||||
|
||||
const idleTransaction = startIdleTransaction(
|
||||
hub,
|
||||
finalContext,
|
||||
idleTimeout,
|
||||
finalTimeout,
|
||||
true,
|
||||
{ location }, // for use in the tracesSampler
|
||||
heartbeatInterval,
|
||||
isPageloadTransaction, // should wait for finish signal if it's a pageload transaction
|
||||
);
|
||||
|
||||
if (isPageloadTransaction) {
|
||||
if (WINDOW.document) {
|
||||
WINDOW.document.addEventListener('readystatechange', () => {
|
||||
if (['interactive', 'complete'].includes(WINDOW.document.readyState)) {
|
||||
idleTransaction.sendAutoFinishSignal();
|
||||
}
|
||||
});
|
||||
|
||||
if (['interactive', 'complete'].includes(WINDOW.document.readyState)) {
|
||||
idleTransaction.sendAutoFinishSignal();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
idleTransaction.registerBeforeFinishCallback(transaction => {
|
||||
this._collectWebVitals();
|
||||
addPerformanceEntries(transaction);
|
||||
});
|
||||
|
||||
return idleTransaction ;
|
||||
}
|
||||
|
||||
/** Start listener for interaction transactions */
|
||||
_registerInteractionListener() {
|
||||
let inflightInteractionTransaction;
|
||||
const registerInteractionTransaction = () => {
|
||||
const { idleTimeout, finalTimeout, heartbeatInterval } = this.options;
|
||||
const op = 'ui.action.click';
|
||||
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
const currentTransaction = getActiveTransaction();
|
||||
if (currentTransaction && currentTransaction.op && ['navigation', 'pageload'].includes(currentTransaction.op)) {
|
||||
DEBUG_BUILD &&
|
||||
logger.warn(
|
||||
`[Tracing] Did not create ${op} transaction because a pageload or navigation transaction is in progress.`,
|
||||
);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (inflightInteractionTransaction) {
|
||||
inflightInteractionTransaction.setFinishReason('interactionInterrupted');
|
||||
inflightInteractionTransaction.end();
|
||||
inflightInteractionTransaction = undefined;
|
||||
}
|
||||
|
||||
if (!this._getCurrentHub) {
|
||||
DEBUG_BUILD && logger.warn(`[Tracing] Did not create ${op} transaction because _getCurrentHub is invalid.`);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (!this._latestRoute.name) {
|
||||
DEBUG_BUILD && logger.warn(`[Tracing] Did not create ${op} transaction because _latestRouteName is missing.`);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const hub = this._getCurrentHub();
|
||||
const { location } = WINDOW;
|
||||
|
||||
const context = {
|
||||
name: this._latestRoute.name,
|
||||
op,
|
||||
trimEnd: true,
|
||||
data: {
|
||||
[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: this._latestRoute.context
|
||||
? getSource(this._latestRoute.context)
|
||||
: 'url',
|
||||
},
|
||||
};
|
||||
|
||||
inflightInteractionTransaction = startIdleTransaction(
|
||||
hub,
|
||||
context,
|
||||
idleTimeout,
|
||||
finalTimeout,
|
||||
true,
|
||||
{ location }, // for use in the tracesSampler
|
||||
heartbeatInterval,
|
||||
);
|
||||
};
|
||||
|
||||
['click'].forEach(type => {
|
||||
if (WINDOW.document) {
|
||||
addEventListener(type, registerInteractionTransaction, { once: false, capture: true });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/** Creates a listener on interaction entries, and maps interactionIds to the origin path of the interaction */
|
||||
_registerInpInteractionListener() {
|
||||
const handleEntries = ({ entries }) => {
|
||||
const client = getClient();
|
||||
// We need to get the replay, user, and activeTransaction from the current scope
|
||||
// so that we can associate replay id, profile id, and a user display to the span
|
||||
const replay =
|
||||
client !== undefined && client.getIntegrationByName !== undefined
|
||||
? (client.getIntegrationByName('Replay') )
|
||||
: undefined;
|
||||
const replayId = replay !== undefined ? replay.getReplayId() : undefined;
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
const activeTransaction = getActiveTransaction();
|
||||
const currentScope = getCurrentScope();
|
||||
const user = currentScope !== undefined ? currentScope.getUser() : undefined;
|
||||
entries.forEach(entry => {
|
||||
if (isPerformanceEventTiming(entry)) {
|
||||
const interactionId = entry.interactionId;
|
||||
if (interactionId === undefined) {
|
||||
return;
|
||||
}
|
||||
const existingInteraction = this._interactionIdToRouteNameMapping[interactionId];
|
||||
const duration = entry.duration;
|
||||
const startTime = entry.startTime;
|
||||
const keys = Object.keys(this._interactionIdToRouteNameMapping);
|
||||
const minInteractionId =
|
||||
keys.length > 0
|
||||
? keys.reduce((a, b) => {
|
||||
return this._interactionIdToRouteNameMapping[a].duration <
|
||||
this._interactionIdToRouteNameMapping[b].duration
|
||||
? a
|
||||
: b;
|
||||
})
|
||||
: undefined;
|
||||
// For a first input event to be considered, we must check that an interaction event does not already exist with the same duration and start time.
|
||||
// This is also checked in the web-vitals library.
|
||||
if (entry.entryType === 'first-input') {
|
||||
const matchingEntry = keys
|
||||
.map(key => this._interactionIdToRouteNameMapping[key])
|
||||
.some(interaction => {
|
||||
return interaction.duration === duration && interaction.startTime === startTime;
|
||||
});
|
||||
if (matchingEntry) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Interactions with an id of 0 and are not first-input are not valid.
|
||||
if (!interactionId) {
|
||||
return;
|
||||
}
|
||||
// If the interaction already exists, we want to use the duration of the longest entry, since that is what the INP metric uses.
|
||||
if (existingInteraction) {
|
||||
existingInteraction.duration = Math.max(existingInteraction.duration, duration);
|
||||
} else if (
|
||||
keys.length < MAX_INTERACTIONS ||
|
||||
minInteractionId === undefined ||
|
||||
duration > this._interactionIdToRouteNameMapping[minInteractionId].duration
|
||||
) {
|
||||
// If the interaction does not exist, we want to add it to the mapping if there is space, or if the duration is longer than the shortest entry.
|
||||
const routeName = this._latestRoute.name;
|
||||
const parentContext = this._latestRoute.context;
|
||||
if (routeName && parentContext) {
|
||||
if (minInteractionId && Object.keys(this._interactionIdToRouteNameMapping).length >= MAX_INTERACTIONS) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
|
||||
delete this._interactionIdToRouteNameMapping[minInteractionId];
|
||||
}
|
||||
this._interactionIdToRouteNameMapping[interactionId] = {
|
||||
routeName,
|
||||
duration,
|
||||
parentContext,
|
||||
user,
|
||||
activeTransaction,
|
||||
replayId,
|
||||
startTime,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
addPerformanceInstrumentationHandler('event', handleEntries);
|
||||
addPerformanceInstrumentationHandler('first-input', handleEntries);
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns the value of a meta tag */
|
||||
function getMetaContent(metaName) {
|
||||
// Can't specify generic to `getDomElement` because tracing can be used
|
||||
// in a variety of environments, have to disable `no-unsafe-member-access`
|
||||
// as a result.
|
||||
const metaTag = getDomElement(`meta[name=${metaName}]`);
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
||||
return metaTag ? metaTag.getAttribute('content') : undefined;
|
||||
}
|
||||
|
||||
function getSource(context) {
|
||||
const sourceFromAttributes = context.attributes && context.attributes[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE];
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
const sourceFromData = context.data && context.data[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE];
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
const sourceFromMetadata = context.metadata && context.metadata.source;
|
||||
|
||||
return sourceFromAttributes || sourceFromData || sourceFromMetadata;
|
||||
}
|
||||
|
||||
function isPerformanceEventTiming(entry) {
|
||||
return 'duration' in entry;
|
||||
}
|
||||
|
||||
export { BROWSER_TRACING_INTEGRATION_ID, BrowserTracing, getMetaContent };
|
||||
//# sourceMappingURL=browsertracing.js.map
|
||||
1
node_modules/@sentry-internal/tracing/esm/browser/browsertracing.js.map
generated
vendored
Normal file
1
node_modules/@sentry-internal/tracing/esm/browser/browsertracing.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
230
node_modules/@sentry-internal/tracing/esm/browser/instrument.js
generated
vendored
Normal file
230
node_modules/@sentry-internal/tracing/esm/browser/instrument.js
generated
vendored
Normal file
@@ -0,0 +1,230 @@
|
||||
import { logger, getFunctionName } from '@sentry/utils';
|
||||
import { DEBUG_BUILD } from '../common/debug-build.js';
|
||||
import { onCLS } from './web-vitals/getCLS.js';
|
||||
import { onFID } from './web-vitals/getFID.js';
|
||||
import { onINP } from './web-vitals/getINP.js';
|
||||
import { onLCP } from './web-vitals/getLCP.js';
|
||||
import { observe } from './web-vitals/lib/observe.js';
|
||||
import { onTTFB } from './web-vitals/onTTFB.js';
|
||||
|
||||
const handlers = {};
|
||||
const instrumented = {};
|
||||
|
||||
let _previousCls;
|
||||
let _previousFid;
|
||||
let _previousLcp;
|
||||
let _previousTtfb;
|
||||
let _previousInp;
|
||||
|
||||
/**
|
||||
* Add a callback that will be triggered when a CLS metric is available.
|
||||
* Returns a cleanup callback which can be called to remove the instrumentation handler.
|
||||
*
|
||||
* Pass `stopOnCallback = true` to stop listening for CLS when the cleanup callback is called.
|
||||
* This will lead to the CLS being finalized and frozen.
|
||||
*/
|
||||
function addClsInstrumentationHandler(
|
||||
callback,
|
||||
stopOnCallback = false,
|
||||
) {
|
||||
return addMetricObserver('cls', callback, instrumentCls, _previousCls, stopOnCallback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a callback that will be triggered when a LCP metric is available.
|
||||
* Returns a cleanup callback which can be called to remove the instrumentation handler.
|
||||
*
|
||||
* Pass `stopOnCallback = true` to stop listening for LCP when the cleanup callback is called.
|
||||
* This will lead to the LCP being finalized and frozen.
|
||||
*/
|
||||
function addLcpInstrumentationHandler(
|
||||
callback,
|
||||
stopOnCallback = false,
|
||||
) {
|
||||
return addMetricObserver('lcp', callback, instrumentLcp, _previousLcp, stopOnCallback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a callback that will be triggered when a FID metric is available.
|
||||
*/
|
||||
function addTtfbInstrumentationHandler(callback) {
|
||||
return addMetricObserver('ttfb', callback, instrumentTtfb, _previousTtfb);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a callback that will be triggered when a FID metric is available.
|
||||
* Returns a cleanup callback which can be called to remove the instrumentation handler.
|
||||
*/
|
||||
function addFidInstrumentationHandler(callback) {
|
||||
return addMetricObserver('fid', callback, instrumentFid, _previousFid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a callback that will be triggered when a INP metric is available.
|
||||
* Returns a cleanup callback which can be called to remove the instrumentation handler.
|
||||
*/
|
||||
function addInpInstrumentationHandler(
|
||||
callback,
|
||||
) {
|
||||
return addMetricObserver('inp', callback, instrumentInp, _previousInp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a callback that will be triggered when a performance observer is triggered,
|
||||
* and receives the entries of the observer.
|
||||
* Returns a cleanup callback which can be called to remove the instrumentation handler.
|
||||
*/
|
||||
function addPerformanceInstrumentationHandler(
|
||||
type,
|
||||
callback,
|
||||
) {
|
||||
addHandler(type, callback);
|
||||
|
||||
if (!instrumented[type]) {
|
||||
instrumentPerformanceObserver(type);
|
||||
instrumented[type] = true;
|
||||
}
|
||||
|
||||
return getCleanupCallback(type, callback);
|
||||
}
|
||||
|
||||
/** Trigger all handlers of a given type. */
|
||||
function triggerHandlers(type, data) {
|
||||
const typeHandlers = handlers[type];
|
||||
|
||||
if (!typeHandlers || !typeHandlers.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const handler of typeHandlers) {
|
||||
try {
|
||||
handler(data);
|
||||
} catch (e) {
|
||||
DEBUG_BUILD &&
|
||||
logger.error(
|
||||
`Error while triggering instrumentation handler.\nType: ${type}\nName: ${getFunctionName(handler)}\nError:`,
|
||||
e,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function instrumentCls() {
|
||||
return onCLS(
|
||||
metric => {
|
||||
triggerHandlers('cls', {
|
||||
metric,
|
||||
});
|
||||
_previousCls = metric;
|
||||
},
|
||||
{ reportAllChanges: true },
|
||||
);
|
||||
}
|
||||
|
||||
function instrumentFid() {
|
||||
return onFID(metric => {
|
||||
triggerHandlers('fid', {
|
||||
metric,
|
||||
});
|
||||
_previousFid = metric;
|
||||
});
|
||||
}
|
||||
|
||||
function instrumentLcp() {
|
||||
return onLCP(metric => {
|
||||
triggerHandlers('lcp', {
|
||||
metric,
|
||||
});
|
||||
_previousLcp = metric;
|
||||
});
|
||||
}
|
||||
|
||||
function instrumentTtfb() {
|
||||
return onTTFB(metric => {
|
||||
triggerHandlers('ttfb', {
|
||||
metric,
|
||||
});
|
||||
_previousTtfb = metric;
|
||||
});
|
||||
}
|
||||
|
||||
function instrumentInp() {
|
||||
return onINP(metric => {
|
||||
triggerHandlers('inp', {
|
||||
metric,
|
||||
});
|
||||
_previousInp = metric;
|
||||
});
|
||||
}
|
||||
|
||||
function addMetricObserver(
|
||||
type,
|
||||
callback,
|
||||
instrumentFn,
|
||||
previousValue,
|
||||
stopOnCallback = false,
|
||||
) {
|
||||
addHandler(type, callback);
|
||||
|
||||
let stopListening;
|
||||
|
||||
if (!instrumented[type]) {
|
||||
stopListening = instrumentFn();
|
||||
instrumented[type] = true;
|
||||
}
|
||||
|
||||
if (previousValue) {
|
||||
callback({ metric: previousValue });
|
||||
}
|
||||
|
||||
return getCleanupCallback(type, callback, stopOnCallback ? stopListening : undefined);
|
||||
}
|
||||
|
||||
function instrumentPerformanceObserver(type) {
|
||||
const options = {};
|
||||
|
||||
// Special per-type options we want to use
|
||||
if (type === 'event') {
|
||||
options.durationThreshold = 0;
|
||||
}
|
||||
|
||||
observe(
|
||||
type,
|
||||
entries => {
|
||||
triggerHandlers(type, { entries });
|
||||
},
|
||||
options,
|
||||
);
|
||||
}
|
||||
|
||||
function addHandler(type, handler) {
|
||||
handlers[type] = handlers[type] || [];
|
||||
(handlers[type] ).push(handler);
|
||||
}
|
||||
|
||||
// Get a callback which can be called to remove the instrumentation handler
|
||||
function getCleanupCallback(
|
||||
type,
|
||||
callback,
|
||||
stopListening,
|
||||
) {
|
||||
return () => {
|
||||
if (stopListening) {
|
||||
stopListening();
|
||||
}
|
||||
|
||||
const typeHandlers = handlers[type];
|
||||
|
||||
if (!typeHandlers) {
|
||||
return;
|
||||
}
|
||||
|
||||
const index = typeHandlers.indexOf(callback);
|
||||
if (index !== -1) {
|
||||
typeHandlers.splice(index, 1);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export { addClsInstrumentationHandler, addFidInstrumentationHandler, addInpInstrumentationHandler, addLcpInstrumentationHandler, addPerformanceInstrumentationHandler, addTtfbInstrumentationHandler };
|
||||
//# sourceMappingURL=instrument.js.map
|
||||
1
node_modules/@sentry-internal/tracing/esm/browser/instrument.js.map
generated
vendored
Normal file
1
node_modules/@sentry-internal/tracing/esm/browser/instrument.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
706
node_modules/@sentry-internal/tracing/esm/browser/metrics/index.js
generated
vendored
Normal file
706
node_modules/@sentry-internal/tracing/esm/browser/metrics/index.js
generated
vendored
Normal file
@@ -0,0 +1,706 @@
|
||||
import { getActiveTransaction, spanToJSON, setMeasurement, getClient, Span, createSpanEnvelope, hasTracingEnabled, isValidSampleRate } from '@sentry/core';
|
||||
import { browserPerformanceTimeOrigin, htmlTreeAsString, getComponentName, logger, parseUrl } from '@sentry/utils';
|
||||
import { DEBUG_BUILD } from '../../common/debug-build.js';
|
||||
import { addPerformanceInstrumentationHandler, addClsInstrumentationHandler, addLcpInstrumentationHandler, addFidInstrumentationHandler, addTtfbInstrumentationHandler, addInpInstrumentationHandler } from '../instrument.js';
|
||||
import { WINDOW } from '../types.js';
|
||||
import { getVisibilityWatcher } from '../web-vitals/lib/getVisibilityWatcher.js';
|
||||
import { _startChild, isMeasurementValue } from './utils.js';
|
||||
import { getNavigationEntry } from '../web-vitals/lib/getNavigationEntry.js';
|
||||
|
||||
const MAX_INT_AS_BYTES = 2147483647;
|
||||
|
||||
/**
|
||||
* Converts from milliseconds to seconds
|
||||
* @param time time in ms
|
||||
*/
|
||||
function msToSec(time) {
|
||||
return time / 1000;
|
||||
}
|
||||
|
||||
function getBrowserPerformanceAPI() {
|
||||
// @ts-expect-error we want to make sure all of these are available, even if TS is sure they are
|
||||
return WINDOW && WINDOW.addEventListener && WINDOW.performance;
|
||||
}
|
||||
|
||||
let _performanceCursor = 0;
|
||||
|
||||
let _measurements = {};
|
||||
let _lcpEntry;
|
||||
let _clsEntry;
|
||||
|
||||
/**
|
||||
* Start tracking web vitals.
|
||||
* The callback returned by this function can be used to stop tracking & ensure all measurements are final & captured.
|
||||
*
|
||||
* @returns A function that forces web vitals collection
|
||||
*/
|
||||
function startTrackingWebVitals() {
|
||||
const performance = getBrowserPerformanceAPI();
|
||||
if (performance && browserPerformanceTimeOrigin) {
|
||||
// @ts-expect-error we want to make sure all of these are available, even if TS is sure they are
|
||||
if (performance.mark) {
|
||||
WINDOW.performance.mark('sentry-tracing-init');
|
||||
}
|
||||
const fidCallback = _trackFID();
|
||||
const clsCallback = _trackCLS();
|
||||
const lcpCallback = _trackLCP();
|
||||
const ttfbCallback = _trackTtfb();
|
||||
|
||||
return () => {
|
||||
fidCallback();
|
||||
clsCallback();
|
||||
lcpCallback();
|
||||
ttfbCallback();
|
||||
};
|
||||
}
|
||||
|
||||
return () => undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start tracking long tasks.
|
||||
*/
|
||||
function startTrackingLongTasks() {
|
||||
addPerformanceInstrumentationHandler('longtask', ({ entries }) => {
|
||||
for (const entry of entries) {
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
const transaction = getActiveTransaction() ;
|
||||
if (!transaction) {
|
||||
return;
|
||||
}
|
||||
const startTime = msToSec((browserPerformanceTimeOrigin ) + entry.startTime);
|
||||
const duration = msToSec(entry.duration);
|
||||
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
transaction.startChild({
|
||||
description: 'Main UI thread blocked',
|
||||
op: 'ui.long-task',
|
||||
origin: 'auto.ui.browser.metrics',
|
||||
startTimestamp: startTime,
|
||||
endTimestamp: startTime + duration,
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Start tracking interaction events.
|
||||
*/
|
||||
function startTrackingInteractions() {
|
||||
addPerformanceInstrumentationHandler('event', ({ entries }) => {
|
||||
for (const entry of entries) {
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
const transaction = getActiveTransaction() ;
|
||||
if (!transaction) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (entry.name === 'click') {
|
||||
const startTime = msToSec((browserPerformanceTimeOrigin ) + entry.startTime);
|
||||
const duration = msToSec(entry.duration);
|
||||
|
||||
const span = {
|
||||
description: htmlTreeAsString(entry.target),
|
||||
op: `ui.interaction.${entry.name}`,
|
||||
origin: 'auto.ui.browser.metrics',
|
||||
startTimestamp: startTime,
|
||||
endTimestamp: startTime + duration,
|
||||
};
|
||||
|
||||
const componentName = getComponentName(entry.target);
|
||||
if (componentName) {
|
||||
span.attributes = { 'ui.component_name': componentName };
|
||||
}
|
||||
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
transaction.startChild(span);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Start tracking INP webvital events.
|
||||
*/
|
||||
function startTrackingINP(
|
||||
interactionIdtoRouteNameMapping,
|
||||
interactionsSampleRate,
|
||||
) {
|
||||
const performance = getBrowserPerformanceAPI();
|
||||
if (performance && browserPerformanceTimeOrigin) {
|
||||
const inpCallback = _trackINP(interactionIdtoRouteNameMapping, interactionsSampleRate);
|
||||
|
||||
return () => {
|
||||
inpCallback();
|
||||
};
|
||||
}
|
||||
|
||||
return () => undefined;
|
||||
}
|
||||
|
||||
/** Starts tracking the Cumulative Layout Shift on the current page. */
|
||||
function _trackCLS() {
|
||||
return addClsInstrumentationHandler(({ metric }) => {
|
||||
const entry = metric.entries[metric.entries.length - 1];
|
||||
if (!entry) {
|
||||
return;
|
||||
}
|
||||
|
||||
DEBUG_BUILD && logger.log('[Measurements] Adding CLS');
|
||||
_measurements['cls'] = { value: metric.value, unit: '' };
|
||||
_clsEntry = entry ;
|
||||
}, true);
|
||||
}
|
||||
|
||||
/** Starts tracking the Largest Contentful Paint on the current page. */
|
||||
function _trackLCP() {
|
||||
return addLcpInstrumentationHandler(({ metric }) => {
|
||||
const entry = metric.entries[metric.entries.length - 1];
|
||||
if (!entry) {
|
||||
return;
|
||||
}
|
||||
|
||||
DEBUG_BUILD && logger.log('[Measurements] Adding LCP');
|
||||
_measurements['lcp'] = { value: metric.value, unit: 'millisecond' };
|
||||
_lcpEntry = entry ;
|
||||
}, true);
|
||||
}
|
||||
|
||||
/** Starts tracking the First Input Delay on the current page. */
|
||||
function _trackFID() {
|
||||
return addFidInstrumentationHandler(({ metric }) => {
|
||||
const entry = metric.entries[metric.entries.length - 1];
|
||||
if (!entry) {
|
||||
return;
|
||||
}
|
||||
|
||||
const timeOrigin = msToSec(browserPerformanceTimeOrigin );
|
||||
const startTime = msToSec(entry.startTime);
|
||||
DEBUG_BUILD && logger.log('[Measurements] Adding FID');
|
||||
_measurements['fid'] = { value: metric.value, unit: 'millisecond' };
|
||||
_measurements['mark.fid'] = { value: timeOrigin + startTime, unit: 'second' };
|
||||
});
|
||||
}
|
||||
|
||||
function _trackTtfb() {
|
||||
return addTtfbInstrumentationHandler(({ metric }) => {
|
||||
const entry = metric.entries[metric.entries.length - 1];
|
||||
if (!entry) {
|
||||
return;
|
||||
}
|
||||
|
||||
DEBUG_BUILD && logger.log('[Measurements] Adding TTFB');
|
||||
_measurements['ttfb'] = { value: metric.value, unit: 'millisecond' };
|
||||
});
|
||||
}
|
||||
|
||||
const INP_ENTRY_MAP = {
|
||||
click: 'click',
|
||||
pointerdown: 'click',
|
||||
pointerup: 'click',
|
||||
mousedown: 'click',
|
||||
mouseup: 'click',
|
||||
touchstart: 'click',
|
||||
touchend: 'click',
|
||||
mouseover: 'hover',
|
||||
mouseout: 'hover',
|
||||
mouseenter: 'hover',
|
||||
mouseleave: 'hover',
|
||||
pointerover: 'hover',
|
||||
pointerout: 'hover',
|
||||
pointerenter: 'hover',
|
||||
pointerleave: 'hover',
|
||||
dragstart: 'drag',
|
||||
dragend: 'drag',
|
||||
drag: 'drag',
|
||||
dragenter: 'drag',
|
||||
dragleave: 'drag',
|
||||
dragover: 'drag',
|
||||
drop: 'drag',
|
||||
keydown: 'press',
|
||||
keyup: 'press',
|
||||
keypress: 'press',
|
||||
input: 'press',
|
||||
};
|
||||
|
||||
/** Starts tracking the Interaction to Next Paint on the current page. */
|
||||
function _trackINP(
|
||||
interactionIdToRouteNameMapping,
|
||||
interactionsSampleRate,
|
||||
) {
|
||||
return addInpInstrumentationHandler(({ metric }) => {
|
||||
if (metric.value === undefined) {
|
||||
return;
|
||||
}
|
||||
const entry = metric.entries.find(
|
||||
entry => entry.duration === metric.value && INP_ENTRY_MAP[entry.name] !== undefined,
|
||||
);
|
||||
const client = getClient();
|
||||
if (!entry || !client) {
|
||||
return;
|
||||
}
|
||||
const interactionType = INP_ENTRY_MAP[entry.name];
|
||||
const options = client.getOptions();
|
||||
/** Build the INP span, create an envelope from the span, and then send the envelope */
|
||||
const startTime = msToSec((browserPerformanceTimeOrigin ) + entry.startTime);
|
||||
const duration = msToSec(metric.value);
|
||||
const interaction =
|
||||
entry.interactionId !== undefined ? interactionIdToRouteNameMapping[entry.interactionId] : undefined;
|
||||
if (interaction === undefined) {
|
||||
return;
|
||||
}
|
||||
const { routeName, parentContext, activeTransaction, user, replayId } = interaction;
|
||||
const userDisplay = user !== undefined ? user.email || user.id || user.ip_address : undefined;
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
const profileId = activeTransaction !== undefined ? activeTransaction.getProfileId() : undefined;
|
||||
const span = new Span({
|
||||
startTimestamp: startTime,
|
||||
endTimestamp: startTime + duration,
|
||||
op: `ui.interaction.${interactionType}`,
|
||||
name: htmlTreeAsString(entry.target),
|
||||
attributes: {
|
||||
release: options.release,
|
||||
environment: options.environment,
|
||||
transaction: routeName,
|
||||
...(userDisplay !== undefined && userDisplay !== '' ? { user: userDisplay } : {}),
|
||||
...(profileId !== undefined ? { profile_id: profileId } : {}),
|
||||
...(replayId !== undefined ? { replay_id: replayId } : {}),
|
||||
},
|
||||
exclusiveTime: metric.value,
|
||||
measurements: {
|
||||
inp: { value: metric.value, unit: 'millisecond' },
|
||||
},
|
||||
});
|
||||
|
||||
/** Check to see if the span should be sampled */
|
||||
const sampleRate = getSampleRate(parentContext, options, interactionsSampleRate);
|
||||
|
||||
if (!sampleRate) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (Math.random() < (sampleRate )) {
|
||||
const envelope = span ? createSpanEnvelope([span], client.getDsn()) : undefined;
|
||||
const transport = client && client.getTransport();
|
||||
if (transport && envelope) {
|
||||
transport.send(envelope).then(null, reason => {
|
||||
DEBUG_BUILD && logger.error('Error while sending interaction:', reason);
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/** Add performance related spans to a transaction */
|
||||
function addPerformanceEntries(transaction) {
|
||||
const performance = getBrowserPerformanceAPI();
|
||||
if (!performance || !WINDOW.performance.getEntries || !browserPerformanceTimeOrigin) {
|
||||
// Gatekeeper if performance API not available
|
||||
return;
|
||||
}
|
||||
|
||||
DEBUG_BUILD && logger.log('[Tracing] Adding & adjusting spans using Performance API');
|
||||
const timeOrigin = msToSec(browserPerformanceTimeOrigin);
|
||||
|
||||
const performanceEntries = performance.getEntries();
|
||||
|
||||
const { op, start_timestamp: transactionStartTime } = spanToJSON(transaction);
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
performanceEntries.slice(_performanceCursor).forEach((entry) => {
|
||||
const startTime = msToSec(entry.startTime);
|
||||
const duration = msToSec(entry.duration);
|
||||
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
if (transaction.op === 'navigation' && transactionStartTime && timeOrigin + startTime < transactionStartTime) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (entry.entryType) {
|
||||
case 'navigation': {
|
||||
_addNavigationSpans(transaction, entry, timeOrigin);
|
||||
break;
|
||||
}
|
||||
case 'mark':
|
||||
case 'paint':
|
||||
case 'measure': {
|
||||
_addMeasureSpans(transaction, entry, startTime, duration, timeOrigin);
|
||||
|
||||
// capture web vitals
|
||||
const firstHidden = getVisibilityWatcher();
|
||||
// Only report if the page wasn't hidden prior to the web vital.
|
||||
const shouldRecord = entry.startTime < firstHidden.firstHiddenTime;
|
||||
|
||||
if (entry.name === 'first-paint' && shouldRecord) {
|
||||
DEBUG_BUILD && logger.log('[Measurements] Adding FP');
|
||||
_measurements['fp'] = { value: entry.startTime, unit: 'millisecond' };
|
||||
}
|
||||
if (entry.name === 'first-contentful-paint' && shouldRecord) {
|
||||
DEBUG_BUILD && logger.log('[Measurements] Adding FCP');
|
||||
_measurements['fcp'] = { value: entry.startTime, unit: 'millisecond' };
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'resource': {
|
||||
_addResourceSpans(transaction, entry, entry.name , startTime, duration, timeOrigin);
|
||||
break;
|
||||
}
|
||||
// Ignore other entry types.
|
||||
}
|
||||
});
|
||||
|
||||
_performanceCursor = Math.max(performanceEntries.length - 1, 0);
|
||||
|
||||
_trackNavigator(transaction);
|
||||
|
||||
// Measurements are only available for pageload transactions
|
||||
if (op === 'pageload') {
|
||||
_addTtfbRequestTimeToMeasurements(_measurements);
|
||||
|
||||
['fcp', 'fp', 'lcp'].forEach(name => {
|
||||
if (!_measurements[name] || !transactionStartTime || timeOrigin >= transactionStartTime) {
|
||||
return;
|
||||
}
|
||||
// The web vitals, fcp, fp, lcp, and ttfb, all measure relative to timeOrigin.
|
||||
// Unfortunately, timeOrigin is not captured within the transaction span data, so these web vitals will need
|
||||
// to be adjusted to be relative to transaction.startTimestamp.
|
||||
const oldValue = _measurements[name].value;
|
||||
const measurementTimestamp = timeOrigin + msToSec(oldValue);
|
||||
|
||||
// normalizedValue should be in milliseconds
|
||||
const normalizedValue = Math.abs((measurementTimestamp - transactionStartTime) * 1000);
|
||||
const delta = normalizedValue - oldValue;
|
||||
|
||||
DEBUG_BUILD && logger.log(`[Measurements] Normalized ${name} from ${oldValue} to ${normalizedValue} (${delta})`);
|
||||
_measurements[name].value = normalizedValue;
|
||||
});
|
||||
|
||||
const fidMark = _measurements['mark.fid'];
|
||||
if (fidMark && _measurements['fid']) {
|
||||
// create span for FID
|
||||
_startChild(transaction, {
|
||||
description: 'first input delay',
|
||||
endTimestamp: fidMark.value + msToSec(_measurements['fid'].value),
|
||||
op: 'ui.action',
|
||||
origin: 'auto.ui.browser.metrics',
|
||||
startTimestamp: fidMark.value,
|
||||
});
|
||||
|
||||
// Delete mark.fid as we don't want it to be part of final payload
|
||||
delete _measurements['mark.fid'];
|
||||
}
|
||||
|
||||
// If FCP is not recorded we should not record the cls value
|
||||
// according to the new definition of CLS.
|
||||
if (!('fcp' in _measurements)) {
|
||||
delete _measurements.cls;
|
||||
}
|
||||
|
||||
Object.keys(_measurements).forEach(measurementName => {
|
||||
setMeasurement(measurementName, _measurements[measurementName].value, _measurements[measurementName].unit);
|
||||
});
|
||||
|
||||
_tagMetricInfo(transaction);
|
||||
}
|
||||
|
||||
_lcpEntry = undefined;
|
||||
_clsEntry = undefined;
|
||||
_measurements = {};
|
||||
}
|
||||
|
||||
/** Create measure related spans */
|
||||
function _addMeasureSpans(
|
||||
transaction,
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
entry,
|
||||
startTime,
|
||||
duration,
|
||||
timeOrigin,
|
||||
) {
|
||||
const measureStartTimestamp = timeOrigin + startTime;
|
||||
const measureEndTimestamp = measureStartTimestamp + duration;
|
||||
|
||||
_startChild(transaction, {
|
||||
description: entry.name ,
|
||||
endTimestamp: measureEndTimestamp,
|
||||
op: entry.entryType ,
|
||||
origin: 'auto.resource.browser.metrics',
|
||||
startTimestamp: measureStartTimestamp,
|
||||
});
|
||||
|
||||
return measureStartTimestamp;
|
||||
}
|
||||
|
||||
/** Instrument navigation entries */
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
function _addNavigationSpans(transaction, entry, timeOrigin) {
|
||||
['unloadEvent', 'redirect', 'domContentLoadedEvent', 'loadEvent', 'connect'].forEach(event => {
|
||||
_addPerformanceNavigationTiming(transaction, entry, event, timeOrigin);
|
||||
});
|
||||
_addPerformanceNavigationTiming(transaction, entry, 'secureConnection', timeOrigin, 'TLS/SSL', 'connectEnd');
|
||||
_addPerformanceNavigationTiming(transaction, entry, 'fetch', timeOrigin, 'cache', 'domainLookupStart');
|
||||
_addPerformanceNavigationTiming(transaction, entry, 'domainLookup', timeOrigin, 'DNS');
|
||||
_addRequest(transaction, entry, timeOrigin);
|
||||
}
|
||||
|
||||
/** Create performance navigation related spans */
|
||||
function _addPerformanceNavigationTiming(
|
||||
transaction,
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
entry,
|
||||
event,
|
||||
timeOrigin,
|
||||
description,
|
||||
eventEnd,
|
||||
) {
|
||||
const end = eventEnd ? (entry[eventEnd] ) : (entry[`${event}End`] );
|
||||
const start = entry[`${event}Start`] ;
|
||||
if (!start || !end) {
|
||||
return;
|
||||
}
|
||||
_startChild(transaction, {
|
||||
op: 'browser',
|
||||
origin: 'auto.browser.browser.metrics',
|
||||
description: description || event,
|
||||
startTimestamp: timeOrigin + msToSec(start),
|
||||
endTimestamp: timeOrigin + msToSec(end),
|
||||
});
|
||||
}
|
||||
|
||||
/** Create request and response related spans */
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
function _addRequest(transaction, entry, timeOrigin) {
|
||||
if (entry.responseEnd) {
|
||||
// It is possible that we are collecting these metrics when the page hasn't finished loading yet, for example when the HTML slowly streams in.
|
||||
// In this case, ie. when the document request hasn't finished yet, `entry.responseEnd` will be 0.
|
||||
// In order not to produce faulty spans, where the end timestamp is before the start timestamp, we will only collect
|
||||
// these spans when the responseEnd value is available. The backend (Relay) would drop the entire transaction if it contained faulty spans.
|
||||
_startChild(transaction, {
|
||||
op: 'browser',
|
||||
origin: 'auto.browser.browser.metrics',
|
||||
description: 'request',
|
||||
startTimestamp: timeOrigin + msToSec(entry.requestStart ),
|
||||
endTimestamp: timeOrigin + msToSec(entry.responseEnd ),
|
||||
});
|
||||
|
||||
_startChild(transaction, {
|
||||
op: 'browser',
|
||||
origin: 'auto.browser.browser.metrics',
|
||||
description: 'response',
|
||||
startTimestamp: timeOrigin + msToSec(entry.responseStart ),
|
||||
endTimestamp: timeOrigin + msToSec(entry.responseEnd ),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/** Create resource-related spans */
|
||||
function _addResourceSpans(
|
||||
transaction,
|
||||
entry,
|
||||
resourceUrl,
|
||||
startTime,
|
||||
duration,
|
||||
timeOrigin,
|
||||
) {
|
||||
// we already instrument based on fetch and xhr, so we don't need to
|
||||
// duplicate spans here.
|
||||
if (entry.initiatorType === 'xmlhttprequest' || entry.initiatorType === 'fetch') {
|
||||
return;
|
||||
}
|
||||
|
||||
const parsedUrl = parseUrl(resourceUrl);
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const data = {};
|
||||
setResourceEntrySizeData(data, entry, 'transferSize', 'http.response_transfer_size');
|
||||
setResourceEntrySizeData(data, entry, 'encodedBodySize', 'http.response_content_length');
|
||||
setResourceEntrySizeData(data, entry, 'decodedBodySize', 'http.decoded_response_content_length');
|
||||
|
||||
if ('renderBlockingStatus' in entry) {
|
||||
data['resource.render_blocking_status'] = entry.renderBlockingStatus;
|
||||
}
|
||||
if (parsedUrl.protocol) {
|
||||
data['url.scheme'] = parsedUrl.protocol.split(':').pop(); // the protocol returned by parseUrl includes a :, but OTEL spec does not, so we remove it.
|
||||
}
|
||||
|
||||
if (parsedUrl.host) {
|
||||
data['server.address'] = parsedUrl.host;
|
||||
}
|
||||
|
||||
data['url.same_origin'] = resourceUrl.includes(WINDOW.location.origin);
|
||||
|
||||
const startTimestamp = timeOrigin + startTime;
|
||||
const endTimestamp = startTimestamp + duration;
|
||||
|
||||
_startChild(transaction, {
|
||||
description: resourceUrl.replace(WINDOW.location.origin, ''),
|
||||
endTimestamp,
|
||||
op: entry.initiatorType ? `resource.${entry.initiatorType}` : 'resource.other',
|
||||
origin: 'auto.resource.browser.metrics',
|
||||
startTimestamp,
|
||||
data,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Capture the information of the user agent.
|
||||
*/
|
||||
function _trackNavigator(transaction) {
|
||||
const navigator = WINDOW.navigator ;
|
||||
if (!navigator) {
|
||||
return;
|
||||
}
|
||||
|
||||
// track network connectivity
|
||||
const connection = navigator.connection;
|
||||
if (connection) {
|
||||
if (connection.effectiveType) {
|
||||
// TODO: Can we rewrite this to an attribute?
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
transaction.setTag('effectiveConnectionType', connection.effectiveType);
|
||||
}
|
||||
|
||||
if (connection.type) {
|
||||
// TODO: Can we rewrite this to an attribute?
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
transaction.setTag('connectionType', connection.type);
|
||||
}
|
||||
|
||||
if (isMeasurementValue(connection.rtt)) {
|
||||
_measurements['connection.rtt'] = { value: connection.rtt, unit: 'millisecond' };
|
||||
}
|
||||
}
|
||||
|
||||
if (isMeasurementValue(navigator.deviceMemory)) {
|
||||
// TODO: Can we rewrite this to an attribute?
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
transaction.setTag('deviceMemory', `${navigator.deviceMemory} GB`);
|
||||
}
|
||||
|
||||
if (isMeasurementValue(navigator.hardwareConcurrency)) {
|
||||
// TODO: Can we rewrite this to an attribute?
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
transaction.setTag('hardwareConcurrency', String(navigator.hardwareConcurrency));
|
||||
}
|
||||
}
|
||||
|
||||
/** Add LCP / CLS data to transaction to allow debugging */
|
||||
function _tagMetricInfo(transaction) {
|
||||
if (_lcpEntry) {
|
||||
DEBUG_BUILD && logger.log('[Measurements] Adding LCP Data');
|
||||
|
||||
// Capture Properties of the LCP element that contributes to the LCP.
|
||||
|
||||
if (_lcpEntry.element) {
|
||||
// TODO: Can we rewrite this to an attribute?
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
transaction.setTag('lcp.element', htmlTreeAsString(_lcpEntry.element));
|
||||
}
|
||||
|
||||
if (_lcpEntry.id) {
|
||||
// TODO: Can we rewrite this to an attribute?
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
transaction.setTag('lcp.id', _lcpEntry.id);
|
||||
}
|
||||
|
||||
if (_lcpEntry.url) {
|
||||
// Trim URL to the first 200 characters.
|
||||
// TODO: Can we rewrite this to an attribute?
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
transaction.setTag('lcp.url', _lcpEntry.url.trim().slice(0, 200));
|
||||
}
|
||||
|
||||
// TODO: Can we rewrite this to an attribute?
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
transaction.setTag('lcp.size', _lcpEntry.size);
|
||||
}
|
||||
|
||||
// See: https://developer.mozilla.org/en-US/docs/Web/API/LayoutShift
|
||||
if (_clsEntry && _clsEntry.sources) {
|
||||
DEBUG_BUILD && logger.log('[Measurements] Adding CLS Data');
|
||||
_clsEntry.sources.forEach((source, index) =>
|
||||
// TODO: Can we rewrite this to an attribute?
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
transaction.setTag(`cls.source.${index + 1}`, htmlTreeAsString(source.node)),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function setResourceEntrySizeData(
|
||||
data,
|
||||
entry,
|
||||
key,
|
||||
dataKey,
|
||||
) {
|
||||
const entryVal = entry[key];
|
||||
if (entryVal != null && entryVal < MAX_INT_AS_BYTES) {
|
||||
data[dataKey] = entryVal;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add ttfb request time information to measurements.
|
||||
*
|
||||
* ttfb information is added via vendored web vitals library.
|
||||
*/
|
||||
function _addTtfbRequestTimeToMeasurements(_measurements) {
|
||||
const navEntry = getNavigationEntry();
|
||||
if (!navEntry) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { responseStart, requestStart } = navEntry;
|
||||
|
||||
if (requestStart <= responseStart) {
|
||||
DEBUG_BUILD && logger.log('[Measurements] Adding TTFB Request Time');
|
||||
_measurements['ttfb.requestTime'] = {
|
||||
value: responseStart - requestStart,
|
||||
unit: 'millisecond',
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/** Taken from @sentry/core sampling.ts */
|
||||
function getSampleRate(
|
||||
transactionContext,
|
||||
options,
|
||||
interactionsSampleRate,
|
||||
) {
|
||||
if (!hasTracingEnabled(options)) {
|
||||
return false;
|
||||
}
|
||||
let sampleRate;
|
||||
if (transactionContext !== undefined && typeof options.tracesSampler === 'function') {
|
||||
sampleRate = options.tracesSampler({
|
||||
transactionContext,
|
||||
name: transactionContext.name,
|
||||
parentSampled: transactionContext.parentSampled,
|
||||
attributes: {
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
...transactionContext.data,
|
||||
...transactionContext.attributes,
|
||||
},
|
||||
location: WINDOW.location,
|
||||
});
|
||||
} else if (transactionContext !== undefined && transactionContext.sampled !== undefined) {
|
||||
sampleRate = transactionContext.sampled;
|
||||
} else if (typeof options.tracesSampleRate !== 'undefined') {
|
||||
sampleRate = options.tracesSampleRate;
|
||||
} else {
|
||||
sampleRate = 1;
|
||||
}
|
||||
if (!isValidSampleRate(sampleRate)) {
|
||||
DEBUG_BUILD && logger.warn('[Tracing] Discarding interaction span because of invalid sample rate.');
|
||||
return false;
|
||||
}
|
||||
if (sampleRate === true) {
|
||||
return interactionsSampleRate;
|
||||
} else if (sampleRate === false) {
|
||||
return 0;
|
||||
}
|
||||
return sampleRate * interactionsSampleRate;
|
||||
}
|
||||
|
||||
export { _addMeasureSpans, _addResourceSpans, addPerformanceEntries, startTrackingINP, startTrackingInteractions, startTrackingLongTasks, startTrackingWebVitals };
|
||||
//# sourceMappingURL=index.js.map
|
||||
1
node_modules/@sentry-internal/tracing/esm/browser/metrics/index.js.map
generated
vendored
Normal file
1
node_modules/@sentry-internal/tracing/esm/browser/metrics/index.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
31
node_modules/@sentry-internal/tracing/esm/browser/metrics/utils.js
generated
vendored
Normal file
31
node_modules/@sentry-internal/tracing/esm/browser/metrics/utils.js
generated
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* Checks if a given value is a valid measurement value.
|
||||
*/
|
||||
function isMeasurementValue(value) {
|
||||
return typeof value === 'number' && isFinite(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to start child on transactions. This function will make sure that the transaction will
|
||||
* use the start timestamp of the created child span if it is earlier than the transactions actual
|
||||
* start timestamp.
|
||||
*
|
||||
* Note: this will not be possible anymore in v8,
|
||||
* unless we do some special handling for browser here...
|
||||
*/
|
||||
function _startChild(transaction, { startTimestamp, ...ctx }) {
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
if (startTimestamp && transaction.startTimestamp > startTimestamp) {
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
transaction.startTimestamp = startTimestamp;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
return transaction.startChild({
|
||||
startTimestamp,
|
||||
...ctx,
|
||||
});
|
||||
}
|
||||
|
||||
export { _startChild, isMeasurementValue };
|
||||
//# sourceMappingURL=utils.js.map
|
||||
1
node_modules/@sentry-internal/tracing/esm/browser/metrics/utils.js.map
generated
vendored
Normal file
1
node_modules/@sentry-internal/tracing/esm/browser/metrics/utils.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"utils.js","sources":["../../../../src/browser/metrics/utils.ts"],"sourcesContent":["import type { Transaction } from '@sentry/core';\nimport type { Span, SpanContext } from '@sentry/types';\n\n/**\n * Checks if a given value is a valid measurement value.\n */\nexport function isMeasurementValue(value: unknown): value is number {\n return typeof value === 'number' && isFinite(value);\n}\n\n/**\n * Helper function to start child on transactions. This function will make sure that the transaction will\n * use the start timestamp of the created child span if it is earlier than the transactions actual\n * start timestamp.\n *\n * Note: this will not be possible anymore in v8,\n * unless we do some special handling for browser here...\n */\nexport function _startChild(transaction: Transaction, { startTimestamp, ...ctx }: SpanContext): Span {\n // eslint-disable-next-line deprecation/deprecation\n if (startTimestamp && transaction.startTimestamp > startTimestamp) {\n // eslint-disable-next-line deprecation/deprecation\n transaction.startTimestamp = startTimestamp;\n }\n\n // eslint-disable-next-line deprecation/deprecation\n return transaction.startChild({\n startTimestamp,\n ...ctx,\n });\n}\n"],"names":[],"mappings":"AAGA;AACA;AACA;AACO,SAAS,kBAAkB,CAAC,KAAK,EAA4B;AACpE,EAAE,OAAO,OAAO,KAAM,KAAI,YAAY,QAAQ,CAAC,KAAK,CAAC,CAAA;AACrD,CAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAAS,WAAW,CAAC,WAAW,EAAe,EAAE,cAAc,EAAE,GAAG,GAAA,EAAK,EAAqB;AACrG;AACA,EAAE,IAAI,cAAe,IAAG,WAAW,CAAC,cAAA,GAAiB,cAAc,EAAE;AACrE;AACA,IAAI,WAAW,CAAC,cAAe,GAAE,cAAc,CAAA;AAC/C,GAAE;AACF;AACA;AACA,EAAE,OAAO,WAAW,CAAC,UAAU,CAAC;AAChC,IAAI,cAAc;AAClB,IAAI,GAAG,GAAG;AACV,GAAG,CAAC,CAAA;AACJ;;;;"}
|
||||
302
node_modules/@sentry-internal/tracing/esm/browser/request.js
generated
vendored
Normal file
302
node_modules/@sentry-internal/tracing/esm/browser/request.js
generated
vendored
Normal file
@@ -0,0 +1,302 @@
|
||||
import { spanToJSON, hasTracingEnabled, setHttpStatus, getCurrentScope, getIsolationScope, startInactiveSpan, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, getClient, spanToTraceHeader, getDynamicSamplingContextFromSpan, getDynamicSamplingContextFromClient } from '@sentry/core';
|
||||
import { addFetchInstrumentationHandler, parseUrl, addXhrInstrumentationHandler, SENTRY_XHR_DATA_KEY, generateSentryTraceHeader, dynamicSamplingContextToSentryBaggageHeader, BAGGAGE_HEADER_NAME, browserPerformanceTimeOrigin, stringMatchesSomePattern } from '@sentry/utils';
|
||||
import { instrumentFetchRequest } from '../common/fetch.js';
|
||||
import { addPerformanceInstrumentationHandler } from './instrument.js';
|
||||
import { WINDOW } from './types.js';
|
||||
|
||||
/* eslint-disable max-lines */
|
||||
|
||||
const DEFAULT_TRACE_PROPAGATION_TARGETS = ['localhost', /^\/(?!\/)/];
|
||||
|
||||
/** Options for Request Instrumentation */
|
||||
|
||||
const defaultRequestInstrumentationOptions = {
|
||||
traceFetch: true,
|
||||
traceXHR: true,
|
||||
enableHTTPTimings: true,
|
||||
// TODO (v8): Remove this property
|
||||
tracingOrigins: DEFAULT_TRACE_PROPAGATION_TARGETS,
|
||||
tracePropagationTargets: DEFAULT_TRACE_PROPAGATION_TARGETS,
|
||||
};
|
||||
|
||||
/** Registers span creators for xhr and fetch requests */
|
||||
function instrumentOutgoingRequests(_options) {
|
||||
const {
|
||||
traceFetch,
|
||||
traceXHR,
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
tracePropagationTargets,
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
tracingOrigins,
|
||||
shouldCreateSpanForRequest,
|
||||
enableHTTPTimings,
|
||||
} = {
|
||||
traceFetch: defaultRequestInstrumentationOptions.traceFetch,
|
||||
traceXHR: defaultRequestInstrumentationOptions.traceXHR,
|
||||
..._options,
|
||||
};
|
||||
|
||||
const shouldCreateSpan =
|
||||
typeof shouldCreateSpanForRequest === 'function' ? shouldCreateSpanForRequest : (_) => true;
|
||||
|
||||
// TODO(v8) Remove tracingOrigins here
|
||||
// The only reason we're passing it in here is because this instrumentOutgoingRequests function is publicly exported
|
||||
// and we don't want to break the API. We can remove it in v8.
|
||||
const shouldAttachHeadersWithTargets = (url) =>
|
||||
shouldAttachHeaders(url, tracePropagationTargets || tracingOrigins);
|
||||
|
||||
const spans = {};
|
||||
|
||||
if (traceFetch) {
|
||||
addFetchInstrumentationHandler(handlerData => {
|
||||
const createdSpan = instrumentFetchRequest(handlerData, shouldCreateSpan, shouldAttachHeadersWithTargets, spans);
|
||||
// We cannot use `window.location` in the generic fetch instrumentation,
|
||||
// but we need it for reliable `server.address` attribute.
|
||||
// so we extend this in here
|
||||
if (createdSpan) {
|
||||
const fullUrl = getFullURL(handlerData.fetchData.url);
|
||||
const host = fullUrl ? parseUrl(fullUrl).host : undefined;
|
||||
createdSpan.setAttributes({
|
||||
'http.url': fullUrl,
|
||||
'server.address': host,
|
||||
});
|
||||
}
|
||||
|
||||
if (enableHTTPTimings && createdSpan) {
|
||||
addHTTPTimings(createdSpan);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (traceXHR) {
|
||||
addXhrInstrumentationHandler(handlerData => {
|
||||
const createdSpan = xhrCallback(handlerData, shouldCreateSpan, shouldAttachHeadersWithTargets, spans);
|
||||
if (enableHTTPTimings && createdSpan) {
|
||||
addHTTPTimings(createdSpan);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function isPerformanceResourceTiming(entry) {
|
||||
return (
|
||||
entry.entryType === 'resource' &&
|
||||
'initiatorType' in entry &&
|
||||
typeof (entry ).nextHopProtocol === 'string' &&
|
||||
(entry.initiatorType === 'fetch' || entry.initiatorType === 'xmlhttprequest')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a temporary observer to listen to the next fetch/xhr resourcing timings,
|
||||
* so that when timings hit their per-browser limit they don't need to be removed.
|
||||
*
|
||||
* @param span A span that has yet to be finished, must contain `url` on data.
|
||||
*/
|
||||
function addHTTPTimings(span) {
|
||||
const { url } = spanToJSON(span).data || {};
|
||||
|
||||
if (!url || typeof url !== 'string') {
|
||||
return;
|
||||
}
|
||||
|
||||
const cleanup = addPerformanceInstrumentationHandler('resource', ({ entries }) => {
|
||||
entries.forEach(entry => {
|
||||
if (isPerformanceResourceTiming(entry) && entry.name.endsWith(url)) {
|
||||
const spanData = resourceTimingEntryToSpanData(entry);
|
||||
spanData.forEach(data => span.setAttribute(...data));
|
||||
// In the next tick, clean this handler up
|
||||
// We have to wait here because otherwise this cleans itself up before it is fully done
|
||||
setTimeout(cleanup);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts ALPN protocol ids to name and version.
|
||||
*
|
||||
* (https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids)
|
||||
* @param nextHopProtocol PerformanceResourceTiming.nextHopProtocol
|
||||
*/
|
||||
function extractNetworkProtocol(nextHopProtocol) {
|
||||
let name = 'unknown';
|
||||
let version = 'unknown';
|
||||
let _name = '';
|
||||
for (const char of nextHopProtocol) {
|
||||
// http/1.1 etc.
|
||||
if (char === '/') {
|
||||
[name, version] = nextHopProtocol.split('/');
|
||||
break;
|
||||
}
|
||||
// h2, h3 etc.
|
||||
if (!isNaN(Number(char))) {
|
||||
name = _name === 'h' ? 'http' : _name;
|
||||
version = nextHopProtocol.split(_name)[1];
|
||||
break;
|
||||
}
|
||||
_name += char;
|
||||
}
|
||||
if (_name === nextHopProtocol) {
|
||||
// webrtc, ftp, etc.
|
||||
name = _name;
|
||||
}
|
||||
return { name, version };
|
||||
}
|
||||
|
||||
function getAbsoluteTime(time = 0) {
|
||||
return ((browserPerformanceTimeOrigin || performance.timeOrigin) + time) / 1000;
|
||||
}
|
||||
|
||||
function resourceTimingEntryToSpanData(resourceTiming) {
|
||||
const { name, version } = extractNetworkProtocol(resourceTiming.nextHopProtocol);
|
||||
|
||||
const timingSpanData = [];
|
||||
|
||||
timingSpanData.push(['network.protocol.version', version], ['network.protocol.name', name]);
|
||||
|
||||
if (!browserPerformanceTimeOrigin) {
|
||||
return timingSpanData;
|
||||
}
|
||||
return [
|
||||
...timingSpanData,
|
||||
['http.request.redirect_start', getAbsoluteTime(resourceTiming.redirectStart)],
|
||||
['http.request.fetch_start', getAbsoluteTime(resourceTiming.fetchStart)],
|
||||
['http.request.domain_lookup_start', getAbsoluteTime(resourceTiming.domainLookupStart)],
|
||||
['http.request.domain_lookup_end', getAbsoluteTime(resourceTiming.domainLookupEnd)],
|
||||
['http.request.connect_start', getAbsoluteTime(resourceTiming.connectStart)],
|
||||
['http.request.secure_connection_start', getAbsoluteTime(resourceTiming.secureConnectionStart)],
|
||||
['http.request.connection_end', getAbsoluteTime(resourceTiming.connectEnd)],
|
||||
['http.request.request_start', getAbsoluteTime(resourceTiming.requestStart)],
|
||||
['http.request.response_start', getAbsoluteTime(resourceTiming.responseStart)],
|
||||
['http.request.response_end', getAbsoluteTime(resourceTiming.responseEnd)],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* A function that determines whether to attach tracing headers to a request.
|
||||
* This was extracted from `instrumentOutgoingRequests` to make it easier to test shouldAttachHeaders.
|
||||
* We only export this fuction for testing purposes.
|
||||
*/
|
||||
function shouldAttachHeaders(url, tracePropagationTargets) {
|
||||
return stringMatchesSomePattern(url, tracePropagationTargets || DEFAULT_TRACE_PROPAGATION_TARGETS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and track xhr request spans
|
||||
*
|
||||
* @returns Span if a span was created, otherwise void.
|
||||
*/
|
||||
// eslint-disable-next-line complexity
|
||||
function xhrCallback(
|
||||
handlerData,
|
||||
shouldCreateSpan,
|
||||
shouldAttachHeaders,
|
||||
spans,
|
||||
) {
|
||||
const xhr = handlerData.xhr;
|
||||
const sentryXhrData = xhr && xhr[SENTRY_XHR_DATA_KEY];
|
||||
|
||||
if (!hasTracingEnabled() || !xhr || xhr.__sentry_own_request__ || !sentryXhrData) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const shouldCreateSpanResult = shouldCreateSpan(sentryXhrData.url);
|
||||
|
||||
// check first if the request has finished and is tracked by an existing span which should now end
|
||||
if (handlerData.endTimestamp && shouldCreateSpanResult) {
|
||||
const spanId = xhr.__sentry_xhr_span_id__;
|
||||
if (!spanId) return;
|
||||
|
||||
const span = spans[spanId];
|
||||
if (span && sentryXhrData.status_code !== undefined) {
|
||||
setHttpStatus(span, sentryXhrData.status_code);
|
||||
span.end();
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
|
||||
delete spans[spanId];
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const scope = getCurrentScope();
|
||||
const isolationScope = getIsolationScope();
|
||||
|
||||
const fullUrl = getFullURL(sentryXhrData.url);
|
||||
const host = fullUrl ? parseUrl(fullUrl).host : undefined;
|
||||
|
||||
const span = shouldCreateSpanResult
|
||||
? startInactiveSpan({
|
||||
name: `${sentryXhrData.method} ${sentryXhrData.url}`,
|
||||
onlyIfParent: true,
|
||||
attributes: {
|
||||
type: 'xhr',
|
||||
'http.method': sentryXhrData.method,
|
||||
'http.url': fullUrl,
|
||||
url: sentryXhrData.url,
|
||||
'server.address': host,
|
||||
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.browser',
|
||||
},
|
||||
op: 'http.client',
|
||||
})
|
||||
: undefined;
|
||||
|
||||
if (span) {
|
||||
xhr.__sentry_xhr_span_id__ = span.spanContext().spanId;
|
||||
spans[xhr.__sentry_xhr_span_id__] = span;
|
||||
}
|
||||
|
||||
const client = getClient();
|
||||
|
||||
if (xhr.setRequestHeader && shouldAttachHeaders(sentryXhrData.url) && client) {
|
||||
const { traceId, spanId, sampled, dsc } = {
|
||||
...isolationScope.getPropagationContext(),
|
||||
...scope.getPropagationContext(),
|
||||
};
|
||||
|
||||
const sentryTraceHeader = span ? spanToTraceHeader(span) : generateSentryTraceHeader(traceId, spanId, sampled);
|
||||
|
||||
const sentryBaggageHeader = dynamicSamplingContextToSentryBaggageHeader(
|
||||
dsc ||
|
||||
(span ? getDynamicSamplingContextFromSpan(span) : getDynamicSamplingContextFromClient(traceId, client, scope)),
|
||||
);
|
||||
|
||||
setHeaderOnXhr(xhr, sentryTraceHeader, sentryBaggageHeader);
|
||||
}
|
||||
|
||||
return span;
|
||||
}
|
||||
|
||||
function setHeaderOnXhr(
|
||||
xhr,
|
||||
sentryTraceHeader,
|
||||
sentryBaggageHeader,
|
||||
) {
|
||||
try {
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
xhr.setRequestHeader('sentry-trace', sentryTraceHeader);
|
||||
if (sentryBaggageHeader) {
|
||||
// From MDN: "If this method is called several times with the same header, the values are merged into one single request header."
|
||||
// We can therefore simply set a baggage header without checking what was there before
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/setRequestHeader
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
xhr.setRequestHeader(BAGGAGE_HEADER_NAME, sentryBaggageHeader);
|
||||
}
|
||||
} catch (_) {
|
||||
// Error: InvalidStateError: Failed to execute 'setRequestHeader' on 'XMLHttpRequest': The object's state must be OPENED.
|
||||
}
|
||||
}
|
||||
|
||||
function getFullURL(url) {
|
||||
try {
|
||||
// By adding a base URL to new URL(), this will also work for relative urls
|
||||
// If `url` is a full URL, the base URL is ignored anyhow
|
||||
const parsed = new URL(url, WINDOW.location.origin);
|
||||
return parsed.href;
|
||||
} catch (e) {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
export { DEFAULT_TRACE_PROPAGATION_TARGETS, defaultRequestInstrumentationOptions, extractNetworkProtocol, instrumentOutgoingRequests, shouldAttachHeaders, xhrCallback };
|
||||
//# sourceMappingURL=request.js.map
|
||||
1
node_modules/@sentry-internal/tracing/esm/browser/request.js.map
generated
vendored
Normal file
1
node_modules/@sentry-internal/tracing/esm/browser/request.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
67
node_modules/@sentry-internal/tracing/esm/browser/router.js
generated
vendored
Normal file
67
node_modules/@sentry-internal/tracing/esm/browser/router.js
generated
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
import { logger, browserPerformanceTimeOrigin, addHistoryInstrumentationHandler } from '@sentry/utils';
|
||||
import { DEBUG_BUILD } from '../common/debug-build.js';
|
||||
import { WINDOW } from './types.js';
|
||||
|
||||
/**
|
||||
* Default function implementing pageload and navigation transactions
|
||||
*/
|
||||
function instrumentRoutingWithDefaults(
|
||||
customStartTransaction,
|
||||
startTransactionOnPageLoad = true,
|
||||
startTransactionOnLocationChange = true,
|
||||
) {
|
||||
if (!WINDOW || !WINDOW.location) {
|
||||
DEBUG_BUILD && logger.warn('Could not initialize routing instrumentation due to invalid location');
|
||||
return;
|
||||
}
|
||||
|
||||
let startingUrl = WINDOW.location.href;
|
||||
|
||||
let activeTransaction;
|
||||
if (startTransactionOnPageLoad) {
|
||||
activeTransaction = customStartTransaction({
|
||||
name: WINDOW.location.pathname,
|
||||
// pageload should always start at timeOrigin (and needs to be in s, not ms)
|
||||
startTimestamp: browserPerformanceTimeOrigin ? browserPerformanceTimeOrigin / 1000 : undefined,
|
||||
op: 'pageload',
|
||||
origin: 'auto.pageload.browser',
|
||||
metadata: { source: 'url' },
|
||||
});
|
||||
}
|
||||
|
||||
if (startTransactionOnLocationChange) {
|
||||
addHistoryInstrumentationHandler(({ to, from }) => {
|
||||
/**
|
||||
* This early return is there to account for some cases where a navigation transaction starts right after
|
||||
* long-running pageload. We make sure that if `from` is undefined and a valid `startingURL` exists, we don't
|
||||
* create an uneccessary navigation transaction.
|
||||
*
|
||||
* This was hard to duplicate, but this behavior stopped as soon as this fix was applied. This issue might also
|
||||
* only be caused in certain development environments where the usage of a hot module reloader is causing
|
||||
* errors.
|
||||
*/
|
||||
if (from === undefined && startingUrl && startingUrl.indexOf(to) !== -1) {
|
||||
startingUrl = undefined;
|
||||
return;
|
||||
}
|
||||
|
||||
if (from !== to) {
|
||||
startingUrl = undefined;
|
||||
if (activeTransaction) {
|
||||
DEBUG_BUILD && logger.log(`[Tracing] Finishing current transaction with op: ${activeTransaction.op}`);
|
||||
// If there's an open transaction on the scope, we need to finish it before creating an new one.
|
||||
activeTransaction.end();
|
||||
}
|
||||
activeTransaction = customStartTransaction({
|
||||
name: WINDOW.location.pathname,
|
||||
op: 'navigation',
|
||||
origin: 'auto.navigation.browser',
|
||||
metadata: { source: 'url' },
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export { instrumentRoutingWithDefaults };
|
||||
//# sourceMappingURL=router.js.map
|
||||
1
node_modules/@sentry-internal/tracing/esm/browser/router.js.map
generated
vendored
Normal file
1
node_modules/@sentry-internal/tracing/esm/browser/router.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"router.js","sources":["../../../src/browser/router.ts"],"sourcesContent":["import type { Transaction, TransactionContext } from '@sentry/types';\nimport { addHistoryInstrumentationHandler, browserPerformanceTimeOrigin, logger } from '@sentry/utils';\n\nimport { DEBUG_BUILD } from '../common/debug-build';\nimport { WINDOW } from './types';\n\n/**\n * Default function implementing pageload and navigation transactions\n */\nexport function instrumentRoutingWithDefaults<T extends Transaction>(\n customStartTransaction: (context: TransactionContext) => T | undefined,\n startTransactionOnPageLoad: boolean = true,\n startTransactionOnLocationChange: boolean = true,\n): void {\n if (!WINDOW || !WINDOW.location) {\n DEBUG_BUILD && logger.warn('Could not initialize routing instrumentation due to invalid location');\n return;\n }\n\n let startingUrl: string | undefined = WINDOW.location.href;\n\n let activeTransaction: T | undefined;\n if (startTransactionOnPageLoad) {\n activeTransaction = customStartTransaction({\n name: WINDOW.location.pathname,\n // pageload should always start at timeOrigin (and needs to be in s, not ms)\n startTimestamp: browserPerformanceTimeOrigin ? browserPerformanceTimeOrigin / 1000 : undefined,\n op: 'pageload',\n origin: 'auto.pageload.browser',\n metadata: { source: 'url' },\n });\n }\n\n if (startTransactionOnLocationChange) {\n addHistoryInstrumentationHandler(({ to, from }) => {\n /**\n * This early return is there to account for some cases where a navigation transaction starts right after\n * long-running pageload. We make sure that if `from` is undefined and a valid `startingURL` exists, we don't\n * create an uneccessary navigation transaction.\n *\n * This was hard to duplicate, but this behavior stopped as soon as this fix was applied. This issue might also\n * only be caused in certain development environments where the usage of a hot module reloader is causing\n * errors.\n */\n if (from === undefined && startingUrl && startingUrl.indexOf(to) !== -1) {\n startingUrl = undefined;\n return;\n }\n\n if (from !== to) {\n startingUrl = undefined;\n if (activeTransaction) {\n DEBUG_BUILD && logger.log(`[Tracing] Finishing current transaction with op: ${activeTransaction.op}`);\n // If there's an open transaction on the scope, we need to finish it before creating an new one.\n activeTransaction.end();\n }\n activeTransaction = customStartTransaction({\n name: WINDOW.location.pathname,\n op: 'navigation',\n origin: 'auto.navigation.browser',\n metadata: { source: 'url' },\n });\n }\n });\n }\n}\n"],"names":[],"mappings":";;;;AAMA;AACA;AACA;AACO,SAAS,6BAA6B;AAC7C,EAAE,sBAAsB;AACxB,EAAE,0BAA0B,GAAY,IAAI;AAC5C,EAAE,gCAAgC,GAAY,IAAI;AAClD,EAAQ;AACR,EAAE,IAAI,CAAC,MAAA,IAAU,CAAC,MAAM,CAAC,QAAQ,EAAE;AACnC,IAAI,eAAe,MAAM,CAAC,IAAI,CAAC,sEAAsE,CAAC,CAAA;AACtG,IAAI,OAAM;AACV,GAAE;AACF;AACA,EAAE,IAAI,WAAW,GAAuB,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAA;AAC5D;AACA,EAAE,IAAI,iBAAiB,CAAA;AACvB,EAAE,IAAI,0BAA0B,EAAE;AAClC,IAAI,iBAAA,GAAoB,sBAAsB,CAAC;AAC/C,MAAM,IAAI,EAAE,MAAM,CAAC,QAAQ,CAAC,QAAQ;AACpC;AACA,MAAM,cAAc,EAAE,4BAA6B,GAAE,+BAA+B,IAAA,GAAO,SAAS;AACpG,MAAM,EAAE,EAAE,UAAU;AACpB,MAAM,MAAM,EAAE,uBAAuB;AACrC,MAAM,QAAQ,EAAE,EAAE,MAAM,EAAE,OAAO;AACjC,KAAK,CAAC,CAAA;AACN,GAAE;AACF;AACA,EAAE,IAAI,gCAAgC,EAAE;AACxC,IAAI,gCAAgC,CAAC,CAAC,EAAE,EAAE,EAAE,IAAA,EAAM,KAAK;AACvD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM,IAAI,IAAA,KAAS,SAAA,IAAa,WAAY,IAAG,WAAW,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC,CAAC,EAAE;AAC/E,QAAQ,WAAA,GAAc,SAAS,CAAA;AAC/B,QAAQ,OAAM;AACd,OAAM;AACN;AACA,MAAM,IAAI,IAAK,KAAI,EAAE,EAAE;AACvB,QAAQ,WAAA,GAAc,SAAS,CAAA;AAC/B,QAAQ,IAAI,iBAAiB,EAAE;AAC/B,UAAU,WAAY,IAAG,MAAM,CAAC,GAAG,CAAC,CAAC,iDAAiD,EAAE,iBAAiB,CAAC,EAAE,CAAC,CAAA,CAAA,CAAA;AACA;AACA,UAAA,iBAAA,CAAA,GAAA,EAAA,CAAA;AACA,SAAA;AACA,QAAA,iBAAA,GAAA,sBAAA,CAAA;AACA,UAAA,IAAA,EAAA,MAAA,CAAA,QAAA,CAAA,QAAA;AACA,UAAA,EAAA,EAAA,YAAA;AACA,UAAA,MAAA,EAAA,yBAAA;AACA,UAAA,QAAA,EAAA,EAAA,MAAA,EAAA,KAAA,EAAA;AACA,SAAA,CAAA,CAAA;AACA,OAAA;AACA,KAAA,CAAA,CAAA;AACA,GAAA;AACA;;;;"}
|
||||
8
node_modules/@sentry-internal/tracing/esm/browser/types.js
generated
vendored
Normal file
8
node_modules/@sentry-internal/tracing/esm/browser/types.js
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
import { GLOBAL_OBJ } from '@sentry/utils';
|
||||
|
||||
const WINDOW = GLOBAL_OBJ
|
||||
|
||||
;
|
||||
|
||||
export { WINDOW };
|
||||
//# sourceMappingURL=types.js.map
|
||||
1
node_modules/@sentry-internal/tracing/esm/browser/types.js.map
generated
vendored
Normal file
1
node_modules/@sentry-internal/tracing/esm/browser/types.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"types.js","sources":["../../../src/browser/types.ts"],"sourcesContent":["import { GLOBAL_OBJ } from '@sentry/utils';\n\nexport const WINDOW = GLOBAL_OBJ as typeof GLOBAL_OBJ &\n // document is not available in all browser environments (webworkers). We make it optional so you have to explicitly check for it\n Omit<Window, 'document'> &\n Partial<Pick<Window, 'document'>>;\n"],"names":[],"mappings":";;AAEO,MAAM,MAAO,GAAE,UAAW;;;;;;"}
|
||||
108
node_modules/@sentry-internal/tracing/esm/browser/web-vitals/getCLS.js
generated
vendored
Normal file
108
node_modules/@sentry-internal/tracing/esm/browser/web-vitals/getCLS.js
generated
vendored
Normal file
@@ -0,0 +1,108 @@
|
||||
import { bindReporter } from './lib/bindReporter.js';
|
||||
import { initMetric } from './lib/initMetric.js';
|
||||
import { observe } from './lib/observe.js';
|
||||
import { onHidden } from './lib/onHidden.js';
|
||||
|
||||
/*
|
||||
* Copyright 2020 Google LLC
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Calculates the [CLS](https://web.dev/cls/) value for the current page and
|
||||
* calls the `callback` function once the value is ready to be reported, along
|
||||
* with all `layout-shift` performance entries that were used in the metric
|
||||
* value calculation. The reported value is a `double` (corresponding to a
|
||||
* [layout shift score](https://web.dev/cls/#layout-shift-score)).
|
||||
*
|
||||
* If the `reportAllChanges` configuration option is set to `true`, the
|
||||
* `callback` function will be called as soon as the value is initially
|
||||
* determined as well as any time the value changes throughout the page
|
||||
* lifespan.
|
||||
*
|
||||
* _**Important:** CLS should be continually monitored for changes throughout
|
||||
* the entire lifespan of a page—including if the user returns to the page after
|
||||
* it's been hidden/backgrounded. However, since browsers often [will not fire
|
||||
* additional callbacks once the user has backgrounded a
|
||||
* page](https://developer.chrome.com/blog/page-lifecycle-api/#advice-hidden),
|
||||
* `callback` is always called when the page's visibility state changes to
|
||||
* hidden. As a result, the `callback` function might be called multiple times
|
||||
* during the same page load._
|
||||
*/
|
||||
const onCLS = (
|
||||
onReport,
|
||||
options = {},
|
||||
) => {
|
||||
const metric = initMetric('CLS', 0);
|
||||
let report;
|
||||
|
||||
let sessionValue = 0;
|
||||
let sessionEntries = [];
|
||||
|
||||
// const handleEntries = (entries: Metric['entries']) => {
|
||||
const handleEntries = (entries) => {
|
||||
entries.forEach(entry => {
|
||||
// Only count layout shifts without recent user input.
|
||||
if (!entry.hadRecentInput) {
|
||||
const firstSessionEntry = sessionEntries[0];
|
||||
const lastSessionEntry = sessionEntries[sessionEntries.length - 1];
|
||||
|
||||
// If the entry occurred less than 1 second after the previous entry and
|
||||
// less than 5 seconds after the first entry in the session, include the
|
||||
// entry in the current session. Otherwise, start a new session.
|
||||
if (
|
||||
sessionValue &&
|
||||
sessionEntries.length !== 0 &&
|
||||
entry.startTime - lastSessionEntry.startTime < 1000 &&
|
||||
entry.startTime - firstSessionEntry.startTime < 5000
|
||||
) {
|
||||
sessionValue += entry.value;
|
||||
sessionEntries.push(entry);
|
||||
} else {
|
||||
sessionValue = entry.value;
|
||||
sessionEntries = [entry];
|
||||
}
|
||||
|
||||
// If the current session value is larger than the current CLS value,
|
||||
// update CLS and the entries contributing to it.
|
||||
if (sessionValue > metric.value) {
|
||||
metric.value = sessionValue;
|
||||
metric.entries = sessionEntries;
|
||||
if (report) {
|
||||
report();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const po = observe('layout-shift', handleEntries);
|
||||
if (po) {
|
||||
report = bindReporter(onReport, metric, options.reportAllChanges);
|
||||
|
||||
const stopListening = () => {
|
||||
handleEntries(po.takeRecords() );
|
||||
report(true);
|
||||
};
|
||||
|
||||
onHidden(stopListening);
|
||||
|
||||
return stopListening;
|
||||
}
|
||||
|
||||
return;
|
||||
};
|
||||
|
||||
export { onCLS };
|
||||
//# sourceMappingURL=getCLS.js.map
|
||||
1
node_modules/@sentry-internal/tracing/esm/browser/web-vitals/getCLS.js.map
generated
vendored
Normal file
1
node_modules/@sentry-internal/tracing/esm/browser/web-vitals/getCLS.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
63
node_modules/@sentry-internal/tracing/esm/browser/web-vitals/getFID.js
generated
vendored
Normal file
63
node_modules/@sentry-internal/tracing/esm/browser/web-vitals/getFID.js
generated
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
import { bindReporter } from './lib/bindReporter.js';
|
||||
import { getVisibilityWatcher } from './lib/getVisibilityWatcher.js';
|
||||
import { initMetric } from './lib/initMetric.js';
|
||||
import { observe } from './lib/observe.js';
|
||||
import { onHidden } from './lib/onHidden.js';
|
||||
|
||||
/*
|
||||
* Copyright 2020 Google LLC
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Calculates the [FID](https://web.dev/fid/) value for the current page and
|
||||
* calls the `callback` function once the value is ready, along with the
|
||||
* relevant `first-input` performance entry used to determine the value. The
|
||||
* reported value is a `DOMHighResTimeStamp`.
|
||||
*
|
||||
* _**Important:** since FID is only reported after the user interacts with the
|
||||
* page, it's possible that it will not be reported for some page loads._
|
||||
*/
|
||||
const onFID = (onReport) => {
|
||||
const visibilityWatcher = getVisibilityWatcher();
|
||||
const metric = initMetric('FID');
|
||||
// eslint-disable-next-line prefer-const
|
||||
let report;
|
||||
|
||||
const handleEntry = (entry) => {
|
||||
// Only report if the page wasn't hidden prior to the first input.
|
||||
if (entry.startTime < visibilityWatcher.firstHiddenTime) {
|
||||
metric.value = entry.processingStart - entry.startTime;
|
||||
metric.entries.push(entry);
|
||||
report(true);
|
||||
}
|
||||
};
|
||||
|
||||
const handleEntries = (entries) => {
|
||||
(entries ).forEach(handleEntry);
|
||||
};
|
||||
|
||||
const po = observe('first-input', handleEntries);
|
||||
report = bindReporter(onReport, metric);
|
||||
|
||||
if (po) {
|
||||
onHidden(() => {
|
||||
handleEntries(po.takeRecords() );
|
||||
po.disconnect();
|
||||
}, true);
|
||||
}
|
||||
};
|
||||
|
||||
export { onFID };
|
||||
//# sourceMappingURL=getFID.js.map
|
||||
1
node_modules/@sentry-internal/tracing/esm/browser/web-vitals/getFID.js.map
generated
vendored
Normal file
1
node_modules/@sentry-internal/tracing/esm/browser/web-vitals/getFID.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"getFID.js","sources":["../../../../src/browser/web-vitals/getFID.ts"],"sourcesContent":["/*\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { bindReporter } from './lib/bindReporter';\nimport { getVisibilityWatcher } from './lib/getVisibilityWatcher';\nimport { initMetric } from './lib/initMetric';\nimport { observe } from './lib/observe';\nimport { onHidden } from './lib/onHidden';\nimport type { FIDMetric, PerformanceEventTiming, ReportCallback } from './types';\n\n/**\n * Calculates the [FID](https://web.dev/fid/) value for the current page and\n * calls the `callback` function once the value is ready, along with the\n * relevant `first-input` performance entry used to determine the value. The\n * reported value is a `DOMHighResTimeStamp`.\n *\n * _**Important:** since FID is only reported after the user interacts with the\n * page, it's possible that it will not be reported for some page loads._\n */\nexport const onFID = (onReport: ReportCallback): void => {\n const visibilityWatcher = getVisibilityWatcher();\n const metric = initMetric('FID');\n // eslint-disable-next-line prefer-const\n let report: ReturnType<typeof bindReporter>;\n\n const handleEntry = (entry: PerformanceEventTiming): void => {\n // Only report if the page wasn't hidden prior to the first input.\n if (entry.startTime < visibilityWatcher.firstHiddenTime) {\n metric.value = entry.processingStart - entry.startTime;\n metric.entries.push(entry);\n report(true);\n }\n };\n\n const handleEntries = (entries: FIDMetric['entries']): void => {\n (entries as PerformanceEventTiming[]).forEach(handleEntry);\n };\n\n const po = observe('first-input', handleEntries);\n report = bindReporter(onReport, metric);\n\n if (po) {\n onHidden(() => {\n handleEntries(po.takeRecords() as FIDMetric['entries']);\n po.disconnect();\n }, true);\n }\n};\n"],"names":[],"mappings":";;;;;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AASA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACa,MAAA,KAAA,GAAQ,CAAC,QAAQ,KAA2B;AACzD,EAAE,MAAM,iBAAA,GAAoB,oBAAoB,EAAE,CAAA;AAClD,EAAE,MAAM,MAAO,GAAE,UAAU,CAAC,KAAK,CAAC,CAAA;AAClC;AACA,EAAE,IAAI,MAAM,CAAA;AACZ;AACA,EAAE,MAAM,WAAA,GAAc,CAAC,KAAK,KAAmC;AAC/D;AACA,IAAI,IAAI,KAAK,CAAC,YAAY,iBAAiB,CAAC,eAAe,EAAE;AAC7D,MAAM,MAAM,CAAC,KAAA,GAAQ,KAAK,CAAC,eAAgB,GAAE,KAAK,CAAC,SAAS,CAAA;AAC5D,MAAM,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;AAChC,MAAM,MAAM,CAAC,IAAI,CAAC,CAAA;AAClB,KAAI;AACJ,GAAG,CAAA;AACH;AACA,EAAE,MAAM,aAAA,GAAgB,CAAC,OAAO,KAAiC;AACjE,IAAI,CAAC,OAAQ,GAA6B,OAAO,CAAC,WAAW,CAAC,CAAA;AAC9D,GAAG,CAAA;AACH;AACA,EAAE,MAAM,KAAK,OAAO,CAAC,aAAa,EAAE,aAAa,CAAC,CAAA;AAClD,EAAE,SAAS,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAA;AACzC;AACA,EAAE,IAAI,EAAE,EAAE;AACV,IAAI,QAAQ,CAAC,MAAM;AACnB,MAAM,aAAa,CAAC,EAAE,CAAC,WAAW,IAA2B,CAAA;AAC7D,MAAM,EAAE,CAAC,UAAU,EAAE,CAAA;AACrB,KAAK,EAAE,IAAI,CAAC,CAAA;AACZ,GAAE;AACF;;;;"}
|
||||
210
node_modules/@sentry-internal/tracing/esm/browser/web-vitals/getINP.js
generated
vendored
Normal file
210
node_modules/@sentry-internal/tracing/esm/browser/web-vitals/getINP.js
generated
vendored
Normal file
@@ -0,0 +1,210 @@
|
||||
import { bindReporter } from './lib/bindReporter.js';
|
||||
import { initMetric } from './lib/initMetric.js';
|
||||
import { observe } from './lib/observe.js';
|
||||
import { onHidden } from './lib/onHidden.js';
|
||||
import { initInteractionCountPolyfill, getInteractionCount } from './lib/polyfills/interactionCountPolyfill.js';
|
||||
|
||||
/*
|
||||
* Copyright 2022 Google LLC
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Returns the interaction count since the last bfcache restore (or for the
|
||||
* full page lifecycle if there were no bfcache restores).
|
||||
*/
|
||||
const getInteractionCountForNavigation = () => {
|
||||
return getInteractionCount();
|
||||
};
|
||||
|
||||
// To prevent unnecessary memory usage on pages with lots of interactions,
|
||||
// store at most 10 of the longest interactions to consider as INP candidates.
|
||||
const MAX_INTERACTIONS_TO_CONSIDER = 10;
|
||||
|
||||
// A list of longest interactions on the page (by latency) sorted so the
|
||||
// longest one is first. The list is as most MAX_INTERACTIONS_TO_CONSIDER long.
|
||||
const longestInteractionList = [];
|
||||
|
||||
// A mapping of longest interactions by their interaction ID.
|
||||
// This is used for faster lookup.
|
||||
const longestInteractionMap = {};
|
||||
|
||||
/**
|
||||
* Takes a performance entry and adds it to the list of worst interactions
|
||||
* if its duration is long enough to make it among the worst. If the
|
||||
* entry is part of an existing interaction, it is merged and the latency
|
||||
* and entries list is updated as needed.
|
||||
*/
|
||||
const processEntry = (entry) => {
|
||||
// The least-long of the 10 longest interactions.
|
||||
const minLongestInteraction = longestInteractionList[longestInteractionList.length - 1];
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
const existingInteraction = longestInteractionMap[entry.interactionId];
|
||||
|
||||
// Only process the entry if it's possibly one of the ten longest,
|
||||
// or if it's part of an existing interaction.
|
||||
if (
|
||||
existingInteraction ||
|
||||
longestInteractionList.length < MAX_INTERACTIONS_TO_CONSIDER ||
|
||||
entry.duration > minLongestInteraction.latency
|
||||
) {
|
||||
// If the interaction already exists, update it. Otherwise create one.
|
||||
if (existingInteraction) {
|
||||
existingInteraction.entries.push(entry);
|
||||
existingInteraction.latency = Math.max(existingInteraction.latency, entry.duration);
|
||||
} else {
|
||||
const interaction = {
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
id: entry.interactionId,
|
||||
latency: entry.duration,
|
||||
entries: [entry],
|
||||
};
|
||||
longestInteractionMap[interaction.id] = interaction;
|
||||
longestInteractionList.push(interaction);
|
||||
}
|
||||
|
||||
// Sort the entries by latency (descending) and keep only the top ten.
|
||||
longestInteractionList.sort((a, b) => b.latency - a.latency);
|
||||
longestInteractionList.splice(MAX_INTERACTIONS_TO_CONSIDER).forEach(i => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
|
||||
delete longestInteractionMap[i.id];
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the estimated p98 longest interaction based on the stored
|
||||
* interaction candidates and the interaction count for the current page.
|
||||
*/
|
||||
const estimateP98LongestInteraction = () => {
|
||||
const candidateInteractionIndex = Math.min(
|
||||
longestInteractionList.length - 1,
|
||||
Math.floor(getInteractionCountForNavigation() / 50),
|
||||
);
|
||||
|
||||
return longestInteractionList[candidateInteractionIndex];
|
||||
};
|
||||
|
||||
/**
|
||||
* Calculates the [INP](https://web.dev/responsiveness/) value for the current
|
||||
* page and calls the `callback` function once the value is ready, along with
|
||||
* the `event` performance entries reported for that interaction. The reported
|
||||
* value is a `DOMHighResTimeStamp`.
|
||||
*
|
||||
* A custom `durationThreshold` configuration option can optionally be passed to
|
||||
* control what `event-timing` entries are considered for INP reporting. The
|
||||
* default threshold is `40`, which means INP scores of less than 40 are
|
||||
* reported as 0. Note that this will not affect your 75th percentile INP value
|
||||
* unless that value is also less than 40 (well below the recommended
|
||||
* [good](https://web.dev/inp/#what-is-a-good-inp-score) threshold).
|
||||
*
|
||||
* If the `reportAllChanges` configuration option is set to `true`, the
|
||||
* `callback` function will be called as soon as the value is initially
|
||||
* determined as well as any time the value changes throughout the page
|
||||
* lifespan.
|
||||
*
|
||||
* _**Important:** INP should be continually monitored for changes throughout
|
||||
* the entire lifespan of a page—including if the user returns to the page after
|
||||
* it's been hidden/backgrounded. However, since browsers often [will not fire
|
||||
* additional callbacks once the user has backgrounded a
|
||||
* page](https://developer.chrome.com/blog/page-lifecycle-api/#advice-hidden),
|
||||
* `callback` is always called when the page's visibility state changes to
|
||||
* hidden. As a result, the `callback` function might be called multiple times
|
||||
* during the same page load._
|
||||
*/
|
||||
const onINP = (onReport, opts) => {
|
||||
// Set defaults
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
opts = opts || {};
|
||||
|
||||
// https://web.dev/inp/#what's-a-%22good%22-inp-value
|
||||
// const thresholds = [200, 500];
|
||||
|
||||
// TODO(philipwalton): remove once the polyfill is no longer needed.
|
||||
initInteractionCountPolyfill();
|
||||
|
||||
const metric = initMetric('INP');
|
||||
// eslint-disable-next-line prefer-const
|
||||
let report;
|
||||
|
||||
const handleEntries = (entries) => {
|
||||
entries.forEach(entry => {
|
||||
if (entry.interactionId) {
|
||||
processEntry(entry);
|
||||
}
|
||||
|
||||
// Entries of type `first-input` don't currently have an `interactionId`,
|
||||
// so to consider them in INP we have to first check that an existing
|
||||
// entry doesn't match the `duration` and `startTime`.
|
||||
// Note that this logic assumes that `event` entries are dispatched
|
||||
// before `first-input` entries. This is true in Chrome but it is not
|
||||
// true in Firefox; however, Firefox doesn't support interactionId, so
|
||||
// it's not an issue at the moment.
|
||||
// TODO(philipwalton): remove once crbug.com/1325826 is fixed.
|
||||
if (entry.entryType === 'first-input') {
|
||||
const noMatchingEntry = !longestInteractionList.some(interaction => {
|
||||
return interaction.entries.some(prevEntry => {
|
||||
return entry.duration === prevEntry.duration && entry.startTime === prevEntry.startTime;
|
||||
});
|
||||
});
|
||||
if (noMatchingEntry) {
|
||||
processEntry(entry);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const inp = estimateP98LongestInteraction();
|
||||
|
||||
if (inp && inp.latency !== metric.value) {
|
||||
metric.value = inp.latency;
|
||||
metric.entries = inp.entries;
|
||||
report();
|
||||
}
|
||||
};
|
||||
|
||||
const po = observe('event', handleEntries, {
|
||||
// Event Timing entries have their durations rounded to the nearest 8ms,
|
||||
// so a duration of 40ms would be any event that spans 2.5 or more frames
|
||||
// at 60Hz. This threshold is chosen to strike a balance between usefulness
|
||||
// and performance. Running this callback for any interaction that spans
|
||||
// just one or two frames is likely not worth the insight that could be
|
||||
// gained.
|
||||
durationThreshold: opts.durationThreshold || 40,
|
||||
} );
|
||||
|
||||
report = bindReporter(onReport, metric, opts.reportAllChanges);
|
||||
|
||||
if (po) {
|
||||
// Also observe entries of type `first-input`. This is useful in cases
|
||||
// where the first interaction is less than the `durationThreshold`.
|
||||
po.observe({ type: 'first-input', buffered: true });
|
||||
|
||||
onHidden(() => {
|
||||
handleEntries(po.takeRecords() );
|
||||
|
||||
// If the interaction count shows that there were interactions but
|
||||
// none were captured by the PerformanceObserver, report a latency of 0.
|
||||
if (metric.value < 0 && getInteractionCountForNavigation() > 0) {
|
||||
metric.value = 0;
|
||||
metric.entries = [];
|
||||
}
|
||||
|
||||
report(true);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export { onINP };
|
||||
//# sourceMappingURL=getINP.js.map
|
||||
1
node_modules/@sentry-internal/tracing/esm/browser/web-vitals/getINP.js.map
generated
vendored
Normal file
1
node_modules/@sentry-internal/tracing/esm/browser/web-vitals/getINP.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
88
node_modules/@sentry-internal/tracing/esm/browser/web-vitals/getLCP.js
generated
vendored
Normal file
88
node_modules/@sentry-internal/tracing/esm/browser/web-vitals/getLCP.js
generated
vendored
Normal file
@@ -0,0 +1,88 @@
|
||||
import { WINDOW } from '../types.js';
|
||||
import { bindReporter } from './lib/bindReporter.js';
|
||||
import { getActivationStart } from './lib/getActivationStart.js';
|
||||
import { getVisibilityWatcher } from './lib/getVisibilityWatcher.js';
|
||||
import { initMetric } from './lib/initMetric.js';
|
||||
import { observe } from './lib/observe.js';
|
||||
import { onHidden } from './lib/onHidden.js';
|
||||
|
||||
/*
|
||||
* Copyright 2020 Google LLC
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.
|
||||
*/
|
||||
|
||||
const reportedMetricIDs = {};
|
||||
|
||||
/**
|
||||
* Calculates the [LCP](https://web.dev/lcp/) value for the current page and
|
||||
* calls the `callback` function once the value is ready (along with the
|
||||
* relevant `largest-contentful-paint` performance entry used to determine the
|
||||
* value). The reported value is a `DOMHighResTimeStamp`.
|
||||
*/
|
||||
const onLCP = (onReport) => {
|
||||
const visibilityWatcher = getVisibilityWatcher();
|
||||
const metric = initMetric('LCP');
|
||||
let report;
|
||||
|
||||
const handleEntries = (entries) => {
|
||||
const lastEntry = entries[entries.length - 1] ;
|
||||
if (lastEntry) {
|
||||
// The startTime attribute returns the value of the renderTime if it is
|
||||
// not 0, and the value of the loadTime otherwise. The activationStart
|
||||
// reference is used because LCP should be relative to page activation
|
||||
// rather than navigation start if the page was prerendered.
|
||||
const value = Math.max(lastEntry.startTime - getActivationStart(), 0);
|
||||
|
||||
// Only report if the page wasn't hidden prior to LCP.
|
||||
if (value < visibilityWatcher.firstHiddenTime) {
|
||||
metric.value = value;
|
||||
metric.entries = [lastEntry];
|
||||
report();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const po = observe('largest-contentful-paint', handleEntries);
|
||||
|
||||
if (po) {
|
||||
report = bindReporter(onReport, metric);
|
||||
|
||||
const stopListening = () => {
|
||||
if (!reportedMetricIDs[metric.id]) {
|
||||
handleEntries(po.takeRecords() );
|
||||
po.disconnect();
|
||||
reportedMetricIDs[metric.id] = true;
|
||||
report(true);
|
||||
}
|
||||
};
|
||||
|
||||
// Stop listening after input. Note: while scrolling is an input that
|
||||
// stop LCP observation, it's unreliable since it can be programmatically
|
||||
// generated. See: https://github.com/GoogleChrome/web-vitals/issues/75
|
||||
['keydown', 'click'].forEach(type => {
|
||||
if (WINDOW.document) {
|
||||
addEventListener(type, stopListening, { once: true, capture: true });
|
||||
}
|
||||
});
|
||||
|
||||
onHidden(stopListening, true);
|
||||
|
||||
return stopListening;
|
||||
}
|
||||
|
||||
return;
|
||||
};
|
||||
|
||||
export { onLCP };
|
||||
//# sourceMappingURL=getLCP.js.map
|
||||
1
node_modules/@sentry-internal/tracing/esm/browser/web-vitals/getLCP.js.map
generated
vendored
Normal file
1
node_modules/@sentry-internal/tracing/esm/browser/web-vitals/getLCP.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
28
node_modules/@sentry-internal/tracing/esm/browser/web-vitals/lib/bindReporter.js
generated
vendored
Normal file
28
node_modules/@sentry-internal/tracing/esm/browser/web-vitals/lib/bindReporter.js
generated
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
const bindReporter = (
|
||||
callback,
|
||||
metric,
|
||||
reportAllChanges,
|
||||
) => {
|
||||
let prevValue;
|
||||
let delta;
|
||||
return (forceReport) => {
|
||||
if (metric.value >= 0) {
|
||||
if (forceReport || reportAllChanges) {
|
||||
delta = metric.value - (prevValue || 0);
|
||||
|
||||
// Report the metric if there's a non-zero delta or if no previous
|
||||
// value exists (which can happen in the case of the document becoming
|
||||
// hidden when the metric value is 0).
|
||||
// See: https://github.com/GoogleChrome/web-vitals/issues/14
|
||||
if (delta || prevValue === undefined) {
|
||||
prevValue = metric.value;
|
||||
metric.delta = delta;
|
||||
callback(metric);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
export { bindReporter };
|
||||
//# sourceMappingURL=bindReporter.js.map
|
||||
1
node_modules/@sentry-internal/tracing/esm/browser/web-vitals/lib/bindReporter.js.map
generated
vendored
Normal file
1
node_modules/@sentry-internal/tracing/esm/browser/web-vitals/lib/bindReporter.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"bindReporter.js","sources":["../../../../../src/browser/web-vitals/lib/bindReporter.ts"],"sourcesContent":["/*\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { Metric, ReportCallback } from '../types';\n\nexport const bindReporter = (\n callback: ReportCallback,\n metric: Metric,\n reportAllChanges?: boolean,\n): ((forceReport?: boolean) => void) => {\n let prevValue: number;\n let delta: number;\n return (forceReport?: boolean) => {\n if (metric.value >= 0) {\n if (forceReport || reportAllChanges) {\n delta = metric.value - (prevValue || 0);\n\n // Report the metric if there's a non-zero delta or if no previous\n // value exists (which can happen in the case of the document becoming\n // hidden when the metric value is 0).\n // See: https://github.com/GoogleChrome/web-vitals/issues/14\n if (delta || prevValue === undefined) {\n prevValue = metric.value;\n metric.delta = delta;\n callback(metric);\n }\n }\n }\n };\n};\n"],"names":[],"mappings":"AAkBO,MAAM,eAAe;AAC5B,EAAE,QAAQ;AACV,EAAE,MAAM;AACR,EAAE,gBAAgB;AAClB,KAAwC;AACxC,EAAE,IAAI,SAAS,CAAA;AACf,EAAE,IAAI,KAAK,CAAA;AACX,EAAE,OAAO,CAAC,WAAW,KAAe;AACpC,IAAI,IAAI,MAAM,CAAC,KAAM,IAAG,CAAC,EAAE;AAC3B,MAAM,IAAI,WAAY,IAAG,gBAAgB,EAAE;AAC3C,QAAQ,KAAA,GAAQ,MAAM,CAAC,KAAA,IAAS,SAAA,IAAa,CAAC,CAAC,CAAA;AAC/C;AACA;AACA;AACA;AACA;AACA,QAAQ,IAAI,KAAA,IAAS,SAAU,KAAI,SAAS,EAAE;AAC9C,UAAU,SAAU,GAAE,MAAM,CAAC,KAAK,CAAA;AAClC,UAAU,MAAM,CAAC,KAAM,GAAE,KAAK,CAAA;AAC9B,UAAU,QAAQ,CAAC,MAAM,CAAC,CAAA;AAC1B,SAAQ;AACR,OAAM;AACN,KAAI;AACJ,GAAG,CAAA;AACH;;;;"}
|
||||
27
node_modules/@sentry-internal/tracing/esm/browser/web-vitals/lib/generateUniqueID.js
generated
vendored
Normal file
27
node_modules/@sentry-internal/tracing/esm/browser/web-vitals/lib/generateUniqueID.js
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright 2020 Google LLC
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Performantly generate a unique, 30-char string by combining a version
|
||||
* number, the current timestamp with a 13-digit number integer.
|
||||
* @return {string}
|
||||
*/
|
||||
const generateUniqueID = () => {
|
||||
return `v3-${Date.now()}-${Math.floor(Math.random() * (9e12 - 1)) + 1e12}`;
|
||||
};
|
||||
|
||||
export { generateUniqueID };
|
||||
//# sourceMappingURL=generateUniqueID.js.map
|
||||
1
node_modules/@sentry-internal/tracing/esm/browser/web-vitals/lib/generateUniqueID.js.map
generated
vendored
Normal file
1
node_modules/@sentry-internal/tracing/esm/browser/web-vitals/lib/generateUniqueID.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"generateUniqueID.js","sources":["../../../../../src/browser/web-vitals/lib/generateUniqueID.ts"],"sourcesContent":["/*\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * Performantly generate a unique, 30-char string by combining a version\n * number, the current timestamp with a 13-digit number integer.\n * @return {string}\n */\nexport const generateUniqueID = (): string => {\n return `v3-${Date.now()}-${Math.floor(Math.random() * (9e12 - 1)) + 1e12}`;\n};\n"],"names":[],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACa,MAAA,gBAAA,GAAmB,MAAc;AAC9C,EAAE,OAAO,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAC,IAAK,IAAA,GAAO,CAAC,CAAC,CAAA,GAAI,IAAI,CAAC,CAAA,CAAA;AACA;;;;"}
|
||||
25
node_modules/@sentry-internal/tracing/esm/browser/web-vitals/lib/getActivationStart.js
generated
vendored
Normal file
25
node_modules/@sentry-internal/tracing/esm/browser/web-vitals/lib/getActivationStart.js
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
import { getNavigationEntry } from './getNavigationEntry.js';
|
||||
|
||||
/*
|
||||
* Copyright 2022 Google LLC
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.
|
||||
*/
|
||||
|
||||
const getActivationStart = () => {
|
||||
const navEntry = getNavigationEntry();
|
||||
return (navEntry && navEntry.activationStart) || 0;
|
||||
};
|
||||
|
||||
export { getActivationStart };
|
||||
//# sourceMappingURL=getActivationStart.js.map
|
||||
1
node_modules/@sentry-internal/tracing/esm/browser/web-vitals/lib/getActivationStart.js.map
generated
vendored
Normal file
1
node_modules/@sentry-internal/tracing/esm/browser/web-vitals/lib/getActivationStart.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"getActivationStart.js","sources":["../../../../../src/browser/web-vitals/lib/getActivationStart.ts"],"sourcesContent":["/*\n * Copyright 2022 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { getNavigationEntry } from './getNavigationEntry';\n\nexport const getActivationStart = (): number => {\n const navEntry = getNavigationEntry();\n return (navEntry && navEntry.activationStart) || 0;\n};\n"],"names":[],"mappings":";;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACa,MAAA,kBAAA,GAAqB,MAAc;AAChD,EAAE,MAAM,QAAA,GAAW,kBAAkB,EAAE,CAAA;AACvC,EAAE,OAAO,CAAC,QAAS,IAAG,QAAQ,CAAC,eAAe,KAAK,CAAC,CAAA;AACpD;;;;"}
|
||||
53
node_modules/@sentry-internal/tracing/esm/browser/web-vitals/lib/getNavigationEntry.js
generated
vendored
Normal file
53
node_modules/@sentry-internal/tracing/esm/browser/web-vitals/lib/getNavigationEntry.js
generated
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
import { WINDOW } from '../../types.js';
|
||||
|
||||
/*
|
||||
* Copyright 2022 Google LLC
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.
|
||||
*/
|
||||
|
||||
const getNavigationEntryFromPerformanceTiming = () => {
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
const timing = WINDOW.performance.timing;
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
const type = WINDOW.performance.navigation.type;
|
||||
|
||||
const navigationEntry = {
|
||||
entryType: 'navigation',
|
||||
startTime: 0,
|
||||
type: type == 2 ? 'back_forward' : type === 1 ? 'reload' : 'navigate',
|
||||
};
|
||||
|
||||
for (const key in timing) {
|
||||
if (key !== 'navigationStart' && key !== 'toJSON') {
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
navigationEntry[key] = Math.max((timing[key ] ) - timing.navigationStart, 0);
|
||||
}
|
||||
}
|
||||
return navigationEntry ;
|
||||
};
|
||||
|
||||
const getNavigationEntry = () => {
|
||||
if (WINDOW.__WEB_VITALS_POLYFILL__) {
|
||||
return (
|
||||
WINDOW.performance &&
|
||||
((performance.getEntriesByType && performance.getEntriesByType('navigation')[0]) ||
|
||||
getNavigationEntryFromPerformanceTiming())
|
||||
);
|
||||
} else {
|
||||
return WINDOW.performance && performance.getEntriesByType && performance.getEntriesByType('navigation')[0];
|
||||
}
|
||||
};
|
||||
|
||||
export { getNavigationEntry };
|
||||
//# sourceMappingURL=getNavigationEntry.js.map
|
||||
1
node_modules/@sentry-internal/tracing/esm/browser/web-vitals/lib/getNavigationEntry.js.map
generated
vendored
Normal file
1
node_modules/@sentry-internal/tracing/esm/browser/web-vitals/lib/getNavigationEntry.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"getNavigationEntry.js","sources":["../../../../../src/browser/web-vitals/lib/getNavigationEntry.ts"],"sourcesContent":["/*\n * Copyright 2022 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { WINDOW } from '../../types';\nimport type { NavigationTimingPolyfillEntry } from '../types';\n\nconst getNavigationEntryFromPerformanceTiming = (): NavigationTimingPolyfillEntry => {\n // eslint-disable-next-line deprecation/deprecation\n const timing = WINDOW.performance.timing;\n // eslint-disable-next-line deprecation/deprecation\n const type = WINDOW.performance.navigation.type;\n\n const navigationEntry: { [key: string]: number | string } = {\n entryType: 'navigation',\n startTime: 0,\n type: type == 2 ? 'back_forward' : type === 1 ? 'reload' : 'navigate',\n };\n\n for (const key in timing) {\n if (key !== 'navigationStart' && key !== 'toJSON') {\n // eslint-disable-next-line deprecation/deprecation\n navigationEntry[key] = Math.max((timing[key as keyof PerformanceTiming] as number) - timing.navigationStart, 0);\n }\n }\n return navigationEntry as unknown as NavigationTimingPolyfillEntry;\n};\n\nexport const getNavigationEntry = (): PerformanceNavigationTiming | NavigationTimingPolyfillEntry | undefined => {\n if (WINDOW.__WEB_VITALS_POLYFILL__) {\n return (\n WINDOW.performance &&\n ((performance.getEntriesByType && performance.getEntriesByType('navigation')[0]) ||\n getNavigationEntryFromPerformanceTiming())\n );\n } else {\n return WINDOW.performance && performance.getEntriesByType && performance.getEntriesByType('navigation')[0];\n }\n};\n"],"names":[],"mappings":";;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAKA,MAAM,uCAAA,GAA0C,MAAqC;AACrF;AACA,EAAE,MAAM,MAAO,GAAE,MAAM,CAAC,WAAW,CAAC,MAAM,CAAA;AAC1C;AACA,EAAE,MAAM,OAAO,MAAM,CAAC,WAAW,CAAC,UAAU,CAAC,IAAI,CAAA;AACjD;AACA,EAAE,MAAM,eAAe,GAAuC;AAC9D,IAAI,SAAS,EAAE,YAAY;AAC3B,IAAI,SAAS,EAAE,CAAC;AAChB,IAAI,IAAI,EAAE,IAAK,IAAG,IAAI,cAAA,GAAiB,IAAA,KAAS,CAAA,GAAI,QAAA,GAAW,UAAU;AACzE,GAAG,CAAA;AACH;AACA,EAAE,KAAK,MAAM,GAAI,IAAG,MAAM,EAAE;AAC5B,IAAI,IAAI,GAAI,KAAI,qBAAqB,GAAA,KAAQ,QAAQ,EAAE;AACvD;AACA,MAAM,eAAe,CAAC,GAAG,CAAA,GAAI,IAAI,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,GAAA,OAA6C,MAAM,CAAC,eAAe,EAAE,CAAC,CAAC,CAAA;AACrH,KAAI;AACJ,GAAE;AACF,EAAE,OAAO,eAAgB,EAAA;AACzB,CAAC,CAAA;AACD;AACa,MAAA,kBAAA,GAAqB,MAA+E;AACjH,EAAE,IAAI,MAAM,CAAC,uBAAuB,EAAE;AACtC,IAAI;AACJ,MAAM,MAAM,CAAC,WAAY;AACzB,OAAO,CAAC,WAAW,CAAC,oBAAoB,WAAW,CAAC,gBAAgB,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;AACrF,QAAQ,uCAAuC,EAAE,CAAA;AACjD,MAAK;AACL,SAAS;AACT,IAAI,OAAO,MAAM,CAAC,WAAY,IAAG,WAAW,CAAC,gBAAA,IAAoB,WAAW,CAAC,gBAAgB,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAA;AAC9G,GAAE;AACF;;;;"}
|
||||
56
node_modules/@sentry-internal/tracing/esm/browser/web-vitals/lib/getVisibilityWatcher.js
generated
vendored
Normal file
56
node_modules/@sentry-internal/tracing/esm/browser/web-vitals/lib/getVisibilityWatcher.js
generated
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
import { WINDOW } from '../../types.js';
|
||||
import { onHidden } from './onHidden.js';
|
||||
|
||||
/*
|
||||
* Copyright 2020 Google LLC
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.
|
||||
*/
|
||||
|
||||
let firstHiddenTime = -1;
|
||||
|
||||
const initHiddenTime = () => {
|
||||
// If the document is hidden and not prerendering, assume it was always
|
||||
// hidden and the page was loaded in the background.
|
||||
if (WINDOW.document && WINDOW.document.visibilityState) {
|
||||
firstHiddenTime = WINDOW.document.visibilityState === 'hidden' && !WINDOW.document.prerendering ? 0 : Infinity;
|
||||
}
|
||||
};
|
||||
|
||||
const trackChanges = () => {
|
||||
// Update the time if/when the document becomes hidden.
|
||||
onHidden(({ timeStamp }) => {
|
||||
firstHiddenTime = timeStamp;
|
||||
}, true);
|
||||
};
|
||||
|
||||
const getVisibilityWatcher = (
|
||||
|
||||
) => {
|
||||
if (firstHiddenTime < 0) {
|
||||
// If the document is hidden when this code runs, assume it was hidden
|
||||
// since navigation start. This isn't a perfect heuristic, but it's the
|
||||
// best we can do until an API is available to support querying past
|
||||
// visibilityState.
|
||||
initHiddenTime();
|
||||
trackChanges();
|
||||
}
|
||||
return {
|
||||
get firstHiddenTime() {
|
||||
return firstHiddenTime;
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export { getVisibilityWatcher };
|
||||
//# sourceMappingURL=getVisibilityWatcher.js.map
|
||||
1
node_modules/@sentry-internal/tracing/esm/browser/web-vitals/lib/getVisibilityWatcher.js.map
generated
vendored
Normal file
1
node_modules/@sentry-internal/tracing/esm/browser/web-vitals/lib/getVisibilityWatcher.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"getVisibilityWatcher.js","sources":["../../../../../src/browser/web-vitals/lib/getVisibilityWatcher.ts"],"sourcesContent":["/*\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { WINDOW } from '../../types';\nimport { onHidden } from './onHidden';\n\nlet firstHiddenTime = -1;\n\nconst initHiddenTime = (): void => {\n // If the document is hidden and not prerendering, assume it was always\n // hidden and the page was loaded in the background.\n if (WINDOW.document && WINDOW.document.visibilityState) {\n firstHiddenTime = WINDOW.document.visibilityState === 'hidden' && !WINDOW.document.prerendering ? 0 : Infinity;\n }\n};\n\nconst trackChanges = (): void => {\n // Update the time if/when the document becomes hidden.\n onHidden(({ timeStamp }) => {\n firstHiddenTime = timeStamp;\n }, true);\n};\n\nexport const getVisibilityWatcher = (): {\n readonly firstHiddenTime: number;\n} => {\n if (firstHiddenTime < 0) {\n // If the document is hidden when this code runs, assume it was hidden\n // since navigation start. This isn't a perfect heuristic, but it's the\n // best we can do until an API is available to support querying past\n // visibilityState.\n initHiddenTime();\n trackChanges();\n }\n return {\n get firstHiddenTime() {\n return firstHiddenTime;\n },\n };\n};\n"],"names":[],"mappings":";;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAIA;AACA,IAAI,eAAA,GAAkB,CAAC,CAAC,CAAA;AACxB;AACA,MAAM,cAAA,GAAiB,MAAY;AACnC;AACA;AACA,EAAE,IAAI,MAAM,CAAC,QAAA,IAAY,MAAM,CAAC,QAAQ,CAAC,eAAe,EAAE;AAC1D,IAAI,kBAAkB,MAAM,CAAC,QAAQ,CAAC,oBAAoB,QAAA,IAAY,CAAC,MAAM,CAAC,QAAQ,CAAC,eAAe,CAAA,GAAI,QAAQ,CAAA;AAClH,GAAE;AACF,CAAC,CAAA;AACD;AACA,MAAM,YAAA,GAAe,MAAY;AACjC;AACA,EAAE,QAAQ,CAAC,CAAC,EAAE,SAAU,EAAC,KAAK;AAC9B,IAAI,eAAA,GAAkB,SAAS,CAAA;AAC/B,GAAG,EAAE,IAAI,CAAC,CAAA;AACV,CAAC,CAAA;AACD;AACO,MAAM,oBAAqB,GAAE;AAClC;AACF,KAAK;AACL,EAAE,IAAI,eAAgB,GAAE,CAAC,EAAE;AAC3B;AACA;AACA;AACA;AACA,IAAI,cAAc,EAAE,CAAA;AACpB,IAAI,YAAY,EAAE,CAAA;AAClB,GAAE;AACF,EAAE,OAAO;AACT,IAAI,IAAI,eAAe,GAAG;AAC1B,MAAM,OAAO,eAAe,CAAA;AAC5B,KAAK;AACL,GAAG,CAAA;AACH;;;;"}
|
||||
46
node_modules/@sentry-internal/tracing/esm/browser/web-vitals/lib/initMetric.js
generated
vendored
Normal file
46
node_modules/@sentry-internal/tracing/esm/browser/web-vitals/lib/initMetric.js
generated
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
import { WINDOW } from '../../types.js';
|
||||
import { generateUniqueID } from './generateUniqueID.js';
|
||||
import { getActivationStart } from './getActivationStart.js';
|
||||
import { getNavigationEntry } from './getNavigationEntry.js';
|
||||
|
||||
/*
|
||||
* Copyright 2020 Google LLC
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.
|
||||
*/
|
||||
|
||||
const initMetric = (name, value) => {
|
||||
const navEntry = getNavigationEntry();
|
||||
let navigationType = 'navigate';
|
||||
|
||||
if (navEntry) {
|
||||
if ((WINDOW.document && WINDOW.document.prerendering) || getActivationStart() > 0) {
|
||||
navigationType = 'prerender';
|
||||
} else {
|
||||
navigationType = navEntry.type.replace(/_/g, '-') ;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
name,
|
||||
value: typeof value === 'undefined' ? -1 : value,
|
||||
rating: 'good', // Will be updated if the value changes.
|
||||
delta: 0,
|
||||
entries: [],
|
||||
id: generateUniqueID(),
|
||||
navigationType,
|
||||
};
|
||||
};
|
||||
|
||||
export { initMetric };
|
||||
//# sourceMappingURL=initMetric.js.map
|
||||
1
node_modules/@sentry-internal/tracing/esm/browser/web-vitals/lib/initMetric.js.map
generated
vendored
Normal file
1
node_modules/@sentry-internal/tracing/esm/browser/web-vitals/lib/initMetric.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"initMetric.js","sources":["../../../../../src/browser/web-vitals/lib/initMetric.ts"],"sourcesContent":["/*\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { WINDOW } from '../../types';\nimport type { Metric } from '../types';\nimport { generateUniqueID } from './generateUniqueID';\nimport { getActivationStart } from './getActivationStart';\nimport { getNavigationEntry } from './getNavigationEntry';\n\nexport const initMetric = (name: Metric['name'], value?: number): Metric => {\n const navEntry = getNavigationEntry();\n let navigationType: Metric['navigationType'] = 'navigate';\n\n if (navEntry) {\n if ((WINDOW.document && WINDOW.document.prerendering) || getActivationStart() > 0) {\n navigationType = 'prerender';\n } else {\n navigationType = navEntry.type.replace(/_/g, '-') as Metric['navigationType'];\n }\n }\n\n return {\n name,\n value: typeof value === 'undefined' ? -1 : value,\n rating: 'good', // Will be updated if the value changes.\n delta: 0,\n entries: [],\n id: generateUniqueID(),\n navigationType,\n };\n};\n"],"names":[],"mappings":";;;;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAOA;MACa,UAAW,GAAE,CAAC,IAAI,EAAkB,KAAK,KAAsB;AAC5E,EAAE,MAAM,QAAA,GAAW,kBAAkB,EAAE,CAAA;AACvC,EAAE,IAAI,cAAc,GAA6B,UAAU,CAAA;AAC3D;AACA,EAAE,IAAI,QAAQ,EAAE;AAChB,IAAI,IAAI,CAAC,MAAM,CAAC,QAAA,IAAY,MAAM,CAAC,QAAQ,CAAC,YAAY,KAAK,kBAAkB,EAAG,GAAE,CAAC,EAAE;AACvF,MAAM,cAAA,GAAiB,WAAW,CAAA;AAClC,WAAW;AACX,MAAM,cAAA,GAAiB,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAE,EAAA;AACxD,KAAI;AACJ,GAAE;AACF;AACA,EAAE,OAAO;AACT,IAAI,IAAI;AACR,IAAI,KAAK,EAAE,OAAO,KAAM,KAAI,cAAc,CAAC,CAAE,GAAE,KAAK;AACpD,IAAI,MAAM,EAAE,MAAM;AAClB,IAAI,KAAK,EAAE,CAAC;AACZ,IAAI,OAAO,EAAE,EAAE;AACf,IAAI,EAAE,EAAE,gBAAgB,EAAE;AAC1B,IAAI,cAAc;AAClB,GAAG,CAAA;AACH;;;;"}
|
||||
37
node_modules/@sentry-internal/tracing/esm/browser/web-vitals/lib/observe.js
generated
vendored
Normal file
37
node_modules/@sentry-internal/tracing/esm/browser/web-vitals/lib/observe.js
generated
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* Takes a performance entry type and a callback function, and creates a
|
||||
* `PerformanceObserver` instance that will observe the specified entry type
|
||||
* with buffering enabled and call the callback _for each entry_.
|
||||
*
|
||||
* This function also feature-detects entry support and wraps the logic in a
|
||||
* try/catch to avoid errors in unsupporting browsers.
|
||||
*/
|
||||
const observe = (
|
||||
type,
|
||||
callback,
|
||||
opts,
|
||||
) => {
|
||||
try {
|
||||
if (PerformanceObserver.supportedEntryTypes.includes(type)) {
|
||||
const po = new PerformanceObserver(list => {
|
||||
callback(list.getEntries() );
|
||||
});
|
||||
po.observe(
|
||||
Object.assign(
|
||||
{
|
||||
type,
|
||||
buffered: true,
|
||||
},
|
||||
opts || {},
|
||||
) ,
|
||||
);
|
||||
return po;
|
||||
}
|
||||
} catch (e) {
|
||||
// Do nothing.
|
||||
}
|
||||
return;
|
||||
};
|
||||
|
||||
export { observe };
|
||||
//# sourceMappingURL=observe.js.map
|
||||
1
node_modules/@sentry-internal/tracing/esm/browser/web-vitals/lib/observe.js.map
generated
vendored
Normal file
1
node_modules/@sentry-internal/tracing/esm/browser/web-vitals/lib/observe.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"observe.js","sources":["../../../../../src/browser/web-vitals/lib/observe.ts"],"sourcesContent":["/*\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { FirstInputPolyfillEntry, NavigationTimingPolyfillEntry, PerformancePaintTiming } from '../types';\n\nexport interface PerformanceEntryHandler {\n (entry: PerformanceEntry): void;\n}\n\ninterface PerformanceEntryMap {\n event: PerformanceEventTiming[];\n paint: PerformancePaintTiming[];\n 'layout-shift': LayoutShift[];\n 'largest-contentful-paint': LargestContentfulPaint[];\n 'first-input': PerformanceEventTiming[] | FirstInputPolyfillEntry[];\n navigation: PerformanceNavigationTiming[] | NavigationTimingPolyfillEntry[];\n resource: PerformanceResourceTiming[];\n longtask: PerformanceEntry[];\n}\n\n/**\n * Takes a performance entry type and a callback function, and creates a\n * `PerformanceObserver` instance that will observe the specified entry type\n * with buffering enabled and call the callback _for each entry_.\n *\n * This function also feature-detects entry support and wraps the logic in a\n * try/catch to avoid errors in unsupporting browsers.\n */\nexport const observe = <K extends keyof PerformanceEntryMap>(\n type: K,\n callback: (entries: PerformanceEntryMap[K]) => void,\n opts?: PerformanceObserverInit,\n): PerformanceObserver | undefined => {\n try {\n if (PerformanceObserver.supportedEntryTypes.includes(type)) {\n const po = new PerformanceObserver(list => {\n callback(list.getEntries() as PerformanceEntryMap[K]);\n });\n po.observe(\n Object.assign(\n {\n type,\n buffered: true,\n },\n opts || {},\n ) as PerformanceObserverInit,\n );\n return po;\n }\n } catch (e) {\n // Do nothing.\n }\n return;\n};\n"],"names":[],"mappings":"AAiCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,MAAM,UAAU;AACvB,EAAE,IAAI;AACN,EAAE,QAAQ;AACV,EAAE,IAAI;AACN,KAAsC;AACtC,EAAE,IAAI;AACN,IAAI,IAAI,mBAAmB,CAAC,mBAAmB,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE;AAChE,MAAM,MAAM,EAAG,GAAE,IAAI,mBAAmB,CAAC,QAAQ;AACjD,QAAQ,QAAQ,CAAC,IAAI,CAAC,UAAU,IAA6B,CAAA;AAC7D,OAAO,CAAC,CAAA;AACR,MAAM,EAAE,CAAC,OAAO;AAChB,QAAQ,MAAM,CAAC,MAAM;AACrB,UAAU;AACV,YAAY,IAAI;AAChB,YAAY,QAAQ,EAAE,IAAI;AAC1B,WAAW;AACX,UAAU,IAAA,IAAQ,EAAE;AACpB,SAAU;AACV,OAAO,CAAA;AACP,MAAM,OAAO,EAAE,CAAA;AACf,KAAI;AACJ,GAAI,CAAA,OAAO,CAAC,EAAE;AACd;AACA,GAAE;AACF,EAAE,OAAM;AACR;;;;"}
|
||||
39
node_modules/@sentry-internal/tracing/esm/browser/web-vitals/lib/onHidden.js
generated
vendored
Normal file
39
node_modules/@sentry-internal/tracing/esm/browser/web-vitals/lib/onHidden.js
generated
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
import { WINDOW } from '../../types.js';
|
||||
|
||||
/*
|
||||
* Copyright 2020 Google LLC
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.
|
||||
*/
|
||||
|
||||
const onHidden = (cb, once) => {
|
||||
const onHiddenOrPageHide = (event) => {
|
||||
if (event.type === 'pagehide' || WINDOW.document.visibilityState === 'hidden') {
|
||||
cb(event);
|
||||
if (once) {
|
||||
removeEventListener('visibilitychange', onHiddenOrPageHide, true);
|
||||
removeEventListener('pagehide', onHiddenOrPageHide, true);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (WINDOW.document) {
|
||||
addEventListener('visibilitychange', onHiddenOrPageHide, true);
|
||||
// Some browsers have buggy implementations of visibilitychange,
|
||||
// so we use pagehide in addition, just to be safe.
|
||||
addEventListener('pagehide', onHiddenOrPageHide, true);
|
||||
}
|
||||
};
|
||||
|
||||
export { onHidden };
|
||||
//# sourceMappingURL=onHidden.js.map
|
||||
1
node_modules/@sentry-internal/tracing/esm/browser/web-vitals/lib/onHidden.js.map
generated
vendored
Normal file
1
node_modules/@sentry-internal/tracing/esm/browser/web-vitals/lib/onHidden.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"onHidden.js","sources":["../../../../../src/browser/web-vitals/lib/onHidden.ts"],"sourcesContent":["/*\n * Copyright 2020 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { WINDOW } from '../../types';\n\nexport interface OnHiddenCallback {\n (event: Event): void;\n}\n\nexport const onHidden = (cb: OnHiddenCallback, once?: boolean): void => {\n const onHiddenOrPageHide = (event: Event): void => {\n if (event.type === 'pagehide' || WINDOW.document!.visibilityState === 'hidden') {\n cb(event);\n if (once) {\n removeEventListener('visibilitychange', onHiddenOrPageHide, true);\n removeEventListener('pagehide', onHiddenOrPageHide, true);\n }\n }\n };\n\n if (WINDOW.document) {\n addEventListener('visibilitychange', onHiddenOrPageHide, true);\n // Some browsers have buggy implementations of visibilitychange,\n // so we use pagehide in addition, just to be safe.\n addEventListener('pagehide', onHiddenOrPageHide, true);\n }\n};\n"],"names":[],"mappings":";;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;MAQa,QAAS,GAAE,CAAC,EAAE,EAAoB,IAAI,KAAqB;AACxE,EAAE,MAAM,kBAAA,GAAqB,CAAC,KAAK,KAAkB;AACrD,IAAI,IAAI,KAAK,CAAC,SAAS,UAAA,IAAc,MAAM,CAAC,QAAQ,CAAE,eAAgB,KAAI,QAAQ,EAAE;AACpF,MAAM,EAAE,CAAC,KAAK,CAAC,CAAA;AACf,MAAM,IAAI,IAAI,EAAE;AAChB,QAAQ,mBAAmB,CAAC,kBAAkB,EAAE,kBAAkB,EAAE,IAAI,CAAC,CAAA;AACzE,QAAQ,mBAAmB,CAAC,UAAU,EAAE,kBAAkB,EAAE,IAAI,CAAC,CAAA;AACjE,OAAM;AACN,KAAI;AACJ,GAAG,CAAA;AACH;AACA,EAAE,IAAI,MAAM,CAAC,QAAQ,EAAE;AACvB,IAAI,gBAAgB,CAAC,kBAAkB,EAAE,kBAAkB,EAAE,IAAI,CAAC,CAAA;AAClE;AACA;AACA,IAAI,gBAAgB,CAAC,UAAU,EAAE,kBAAkB,EAAE,IAAI,CAAC,CAAA;AAC1D,GAAE;AACF;;;;"}
|
||||
42
node_modules/@sentry-internal/tracing/esm/browser/web-vitals/lib/polyfills/interactionCountPolyfill.js
generated
vendored
Normal file
42
node_modules/@sentry-internal/tracing/esm/browser/web-vitals/lib/polyfills/interactionCountPolyfill.js
generated
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
import { observe } from '../observe.js';
|
||||
|
||||
let interactionCountEstimate = 0;
|
||||
let minKnownInteractionId = Infinity;
|
||||
let maxKnownInteractionId = 0;
|
||||
|
||||
const updateEstimate = (entries) => {
|
||||
(entries ).forEach(e => {
|
||||
if (e.interactionId) {
|
||||
minKnownInteractionId = Math.min(minKnownInteractionId, e.interactionId);
|
||||
maxKnownInteractionId = Math.max(maxKnownInteractionId, e.interactionId);
|
||||
|
||||
interactionCountEstimate = maxKnownInteractionId ? (maxKnownInteractionId - minKnownInteractionId) / 7 + 1 : 0;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
let po;
|
||||
|
||||
/**
|
||||
* Returns the `interactionCount` value using the native API (if available)
|
||||
* or the polyfill estimate in this module.
|
||||
*/
|
||||
const getInteractionCount = () => {
|
||||
return po ? interactionCountEstimate : performance.interactionCount || 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Feature detects native support or initializes the polyfill if needed.
|
||||
*/
|
||||
const initInteractionCountPolyfill = () => {
|
||||
if ('interactionCount' in performance || po) return;
|
||||
|
||||
po = observe('event', updateEstimate, {
|
||||
type: 'event',
|
||||
buffered: true,
|
||||
durationThreshold: 0,
|
||||
} );
|
||||
};
|
||||
|
||||
export { getInteractionCount, initInteractionCountPolyfill };
|
||||
//# sourceMappingURL=interactionCountPolyfill.js.map
|
||||
1
node_modules/@sentry-internal/tracing/esm/browser/web-vitals/lib/polyfills/interactionCountPolyfill.js.map
generated
vendored
Normal file
1
node_modules/@sentry-internal/tracing/esm/browser/web-vitals/lib/polyfills/interactionCountPolyfill.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"interactionCountPolyfill.js","sources":["../../../../../../src/browser/web-vitals/lib/polyfills/interactionCountPolyfill.ts"],"sourcesContent":["/*\n * Copyright 2022 Google LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * https://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type { Metric } from '../../types';\nimport { observe } from '../observe';\n\ndeclare global {\n interface Performance {\n interactionCount: number;\n }\n}\n\nlet interactionCountEstimate = 0;\nlet minKnownInteractionId = Infinity;\nlet maxKnownInteractionId = 0;\n\nconst updateEstimate = (entries: Metric['entries']): void => {\n (entries as PerformanceEventTiming[]).forEach(e => {\n if (e.interactionId) {\n minKnownInteractionId = Math.min(minKnownInteractionId, e.interactionId);\n maxKnownInteractionId = Math.max(maxKnownInteractionId, e.interactionId);\n\n interactionCountEstimate = maxKnownInteractionId ? (maxKnownInteractionId - minKnownInteractionId) / 7 + 1 : 0;\n }\n });\n};\n\nlet po: PerformanceObserver | undefined;\n\n/**\n * Returns the `interactionCount` value using the native API (if available)\n * or the polyfill estimate in this module.\n */\nexport const getInteractionCount = (): number => {\n return po ? interactionCountEstimate : performance.interactionCount || 0;\n};\n\n/**\n * Feature detects native support or initializes the polyfill if needed.\n */\nexport const initInteractionCountPolyfill = (): void => {\n if ('interactionCount' in performance || po) return;\n\n po = observe('event', updateEstimate, {\n type: 'event',\n buffered: true,\n durationThreshold: 0,\n } as PerformanceObserverInit);\n};\n"],"names":[],"mappings":";;AAyBA,IAAI,wBAAA,GAA2B,CAAC,CAAA;AAChC,IAAI,qBAAA,GAAwB,QAAQ,CAAA;AACpC,IAAI,qBAAA,GAAwB,CAAC,CAAA;AAC7B;AACA,MAAM,cAAe,GAAE,CAAC,OAAO,KAA8B;AAC7D,EAAE,CAAC,OAAQ,GAA6B,OAAO,CAAC,KAAK;AACrD,IAAI,IAAI,CAAC,CAAC,aAAa,EAAE;AACzB,MAAM,qBAAA,GAAwB,IAAI,CAAC,GAAG,CAAC,qBAAqB,EAAE,CAAC,CAAC,aAAa,CAAC,CAAA;AAC9E,MAAM,qBAAA,GAAwB,IAAI,CAAC,GAAG,CAAC,qBAAqB,EAAE,CAAC,CAAC,aAAa,CAAC,CAAA;AAC9E;AACA,MAAM,wBAAyB,GAAE,qBAAsB,GAAE,CAAC,qBAAsB,GAAE,qBAAqB,IAAI,CAAA,GAAI,CAAA,GAAI,CAAC,CAAA;AACpH,KAAI;AACJ,GAAG,CAAC,CAAA;AACJ,CAAC,CAAA;AACD;AACA,IAAI,EAAE,CAAA;AACN;AACA;AACA;AACA;AACA;AACa,MAAA,mBAAA,GAAsB,MAAc;AACjD,EAAE,OAAO,KAAK,wBAAA,GAA2B,WAAW,CAAC,gBAAiB,IAAG,CAAC,CAAA;AAC1E,EAAC;AACD;AACA;AACA;AACA;AACa,MAAA,4BAAA,GAA+B,MAAY;AACxD,EAAE,IAAI,kBAAmB,IAAG,eAAe,EAAE,EAAE,OAAM;AACrD;AACA,EAAE,KAAK,OAAO,CAAC,OAAO,EAAE,cAAc,EAAE;AACxC,IAAI,IAAI,EAAE,OAAO;AACjB,IAAI,QAAQ,EAAE,IAAI;AAClB,IAAI,iBAAiB,EAAE,CAAC;AACxB,KAA+B,CAAA;AAC/B;;;;"}
|
||||
92
node_modules/@sentry-internal/tracing/esm/browser/web-vitals/onTTFB.js
generated
vendored
Normal file
92
node_modules/@sentry-internal/tracing/esm/browser/web-vitals/onTTFB.js
generated
vendored
Normal file
@@ -0,0 +1,92 @@
|
||||
import { WINDOW } from '../types.js';
|
||||
import { bindReporter } from './lib/bindReporter.js';
|
||||
import { getActivationStart } from './lib/getActivationStart.js';
|
||||
import { getNavigationEntry } from './lib/getNavigationEntry.js';
|
||||
import { initMetric } from './lib/initMetric.js';
|
||||
|
||||
/*
|
||||
* Copyright 2020 Google LLC
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Runs in the next task after the page is done loading and/or prerendering.
|
||||
* @param callback
|
||||
*/
|
||||
const whenReady = (callback) => {
|
||||
if (!WINDOW.document) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (WINDOW.document.prerendering) {
|
||||
addEventListener('prerenderingchange', () => whenReady(callback), true);
|
||||
} else if (WINDOW.document.readyState !== 'complete') {
|
||||
addEventListener('load', () => whenReady(callback), true);
|
||||
} else {
|
||||
// Queue a task so the callback runs after `loadEventEnd`.
|
||||
setTimeout(callback, 0);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Calculates the [TTFB](https://web.dev/time-to-first-byte/) value for the
|
||||
* current page and calls the `callback` function once the page has loaded,
|
||||
* along with the relevant `navigation` performance entry used to determine the
|
||||
* value. The reported value is a `DOMHighResTimeStamp`.
|
||||
*
|
||||
* Note, this function waits until after the page is loaded to call `callback`
|
||||
* in order to ensure all properties of the `navigation` entry are populated.
|
||||
* This is useful if you want to report on other metrics exposed by the
|
||||
* [Navigation Timing API](https://w3c.github.io/navigation-timing/). For
|
||||
* example, the TTFB metric starts from the page's [time
|
||||
* origin](https://www.w3.org/TR/hr-time-2/#sec-time-origin), which means it
|
||||
* includes time spent on DNS lookup, connection negotiation, network latency,
|
||||
* and server processing time.
|
||||
*/
|
||||
const onTTFB = (onReport, opts) => {
|
||||
// Set defaults
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
opts = opts || {};
|
||||
|
||||
// https://web.dev/ttfb/#what-is-a-good-ttfb-score
|
||||
// const thresholds = [800, 1800];
|
||||
|
||||
const metric = initMetric('TTFB');
|
||||
const report = bindReporter(onReport, metric, opts.reportAllChanges);
|
||||
|
||||
whenReady(() => {
|
||||
const navEntry = getNavigationEntry() ;
|
||||
|
||||
if (navEntry) {
|
||||
// The activationStart reference is used because TTFB should be
|
||||
// relative to page activation rather than navigation start if the
|
||||
// page was prerendered. But in cases where `activationStart` occurs
|
||||
// after the first byte is received, this time should be clamped at 0.
|
||||
metric.value = Math.max(navEntry.responseStart - getActivationStart(), 0);
|
||||
|
||||
// In some cases the value reported is negative or is larger
|
||||
// than the current page time. Ignore these cases:
|
||||
// https://github.com/GoogleChrome/web-vitals/issues/137
|
||||
// https://github.com/GoogleChrome/web-vitals/issues/162
|
||||
if (metric.value < 0 || metric.value > performance.now()) return;
|
||||
|
||||
metric.entries = [navEntry];
|
||||
|
||||
report(true);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export { onTTFB };
|
||||
//# sourceMappingURL=onTTFB.js.map
|
||||
1
node_modules/@sentry-internal/tracing/esm/browser/web-vitals/onTTFB.js.map
generated
vendored
Normal file
1
node_modules/@sentry-internal/tracing/esm/browser/web-vitals/onTTFB.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
9
node_modules/@sentry-internal/tracing/esm/common/debug-build.js
generated
vendored
Normal file
9
node_modules/@sentry-internal/tracing/esm/common/debug-build.js
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
/**
|
||||
* This serves as a build time flag that will be true by default, but false in non-debug builds or if users replace `__SENTRY_DEBUG__` in their generated code.
|
||||
*
|
||||
* ATTENTION: This constant must never cross package boundaries (i.e. be exported) to guarantee that it can be used for tree shaking.
|
||||
*/
|
||||
const DEBUG_BUILD = (typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__);
|
||||
|
||||
export { DEBUG_BUILD };
|
||||
//# sourceMappingURL=debug-build.js.map
|
||||
1
node_modules/@sentry-internal/tracing/esm/common/debug-build.js.map
generated
vendored
Normal file
1
node_modules/@sentry-internal/tracing/esm/common/debug-build.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"debug-build.js","sources":["../../../src/common/debug-build.ts"],"sourcesContent":["declare const __DEBUG_BUILD__: boolean;\n\n/**\n * This serves as a build time flag that will be true by default, but false in non-debug builds or if users replace `__SENTRY_DEBUG__` in their generated code.\n *\n * ATTENTION: This constant must never cross package boundaries (i.e. be exported) to guarantee that it can be used for tree shaking.\n */\nexport const DEBUG_BUILD = __DEBUG_BUILD__;\n"],"names":[],"mappings":"AAEA;AACA;AACA;AACA;AACA;AACO,MAAM,WAAY,IAAE,OAAA,gBAAA,KAAA,WAAA,IAAA,gBAAA;;;;"}
|
||||
188
node_modules/@sentry-internal/tracing/esm/common/fetch.js
generated
vendored
Normal file
188
node_modules/@sentry-internal/tracing/esm/common/fetch.js
generated
vendored
Normal file
@@ -0,0 +1,188 @@
|
||||
import { hasTracingEnabled, getCurrentScope, getClient, startInactiveSpan, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, getIsolationScope, spanToTraceHeader, getDynamicSamplingContextFromSpan, getDynamicSamplingContextFromClient, setHttpStatus } from '@sentry/core';
|
||||
import { parseUrl, generateSentryTraceHeader, dynamicSamplingContextToSentryBaggageHeader, isInstanceOf, BAGGAGE_HEADER_NAME } from '@sentry/utils';
|
||||
|
||||
/**
|
||||
* Create and track fetch request spans for usage in combination with `addInstrumentationHandler`.
|
||||
*
|
||||
* @returns Span if a span was created, otherwise void.
|
||||
*/
|
||||
function instrumentFetchRequest(
|
||||
handlerData,
|
||||
shouldCreateSpan,
|
||||
shouldAttachHeaders,
|
||||
spans,
|
||||
spanOrigin = 'auto.http.browser',
|
||||
) {
|
||||
if (!hasTracingEnabled() || !handlerData.fetchData) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const shouldCreateSpanResult = shouldCreateSpan(handlerData.fetchData.url);
|
||||
|
||||
if (handlerData.endTimestamp && shouldCreateSpanResult) {
|
||||
const spanId = handlerData.fetchData.__span;
|
||||
if (!spanId) return;
|
||||
|
||||
const span = spans[spanId];
|
||||
if (span) {
|
||||
endSpan(span, handlerData);
|
||||
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
|
||||
delete spans[spanId];
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const scope = getCurrentScope();
|
||||
const client = getClient();
|
||||
|
||||
const { method, url } = handlerData.fetchData;
|
||||
|
||||
const fullUrl = getFullURL(url);
|
||||
const host = fullUrl ? parseUrl(fullUrl).host : undefined;
|
||||
|
||||
const span = shouldCreateSpanResult
|
||||
? startInactiveSpan({
|
||||
name: `${method} ${url}`,
|
||||
onlyIfParent: true,
|
||||
attributes: {
|
||||
url,
|
||||
type: 'fetch',
|
||||
'http.method': method,
|
||||
'http.url': fullUrl,
|
||||
'server.address': host,
|
||||
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: spanOrigin,
|
||||
},
|
||||
op: 'http.client',
|
||||
})
|
||||
: undefined;
|
||||
|
||||
if (span) {
|
||||
handlerData.fetchData.__span = span.spanContext().spanId;
|
||||
spans[span.spanContext().spanId] = span;
|
||||
}
|
||||
|
||||
if (shouldAttachHeaders(handlerData.fetchData.url) && client) {
|
||||
const request = handlerData.args[0];
|
||||
|
||||
// In case the user hasn't set the second argument of a fetch call we default it to `{}`.
|
||||
handlerData.args[1] = handlerData.args[1] || {};
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const options = handlerData.args[1];
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-member-access
|
||||
options.headers = addTracingHeadersToFetchRequest(request, client, scope, options, span);
|
||||
}
|
||||
|
||||
return span;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds sentry-trace and baggage headers to the various forms of fetch headers
|
||||
*/
|
||||
function addTracingHeadersToFetchRequest(
|
||||
request, // unknown is actually type Request but we can't export DOM types from this package,
|
||||
client,
|
||||
scope,
|
||||
options
|
||||
|
||||
,
|
||||
requestSpan,
|
||||
) {
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
const span = requestSpan || scope.getSpan();
|
||||
|
||||
const isolationScope = getIsolationScope();
|
||||
|
||||
const { traceId, spanId, sampled, dsc } = {
|
||||
...isolationScope.getPropagationContext(),
|
||||
...scope.getPropagationContext(),
|
||||
};
|
||||
|
||||
const sentryTraceHeader = span ? spanToTraceHeader(span) : generateSentryTraceHeader(traceId, spanId, sampled);
|
||||
|
||||
const sentryBaggageHeader = dynamicSamplingContextToSentryBaggageHeader(
|
||||
dsc ||
|
||||
(span ? getDynamicSamplingContextFromSpan(span) : getDynamicSamplingContextFromClient(traceId, client, scope)),
|
||||
);
|
||||
|
||||
const headers =
|
||||
options.headers ||
|
||||
(typeof Request !== 'undefined' && isInstanceOf(request, Request) ? (request ).headers : undefined);
|
||||
|
||||
if (!headers) {
|
||||
return { 'sentry-trace': sentryTraceHeader, baggage: sentryBaggageHeader };
|
||||
} else if (typeof Headers !== 'undefined' && isInstanceOf(headers, Headers)) {
|
||||
const newHeaders = new Headers(headers );
|
||||
|
||||
newHeaders.append('sentry-trace', sentryTraceHeader);
|
||||
|
||||
if (sentryBaggageHeader) {
|
||||
// If the same header is appended multiple times the browser will merge the values into a single request header.
|
||||
// Its therefore safe to simply push a "baggage" entry, even though there might already be another baggage header.
|
||||
newHeaders.append(BAGGAGE_HEADER_NAME, sentryBaggageHeader);
|
||||
}
|
||||
|
||||
return newHeaders ;
|
||||
} else if (Array.isArray(headers)) {
|
||||
const newHeaders = [...headers, ['sentry-trace', sentryTraceHeader]];
|
||||
|
||||
if (sentryBaggageHeader) {
|
||||
// If there are multiple entries with the same key, the browser will merge the values into a single request header.
|
||||
// Its therefore safe to simply push a "baggage" entry, even though there might already be another baggage header.
|
||||
newHeaders.push([BAGGAGE_HEADER_NAME, sentryBaggageHeader]);
|
||||
}
|
||||
|
||||
return newHeaders ;
|
||||
} else {
|
||||
const existingBaggageHeader = 'baggage' in headers ? headers.baggage : undefined;
|
||||
const newBaggageHeaders = [];
|
||||
|
||||
if (Array.isArray(existingBaggageHeader)) {
|
||||
newBaggageHeaders.push(...existingBaggageHeader);
|
||||
} else if (existingBaggageHeader) {
|
||||
newBaggageHeaders.push(existingBaggageHeader);
|
||||
}
|
||||
|
||||
if (sentryBaggageHeader) {
|
||||
newBaggageHeaders.push(sentryBaggageHeader);
|
||||
}
|
||||
|
||||
return {
|
||||
...(headers ),
|
||||
'sentry-trace': sentryTraceHeader,
|
||||
baggage: newBaggageHeaders.length > 0 ? newBaggageHeaders.join(',') : undefined,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function getFullURL(url) {
|
||||
try {
|
||||
const parsed = new URL(url);
|
||||
return parsed.href;
|
||||
} catch (e) {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
function endSpan(span, handlerData) {
|
||||
if (handlerData.response) {
|
||||
setHttpStatus(span, handlerData.response.status);
|
||||
|
||||
const contentLength =
|
||||
handlerData.response && handlerData.response.headers && handlerData.response.headers.get('content-length');
|
||||
|
||||
if (contentLength) {
|
||||
const contentLengthNum = parseInt(contentLength);
|
||||
if (contentLengthNum > 0) {
|
||||
span.setAttribute('http.response_content_length', contentLengthNum);
|
||||
}
|
||||
}
|
||||
} else if (handlerData.error) {
|
||||
span.setStatus('internal_error');
|
||||
}
|
||||
span.end();
|
||||
}
|
||||
|
||||
export { addTracingHeadersToFetchRequest, instrumentFetchRequest };
|
||||
//# sourceMappingURL=fetch.js.map
|
||||
1
node_modules/@sentry-internal/tracing/esm/common/fetch.js.map
generated
vendored
Normal file
1
node_modules/@sentry-internal/tracing/esm/common/fetch.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
69
node_modules/@sentry-internal/tracing/esm/extensions.js
generated
vendored
Normal file
69
node_modules/@sentry-internal/tracing/esm/extensions.js
generated
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
import { addTracingExtensions, getMainCarrier } from '@sentry/core';
|
||||
import { isNodeEnv, loadModule, dynamicRequire } from '@sentry/utils';
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
function _autoloadDatabaseIntegrations() {
|
||||
const carrier = getMainCarrier();
|
||||
if (!carrier.__SENTRY__) {
|
||||
return;
|
||||
}
|
||||
|
||||
const packageToIntegrationMapping = {
|
||||
mongodb() {
|
||||
const integration = dynamicRequire(module, './node/integrations/mongo')
|
||||
|
||||
;
|
||||
return new integration.Mongo();
|
||||
},
|
||||
mongoose() {
|
||||
const integration = dynamicRequire(module, './node/integrations/mongo')
|
||||
|
||||
;
|
||||
return new integration.Mongo();
|
||||
},
|
||||
mysql() {
|
||||
const integration = dynamicRequire(module, './node/integrations/mysql')
|
||||
|
||||
;
|
||||
return new integration.Mysql();
|
||||
},
|
||||
pg() {
|
||||
const integration = dynamicRequire(module, './node/integrations/postgres')
|
||||
|
||||
;
|
||||
return new integration.Postgres();
|
||||
},
|
||||
};
|
||||
|
||||
const mappedPackages = Object.keys(packageToIntegrationMapping)
|
||||
.filter(moduleName => !!loadModule(moduleName))
|
||||
.map(pkg => {
|
||||
try {
|
||||
return packageToIntegrationMapping[pkg]();
|
||||
} catch (e) {
|
||||
return undefined;
|
||||
}
|
||||
})
|
||||
.filter(p => p) ;
|
||||
|
||||
if (mappedPackages.length > 0) {
|
||||
carrier.__SENTRY__.integrations = [...(carrier.__SENTRY__.integrations || []), ...mappedPackages];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This patches the global object and injects the Tracing extensions methods
|
||||
*/
|
||||
function addExtensionMethods() {
|
||||
addTracingExtensions();
|
||||
|
||||
// Detect and automatically load specified integrations.
|
||||
if (isNodeEnv()) {
|
||||
_autoloadDatabaseIntegrations();
|
||||
}
|
||||
}
|
||||
|
||||
export { addExtensionMethods };
|
||||
//# sourceMappingURL=extensions.js.map
|
||||
1
node_modules/@sentry-internal/tracing/esm/extensions.js.map
generated
vendored
Normal file
1
node_modules/@sentry-internal/tracing/esm/extensions.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"extensions.js","sources":["../../src/extensions.ts"],"sourcesContent":["import { addTracingExtensions, getMainCarrier } from '@sentry/core';\nimport type { Integration, IntegrationClass } from '@sentry/types';\nimport { dynamicRequire, isNodeEnv, loadModule } from '@sentry/utils';\n\n/**\n * @private\n */\nfunction _autoloadDatabaseIntegrations(): void {\n const carrier = getMainCarrier();\n if (!carrier.__SENTRY__) {\n return;\n }\n\n const packageToIntegrationMapping: Record<string, () => Integration> = {\n mongodb() {\n const integration = dynamicRequire(module, './node/integrations/mongo') as {\n Mongo: IntegrationClass<Integration>;\n };\n return new integration.Mongo();\n },\n mongoose() {\n const integration = dynamicRequire(module, './node/integrations/mongo') as {\n Mongo: IntegrationClass<Integration>;\n };\n return new integration.Mongo();\n },\n mysql() {\n const integration = dynamicRequire(module, './node/integrations/mysql') as {\n Mysql: IntegrationClass<Integration>;\n };\n return new integration.Mysql();\n },\n pg() {\n const integration = dynamicRequire(module, './node/integrations/postgres') as {\n Postgres: IntegrationClass<Integration>;\n };\n return new integration.Postgres();\n },\n };\n\n const mappedPackages = Object.keys(packageToIntegrationMapping)\n .filter(moduleName => !!loadModule(moduleName))\n .map(pkg => {\n try {\n return packageToIntegrationMapping[pkg]();\n } catch (e) {\n return undefined;\n }\n })\n .filter(p => p) as Integration[];\n\n if (mappedPackages.length > 0) {\n carrier.__SENTRY__.integrations = [...(carrier.__SENTRY__.integrations || []), ...mappedPackages];\n }\n}\n\n/**\n * This patches the global object and injects the Tracing extensions methods\n */\nexport function addExtensionMethods(): void {\n addTracingExtensions();\n\n // Detect and automatically load specified integrations.\n if (isNodeEnv()) {\n _autoloadDatabaseIntegrations();\n }\n}\n"],"names":[],"mappings":";;;AAIA;AACA;AACA;AACA,SAAS,6BAA6B,GAAS;AAC/C,EAAE,MAAM,OAAA,GAAU,cAAc,EAAE,CAAA;AAClC,EAAE,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE;AAC3B,IAAI,OAAM;AACV,GAAE;AACF;AACA,EAAE,MAAM,2BAA2B,GAAsC;AACzE,IAAI,OAAO,GAAG;AACd,MAAM,MAAM,cAAc,cAAc,CAAC,MAAM,EAAE,2BAA2B,CAAE;;AAExE,CAAA;AACN,MAAM,OAAO,IAAI,WAAW,CAAC,KAAK,EAAE,CAAA;AACpC,KAAK;AACL,IAAI,QAAQ,GAAG;AACf,MAAM,MAAM,cAAc,cAAc,CAAC,MAAM,EAAE,2BAA2B,CAAE;;AAExE,CAAA;AACN,MAAM,OAAO,IAAI,WAAW,CAAC,KAAK,EAAE,CAAA;AACpC,KAAK;AACL,IAAI,KAAK,GAAG;AACZ,MAAM,MAAM,cAAc,cAAc,CAAC,MAAM,EAAE,2BAA2B,CAAE;;AAExE,CAAA;AACN,MAAM,OAAO,IAAI,WAAW,CAAC,KAAK,EAAE,CAAA;AACpC,KAAK;AACL,IAAI,EAAE,GAAG;AACT,MAAM,MAAM,cAAc,cAAc,CAAC,MAAM,EAAE,8BAA8B,CAAE;;AAE3E,CAAA;AACN,MAAM,OAAO,IAAI,WAAW,CAAC,QAAQ,EAAE,CAAA;AACvC,KAAK;AACL,GAAG,CAAA;AACH;AACA,EAAE,MAAM,cAAe,GAAE,MAAM,CAAC,IAAI,CAAC,2BAA2B,CAAA;AAChE,KAAK,MAAM,CAAC,UAAW,IAAG,CAAC,CAAC,UAAU,CAAC,UAAU,CAAC,CAAA;AAClD,KAAK,GAAG,CAAC,GAAA,IAAO;AAChB,MAAM,IAAI;AACV,QAAQ,OAAO,2BAA2B,CAAC,GAAG,CAAC,EAAE,CAAA;AACjD,OAAQ,CAAA,OAAO,CAAC,EAAE;AAClB,QAAQ,OAAO,SAAS,CAAA;AACxB,OAAM;AACN,KAAK,CAAA;AACL,KAAK,MAAM,CAAC,CAAE,IAAG,CAAC,CAAE,EAAA;AACpB;AACA,EAAE,IAAI,cAAc,CAAC,MAAO,GAAE,CAAC,EAAE;AACjC,IAAI,OAAO,CAAC,UAAU,CAAC,eAAe,CAAC,IAAI,OAAO,CAAC,UAAU,CAAC,gBAAgB,EAAE,CAAC,EAAE,GAAG,cAAc,CAAC,CAAA;AACrG,GAAE;AACF,CAAA;AACA;AACA;AACA;AACA;AACO,SAAS,mBAAmB,GAAS;AAC5C,EAAE,oBAAoB,EAAE,CAAA;AACxB;AACA;AACA,EAAE,IAAI,SAAS,EAAE,EAAE;AACnB,IAAI,6BAA6B,EAAE,CAAA;AACnC,GAAE;AACF;;;;"}
|
||||
17
node_modules/@sentry-internal/tracing/esm/index.js
generated
vendored
Normal file
17
node_modules/@sentry-internal/tracing/esm/index.js
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
export { IdleTransaction, Span, SpanStatus, Transaction, extractTraceparentData, getActiveTransaction, hasTracingEnabled, spanStatusfromHttpCode, startIdleTransaction } from '@sentry/core';
|
||||
export { TRACEPARENT_REGEXP, stripUrlQueryAndFragment } from '@sentry/utils';
|
||||
export { Express } from './node/integrations/express.js';
|
||||
export { Postgres } from './node/integrations/postgres.js';
|
||||
export { Mysql } from './node/integrations/mysql.js';
|
||||
export { Mongo } from './node/integrations/mongo.js';
|
||||
export { Prisma } from './node/integrations/prisma.js';
|
||||
export { GraphQL } from './node/integrations/graphql.js';
|
||||
export { Apollo } from './node/integrations/apollo.js';
|
||||
export { lazyLoadedNodePerformanceMonitoringIntegrations } from './node/integrations/lazy.js';
|
||||
export { BROWSER_TRACING_INTEGRATION_ID, BrowserTracing } from './browser/browsertracing.js';
|
||||
export { browserTracingIntegration, startBrowserTracingNavigationSpan, startBrowserTracingPageLoadSpan } from './browser/browserTracingIntegration.js';
|
||||
export { defaultRequestInstrumentationOptions, instrumentOutgoingRequests } from './browser/request.js';
|
||||
export { addClsInstrumentationHandler, addFidInstrumentationHandler, addLcpInstrumentationHandler, addPerformanceInstrumentationHandler } from './browser/instrument.js';
|
||||
export { addTracingHeadersToFetchRequest, instrumentFetchRequest } from './common/fetch.js';
|
||||
export { addExtensionMethods } from './extensions.js';
|
||||
//# sourceMappingURL=index.js.map
|
||||
1
node_modules/@sentry-internal/tracing/esm/index.js.map
generated
vendored
Normal file
1
node_modules/@sentry-internal/tracing/esm/index.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;"}
|
||||
186
node_modules/@sentry-internal/tracing/esm/node/integrations/apollo.js
generated
vendored
Normal file
186
node_modules/@sentry-internal/tracing/esm/node/integrations/apollo.js
generated
vendored
Normal file
@@ -0,0 +1,186 @@
|
||||
import { _optionalChain } from '@sentry/utils';
|
||||
import { loadModule, logger, fill, arrayify, isThenable } from '@sentry/utils';
|
||||
import { DEBUG_BUILD } from '../../common/debug-build.js';
|
||||
import { shouldDisableAutoInstrumentation } from './utils/node-utils.js';
|
||||
|
||||
/** Tracing integration for Apollo */
|
||||
class Apollo {
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
static __initStatic() {this.id = 'Apollo';}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
constructor(
|
||||
options = {
|
||||
useNestjs: false,
|
||||
},
|
||||
) {
|
||||
this.name = Apollo.id;
|
||||
this._useNest = !!options.useNestjs;
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
loadDependency() {
|
||||
if (this._useNest) {
|
||||
this._module = this._module || loadModule('@nestjs/graphql');
|
||||
} else {
|
||||
this._module = this._module || loadModule('apollo-server-core');
|
||||
}
|
||||
|
||||
return this._module;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
setupOnce(_, getCurrentHub) {
|
||||
if (shouldDisableAutoInstrumentation(getCurrentHub)) {
|
||||
DEBUG_BUILD && logger.log('Apollo Integration is skipped because of instrumenter configuration.');
|
||||
return;
|
||||
}
|
||||
|
||||
if (this._useNest) {
|
||||
const pkg = this.loadDependency();
|
||||
|
||||
if (!pkg) {
|
||||
DEBUG_BUILD && logger.error('Apollo-NestJS Integration was unable to require @nestjs/graphql package.');
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterate over resolvers of NestJS ResolversExplorerService before schemas are constructed.
|
||||
*/
|
||||
fill(
|
||||
pkg.GraphQLFactory.prototype,
|
||||
'mergeWithSchema',
|
||||
function (orig) {
|
||||
return function (
|
||||
|
||||
...args
|
||||
) {
|
||||
fill(this.resolversExplorerService, 'explore', function (orig) {
|
||||
return function () {
|
||||
const resolvers = arrayify(orig.call(this));
|
||||
|
||||
const instrumentedResolvers = instrumentResolvers(resolvers, getCurrentHub);
|
||||
|
||||
return instrumentedResolvers;
|
||||
};
|
||||
});
|
||||
|
||||
return orig.call(this, ...args);
|
||||
};
|
||||
},
|
||||
);
|
||||
} else {
|
||||
const pkg = this.loadDependency();
|
||||
|
||||
if (!pkg) {
|
||||
DEBUG_BUILD && logger.error('Apollo Integration was unable to require apollo-server-core package.');
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterate over resolvers of the ApolloServer instance before schemas are constructed.
|
||||
*/
|
||||
fill(pkg.ApolloServerBase.prototype, 'constructSchema', function (orig) {
|
||||
return function (
|
||||
|
||||
) {
|
||||
if (!this.config.resolvers) {
|
||||
if (DEBUG_BUILD) {
|
||||
if (this.config.schema) {
|
||||
logger.warn(
|
||||
'Apollo integration is not able to trace `ApolloServer` instances constructed via `schema` property.' +
|
||||
'If you are using NestJS with Apollo, please use `Sentry.Integrations.Apollo({ useNestjs: true })` instead.',
|
||||
);
|
||||
logger.warn();
|
||||
} else if (this.config.modules) {
|
||||
logger.warn(
|
||||
'Apollo integration is not able to trace `ApolloServer` instances constructed via `modules` property.',
|
||||
);
|
||||
}
|
||||
|
||||
logger.error('Skipping tracing as no resolvers found on the `ApolloServer` instance.');
|
||||
}
|
||||
|
||||
return orig.call(this);
|
||||
}
|
||||
|
||||
const resolvers = arrayify(this.config.resolvers);
|
||||
|
||||
this.config.resolvers = instrumentResolvers(resolvers, getCurrentHub);
|
||||
|
||||
return orig.call(this);
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
}Apollo.__initStatic();
|
||||
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
function instrumentResolvers(resolvers, getCurrentHub) {
|
||||
return resolvers.map(model => {
|
||||
Object.keys(model).forEach(resolverGroupName => {
|
||||
Object.keys(model[resolverGroupName]).forEach(resolverName => {
|
||||
if (typeof model[resolverGroupName][resolverName] !== 'function') {
|
||||
return;
|
||||
}
|
||||
|
||||
wrapResolver(model, resolverGroupName, resolverName, getCurrentHub);
|
||||
});
|
||||
});
|
||||
|
||||
return model;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap a single resolver which can be a parent of other resolvers and/or db operations.
|
||||
*/
|
||||
function wrapResolver(
|
||||
model,
|
||||
resolverGroupName,
|
||||
resolverName,
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
getCurrentHub,
|
||||
) {
|
||||
fill(model[resolverGroupName], resolverName, function (orig) {
|
||||
return function ( ...args) {
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
const scope = getCurrentHub().getScope();
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
const parentSpan = scope.getSpan();
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
const span = _optionalChain([parentSpan, 'optionalAccess', _2 => _2.startChild, 'call', _3 => _3({
|
||||
description: `${resolverGroupName}.${resolverName}`,
|
||||
op: 'graphql.resolve',
|
||||
origin: 'auto.graphql.apollo',
|
||||
})]);
|
||||
|
||||
const rv = orig.call(this, ...args);
|
||||
|
||||
if (isThenable(rv)) {
|
||||
return rv.then((res) => {
|
||||
_optionalChain([span, 'optionalAccess', _4 => _4.end, 'call', _5 => _5()]);
|
||||
return res;
|
||||
});
|
||||
}
|
||||
|
||||
_optionalChain([span, 'optionalAccess', _6 => _6.end, 'call', _7 => _7()]);
|
||||
|
||||
return rv;
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
export { Apollo };
|
||||
//# sourceMappingURL=apollo.js.map
|
||||
1
node_modules/@sentry-internal/tracing/esm/node/integrations/apollo.js.map
generated
vendored
Normal file
1
node_modules/@sentry-internal/tracing/esm/node/integrations/apollo.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
488
node_modules/@sentry-internal/tracing/esm/node/integrations/express.js
generated
vendored
Normal file
488
node_modules/@sentry-internal/tracing/esm/node/integrations/express.js
generated
vendored
Normal file
@@ -0,0 +1,488 @@
|
||||
import { _optionalChain } from '@sentry/utils';
|
||||
import { spanToJSON, SEMANTIC_ATTRIBUTE_SENTRY_SOURCE } from '@sentry/core';
|
||||
import { logger, getNumberOfUrlSegments, stripUrlQueryAndFragment, extractPathForTransaction, isRegExp, GLOBAL_OBJ } from '@sentry/utils';
|
||||
import { DEBUG_BUILD } from '../../common/debug-build.js';
|
||||
import { shouldDisableAutoInstrumentation } from './utils/node-utils.js';
|
||||
|
||||
/* eslint-disable max-lines */
|
||||
|
||||
/**
|
||||
* Express integration
|
||||
*
|
||||
* Provides an request and error handler for Express framework as well as tracing capabilities
|
||||
*/
|
||||
class Express {
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
static __initStatic() {this.id = 'Express';}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
/**
|
||||
* Express App instance
|
||||
*/
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
constructor(options = {}) {
|
||||
this.name = Express.id;
|
||||
this._router = options.router || options.app;
|
||||
this._methods = (Array.isArray(options.methods) ? options.methods : []).concat('use');
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
setupOnce(_, getCurrentHub) {
|
||||
if (!this._router) {
|
||||
DEBUG_BUILD && logger.error('ExpressIntegration is missing an Express instance');
|
||||
return;
|
||||
}
|
||||
|
||||
if (shouldDisableAutoInstrumentation(getCurrentHub)) {
|
||||
DEBUG_BUILD && logger.log('Express Integration is skipped because of instrumenter configuration.');
|
||||
return;
|
||||
}
|
||||
|
||||
instrumentMiddlewares(this._router, this._methods);
|
||||
instrumentRouter(this._router );
|
||||
}
|
||||
}Express.__initStatic();
|
||||
|
||||
/**
|
||||
* Wraps original middleware function in a tracing call, which stores the info about the call as a span,
|
||||
* and finishes it once the middleware is done invoking.
|
||||
*
|
||||
* Express middlewares have 3 various forms, thus we have to take care of all of them:
|
||||
* // sync
|
||||
* app.use(function (req, res) { ... })
|
||||
* // async
|
||||
* app.use(function (req, res, next) { ... })
|
||||
* // error handler
|
||||
* app.use(function (err, req, res, next) { ... })
|
||||
*
|
||||
* They all internally delegate to the `router[method]` of the given application instance.
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types, @typescript-eslint/no-explicit-any
|
||||
function wrap(fn, method) {
|
||||
const arity = fn.length;
|
||||
|
||||
switch (arity) {
|
||||
case 2: {
|
||||
return function ( req, res) {
|
||||
const transaction = res.__sentry_transaction;
|
||||
if (transaction) {
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
const span = transaction.startChild({
|
||||
description: fn.name,
|
||||
op: `middleware.express.${method}`,
|
||||
origin: 'auto.middleware.express',
|
||||
});
|
||||
res.once('finish', () => {
|
||||
span.end();
|
||||
});
|
||||
}
|
||||
return fn.call(this, req, res);
|
||||
};
|
||||
}
|
||||
case 3: {
|
||||
return function (
|
||||
|
||||
req,
|
||||
res,
|
||||
next,
|
||||
) {
|
||||
const transaction = res.__sentry_transaction;
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
const span = _optionalChain([transaction, 'optionalAccess', _2 => _2.startChild, 'call', _3 => _3({
|
||||
description: fn.name,
|
||||
op: `middleware.express.${method}`,
|
||||
origin: 'auto.middleware.express',
|
||||
})]);
|
||||
fn.call(this, req, res, function ( ...args) {
|
||||
_optionalChain([span, 'optionalAccess', _4 => _4.end, 'call', _5 => _5()]);
|
||||
next.call(this, ...args);
|
||||
});
|
||||
};
|
||||
}
|
||||
case 4: {
|
||||
return function (
|
||||
|
||||
err,
|
||||
req,
|
||||
res,
|
||||
next,
|
||||
) {
|
||||
const transaction = res.__sentry_transaction;
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
const span = _optionalChain([transaction, 'optionalAccess', _6 => _6.startChild, 'call', _7 => _7({
|
||||
description: fn.name,
|
||||
op: `middleware.express.${method}`,
|
||||
origin: 'auto.middleware.express',
|
||||
})]);
|
||||
fn.call(this, err, req, res, function ( ...args) {
|
||||
_optionalChain([span, 'optionalAccess', _8 => _8.end, 'call', _9 => _9()]);
|
||||
next.call(this, ...args);
|
||||
});
|
||||
};
|
||||
}
|
||||
default: {
|
||||
throw new Error(`Express middleware takes 2-4 arguments. Got: ${arity}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes all the function arguments passed to the original `app` or `router` method, eg. `app.use` or `router.use`
|
||||
* and wraps every function, as well as array of functions with a call to our `wrap` method.
|
||||
* We have to take care of the arrays as well as iterate over all of the arguments,
|
||||
* as `app.use` can accept middlewares in few various forms.
|
||||
*
|
||||
* app.use([<path>], <fn>)
|
||||
* app.use([<path>], <fn>, ...<fn>)
|
||||
* app.use([<path>], ...<fn>[])
|
||||
*/
|
||||
function wrapMiddlewareArgs(args, method) {
|
||||
return args.map((arg) => {
|
||||
if (typeof arg === 'function') {
|
||||
return wrap(arg, method);
|
||||
}
|
||||
|
||||
if (Array.isArray(arg)) {
|
||||
return arg.map((a) => {
|
||||
if (typeof a === 'function') {
|
||||
return wrap(a, method);
|
||||
}
|
||||
return a;
|
||||
});
|
||||
}
|
||||
|
||||
return arg;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Patches original router to utilize our tracing functionality
|
||||
*/
|
||||
function patchMiddleware(router, method) {
|
||||
const originalCallback = router[method];
|
||||
|
||||
router[method] = function (...args) {
|
||||
return originalCallback.call(this, ...wrapMiddlewareArgs(args, method));
|
||||
};
|
||||
|
||||
return router;
|
||||
}
|
||||
|
||||
/**
|
||||
* Patches original router methods
|
||||
*/
|
||||
function instrumentMiddlewares(router, methods = []) {
|
||||
methods.forEach((method) => patchMiddleware(router, method));
|
||||
}
|
||||
|
||||
/**
|
||||
* Patches the prototype of Express.Router to accumulate the resolved route
|
||||
* if a layer instance's `match` function was called and it returned a successful match.
|
||||
*
|
||||
* @see https://github.com/expressjs/express/blob/master/lib/router/index.js
|
||||
*
|
||||
* @param appOrRouter the router instance which can either be an app (i.e. top-level) or a (nested) router.
|
||||
*/
|
||||
function instrumentRouter(appOrRouter) {
|
||||
// This is how we can distinguish between app and routers
|
||||
const isApp = 'settings' in appOrRouter;
|
||||
|
||||
// In case the app's top-level router hasn't been initialized yet, we have to do it now
|
||||
if (isApp && appOrRouter._router === undefined && appOrRouter.lazyrouter) {
|
||||
appOrRouter.lazyrouter();
|
||||
}
|
||||
|
||||
const router = isApp ? appOrRouter._router : appOrRouter;
|
||||
|
||||
if (!router) {
|
||||
/*
|
||||
If we end up here, this means likely that this integration is used with Express 3 or Express 5.
|
||||
For now, we don't support these versions (3 is very old and 5 is still in beta). To support Express 5,
|
||||
we'd need to make more changes to the routing instrumentation because the router is no longer part of
|
||||
the Express core package but maintained in its own package. The new router has different function
|
||||
signatures and works slightly differently, demanding more changes than just taking the router from
|
||||
`app.router` instead of `app._router`.
|
||||
@see https://github.com/pillarjs/router
|
||||
|
||||
TODO: Proper Express 5 support
|
||||
*/
|
||||
DEBUG_BUILD && logger.debug('Cannot instrument router for URL Parameterization (did not find a valid router).');
|
||||
DEBUG_BUILD && logger.debug('Routing instrumentation is currently only supported in Express 4.');
|
||||
return;
|
||||
}
|
||||
|
||||
const routerProto = Object.getPrototypeOf(router) ;
|
||||
|
||||
const originalProcessParams = routerProto.process_params;
|
||||
routerProto.process_params = function process_params(
|
||||
layer,
|
||||
called,
|
||||
req,
|
||||
res,
|
||||
done,
|
||||
) {
|
||||
// Base case: We're in the first part of the URL (thus we start with the root '/')
|
||||
if (!req._reconstructedRoute) {
|
||||
req._reconstructedRoute = '';
|
||||
}
|
||||
|
||||
// If the layer's partial route has params, is a regex or an array, the route is stored in layer.route.
|
||||
const { layerRoutePath, isRegex, isArray, numExtraSegments } = getLayerRoutePathInfo(layer);
|
||||
|
||||
if (layerRoutePath || isRegex || isArray) {
|
||||
req._hasParameters = true;
|
||||
}
|
||||
|
||||
// Otherwise, the hardcoded path (i.e. a partial route without params) is stored in layer.path
|
||||
let partialRoute;
|
||||
|
||||
if (layerRoutePath) {
|
||||
partialRoute = layerRoutePath;
|
||||
} else {
|
||||
/**
|
||||
* prevent duplicate segment in _reconstructedRoute param if router match multiple routes before final path
|
||||
* example:
|
||||
* original url: /api/v1/1234
|
||||
* prevent: /api/api/v1/:userId
|
||||
* router structure
|
||||
* /api -> middleware
|
||||
* /api/v1 -> middleware
|
||||
* /1234 -> endpoint with param :userId
|
||||
* final _reconstructedRoute is /api/v1/:userId
|
||||
*/
|
||||
partialRoute = preventDuplicateSegments(req.originalUrl, req._reconstructedRoute, layer.path) || '';
|
||||
}
|
||||
|
||||
// Normalize the partial route so that it doesn't contain leading or trailing slashes
|
||||
// and exclude empty or '*' wildcard routes.
|
||||
// The exclusion of '*' routes is our best effort to not "pollute" the transaction name
|
||||
// with interim handlers (e.g. ones that check authentication or do other middleware stuff).
|
||||
// We want to end up with the parameterized URL of the incoming request without any extraneous path segments.
|
||||
const finalPartialRoute = partialRoute
|
||||
.split('/')
|
||||
.filter(segment => segment.length > 0 && (isRegex || isArray || !segment.includes('*')))
|
||||
.join('/');
|
||||
|
||||
// If we found a valid partial URL, we append it to the reconstructed route
|
||||
if (finalPartialRoute && finalPartialRoute.length > 0) {
|
||||
// If the partial route is from a regex route, we append a '/' to close the regex
|
||||
req._reconstructedRoute += `/${finalPartialRoute}${isRegex ? '/' : ''}`;
|
||||
}
|
||||
|
||||
// Now we check if we are in the "last" part of the route. We determine this by comparing the
|
||||
// number of URL segments from the original URL to that of our reconstructed parameterized URL.
|
||||
// If we've reached our final destination, we update the transaction name.
|
||||
const urlLength = getNumberOfUrlSegments(stripUrlQueryAndFragment(req.originalUrl || '')) + numExtraSegments;
|
||||
const routeLength = getNumberOfUrlSegments(req._reconstructedRoute);
|
||||
|
||||
if (urlLength === routeLength) {
|
||||
if (!req._hasParameters) {
|
||||
if (req._reconstructedRoute !== req.originalUrl) {
|
||||
req._reconstructedRoute = req.originalUrl ? stripUrlQueryAndFragment(req.originalUrl) : req.originalUrl;
|
||||
}
|
||||
}
|
||||
|
||||
const transaction = res.__sentry_transaction;
|
||||
const attributes = (transaction && spanToJSON(transaction).data) || {};
|
||||
if (transaction && attributes[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE] !== 'custom') {
|
||||
// If the request URL is '/' or empty, the reconstructed route will be empty.
|
||||
// Therefore, we fall back to setting the final route to '/' in this case.
|
||||
const finalRoute = req._reconstructedRoute || '/';
|
||||
|
||||
const [name, source] = extractPathForTransaction(req, { path: true, method: true, customRoute: finalRoute });
|
||||
transaction.updateName(name);
|
||||
transaction.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, source);
|
||||
}
|
||||
}
|
||||
|
||||
return originalProcessParams.call(this, layer, called, req, res, done);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Recreate layer.route.path from layer.regexp and layer.keys.
|
||||
* Works until express.js used package path-to-regexp@0.1.7
|
||||
* or until layer.keys contain offset attribute
|
||||
*
|
||||
* @param layer the layer to extract the stringified route from
|
||||
*
|
||||
* @returns string in layer.route.path structure 'router/:pathParam' or undefined
|
||||
*/
|
||||
const extractOriginalRoute = (
|
||||
path,
|
||||
regexp,
|
||||
keys,
|
||||
) => {
|
||||
if (!path || !regexp || !keys || Object.keys(keys).length === 0 || !_optionalChain([keys, 'access', _10 => _10[0], 'optionalAccess', _11 => _11.offset])) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const orderedKeys = keys.sort((a, b) => a.offset - b.offset);
|
||||
|
||||
// add d flag for getting indices from regexp result
|
||||
// eslint-disable-next-line @sentry-internal/sdk/no-regexp-constructor -- regexp comes from express.js
|
||||
const pathRegex = new RegExp(regexp, `${regexp.flags}d`);
|
||||
/**
|
||||
* use custom type cause of TS error with missing indices in RegExpExecArray
|
||||
*/
|
||||
const execResult = pathRegex.exec(path) ;
|
||||
|
||||
if (!execResult || !execResult.indices) {
|
||||
return undefined;
|
||||
}
|
||||
/**
|
||||
* remove first match from regex cause contain whole layer.path
|
||||
*/
|
||||
const [, ...paramIndices] = execResult.indices;
|
||||
|
||||
if (paramIndices.length !== orderedKeys.length) {
|
||||
return undefined;
|
||||
}
|
||||
let resultPath = path;
|
||||
let indexShift = 0;
|
||||
|
||||
/**
|
||||
* iterate param matches from regexp.exec
|
||||
*/
|
||||
paramIndices.forEach((item, index) => {
|
||||
/** check if offsets is define because in some cases regex d flag returns undefined */
|
||||
if (item) {
|
||||
const [startOffset, endOffset] = item;
|
||||
/**
|
||||
* isolate part before param
|
||||
*/
|
||||
const substr1 = resultPath.substring(0, startOffset - indexShift);
|
||||
/**
|
||||
* define paramName as replacement in format :pathParam
|
||||
*/
|
||||
const replacement = `:${orderedKeys[index].name}`;
|
||||
|
||||
/**
|
||||
* isolate part after param
|
||||
*/
|
||||
const substr2 = resultPath.substring(endOffset - indexShift);
|
||||
|
||||
/**
|
||||
* recreate original path but with param replacement
|
||||
*/
|
||||
resultPath = substr1 + replacement + substr2;
|
||||
|
||||
/**
|
||||
* calculate new index shift after resultPath was modified
|
||||
*/
|
||||
indexShift = indexShift + (endOffset - startOffset - replacement.length);
|
||||
}
|
||||
});
|
||||
|
||||
return resultPath;
|
||||
};
|
||||
|
||||
/**
|
||||
* Extracts and stringifies the layer's route which can either be a string with parameters (`users/:id`),
|
||||
* a RegEx (`/test/`) or an array of strings and regexes (`['/path1', /\/path[2-5]/, /path/:id]`). Additionally
|
||||
* returns extra information about the route, such as if the route is defined as regex or as an array.
|
||||
*
|
||||
* @param layer the layer to extract the stringified route from
|
||||
*
|
||||
* @returns an object containing the stringified route, a flag determining if the route was a regex
|
||||
* and the number of extra segments to the matched path that are additionally in the route,
|
||||
* if the route was an array (defaults to 0).
|
||||
*/
|
||||
function getLayerRoutePathInfo(layer) {
|
||||
let lrp = _optionalChain([layer, 'access', _12 => _12.route, 'optionalAccess', _13 => _13.path]);
|
||||
|
||||
const isRegex = isRegExp(lrp);
|
||||
const isArray = Array.isArray(lrp);
|
||||
|
||||
if (!lrp) {
|
||||
// parse node.js major version
|
||||
// Next.js will complain if we directly use `proces.versions` here because of edge runtime.
|
||||
const [major] = (GLOBAL_OBJ ).process.versions.node.split('.').map(Number);
|
||||
|
||||
// allow call extractOriginalRoute only if node version support Regex d flag, node 16+
|
||||
if (major >= 16) {
|
||||
/**
|
||||
* If lrp does not exist try to recreate original layer path from route regexp
|
||||
*/
|
||||
lrp = extractOriginalRoute(layer.path, layer.regexp, layer.keys);
|
||||
}
|
||||
}
|
||||
|
||||
if (!lrp) {
|
||||
return { isRegex, isArray, numExtraSegments: 0 };
|
||||
}
|
||||
|
||||
const numExtraSegments = isArray
|
||||
? Math.max(getNumberOfArrayUrlSegments(lrp ) - getNumberOfUrlSegments(layer.path || ''), 0)
|
||||
: 0;
|
||||
|
||||
const layerRoutePath = getLayerRoutePathString(isArray, lrp);
|
||||
|
||||
return { layerRoutePath, isRegex, isArray, numExtraSegments };
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of URL segments in an array of routes
|
||||
*
|
||||
* Example: ['/api/test', /\/api\/post[0-9]/, '/users/:id/details`] -> 7
|
||||
*/
|
||||
function getNumberOfArrayUrlSegments(routesArray) {
|
||||
return routesArray.reduce((accNumSegments, currentRoute) => {
|
||||
// array members can be a RegEx -> convert them toString
|
||||
return accNumSegments + getNumberOfUrlSegments(currentRoute.toString());
|
||||
}, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts and returns the stringified version of the layers route path
|
||||
* Handles route arrays (by joining the paths together) as well as RegExp and normal
|
||||
* string values (in the latter case the toString conversion is technically unnecessary but
|
||||
* it doesn't hurt us either).
|
||||
*/
|
||||
function getLayerRoutePathString(isArray, lrp) {
|
||||
if (isArray) {
|
||||
return (lrp ).map(r => r.toString()).join(',');
|
||||
}
|
||||
return lrp && lrp.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* remove duplicate segment contain in layerPath against reconstructedRoute,
|
||||
* and return only unique segment that can be added into reconstructedRoute
|
||||
*/
|
||||
function preventDuplicateSegments(
|
||||
originalUrl,
|
||||
reconstructedRoute,
|
||||
layerPath,
|
||||
) {
|
||||
// filter query params
|
||||
const normalizeURL = stripUrlQueryAndFragment(originalUrl || '');
|
||||
const originalUrlSplit = _optionalChain([normalizeURL, 'optionalAccess', _14 => _14.split, 'call', _15 => _15('/'), 'access', _16 => _16.filter, 'call', _17 => _17(v => !!v)]);
|
||||
let tempCounter = 0;
|
||||
const currentOffset = _optionalChain([reconstructedRoute, 'optionalAccess', _18 => _18.split, 'call', _19 => _19('/'), 'access', _20 => _20.filter, 'call', _21 => _21(v => !!v), 'access', _22 => _22.length]) || 0;
|
||||
const result = _optionalChain([layerPath
|
||||
, 'optionalAccess', _23 => _23.split, 'call', _24 => _24('/')
|
||||
, 'access', _25 => _25.filter, 'call', _26 => _26(segment => {
|
||||
if (_optionalChain([originalUrlSplit, 'optionalAccess', _27 => _27[currentOffset + tempCounter]]) === segment) {
|
||||
tempCounter += 1;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
})
|
||||
, 'access', _28 => _28.join, 'call', _29 => _29('/')]);
|
||||
return result;
|
||||
}
|
||||
|
||||
export { Express, extractOriginalRoute, preventDuplicateSegments };
|
||||
//# sourceMappingURL=express.js.map
|
||||
1
node_modules/@sentry-internal/tracing/esm/node/integrations/express.js.map
generated
vendored
Normal file
1
node_modules/@sentry-internal/tracing/esm/node/integrations/express.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
82
node_modules/@sentry-internal/tracing/esm/node/integrations/graphql.js
generated
vendored
Normal file
82
node_modules/@sentry-internal/tracing/esm/node/integrations/graphql.js
generated
vendored
Normal file
@@ -0,0 +1,82 @@
|
||||
import { _optionalChain } from '@sentry/utils';
|
||||
import { loadModule, logger, fill, isThenable } from '@sentry/utils';
|
||||
import { DEBUG_BUILD } from '../../common/debug-build.js';
|
||||
import { shouldDisableAutoInstrumentation } from './utils/node-utils.js';
|
||||
|
||||
/** Tracing integration for graphql package */
|
||||
class GraphQL {
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
static __initStatic() {this.id = 'GraphQL';}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
constructor() {
|
||||
this.name = GraphQL.id;
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
loadDependency() {
|
||||
return (this._module = this._module || loadModule('graphql/execution/execute.js'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
setupOnce(_, getCurrentHub) {
|
||||
if (shouldDisableAutoInstrumentation(getCurrentHub)) {
|
||||
DEBUG_BUILD && logger.log('GraphQL Integration is skipped because of instrumenter configuration.');
|
||||
return;
|
||||
}
|
||||
|
||||
const pkg = this.loadDependency();
|
||||
|
||||
if (!pkg) {
|
||||
DEBUG_BUILD && logger.error('GraphQL Integration was unable to require graphql/execution package.');
|
||||
return;
|
||||
}
|
||||
|
||||
fill(pkg, 'execute', function (orig) {
|
||||
return function ( ...args) {
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
const scope = getCurrentHub().getScope();
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
const parentSpan = scope.getSpan();
|
||||
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
const span = _optionalChain([parentSpan, 'optionalAccess', _2 => _2.startChild, 'call', _3 => _3({
|
||||
description: 'execute',
|
||||
op: 'graphql.execute',
|
||||
origin: 'auto.graphql.graphql',
|
||||
})]);
|
||||
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
_optionalChain([scope, 'optionalAccess', _4 => _4.setSpan, 'call', _5 => _5(span)]);
|
||||
|
||||
const rv = orig.call(this, ...args);
|
||||
|
||||
if (isThenable(rv)) {
|
||||
return rv.then((res) => {
|
||||
_optionalChain([span, 'optionalAccess', _6 => _6.end, 'call', _7 => _7()]);
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
_optionalChain([scope, 'optionalAccess', _8 => _8.setSpan, 'call', _9 => _9(parentSpan)]);
|
||||
|
||||
return res;
|
||||
});
|
||||
}
|
||||
|
||||
_optionalChain([span, 'optionalAccess', _10 => _10.end, 'call', _11 => _11()]);
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
_optionalChain([scope, 'optionalAccess', _12 => _12.setSpan, 'call', _13 => _13(parentSpan)]);
|
||||
return rv;
|
||||
};
|
||||
});
|
||||
}
|
||||
}GraphQL.__initStatic();
|
||||
|
||||
export { GraphQL };
|
||||
//# sourceMappingURL=graphql.js.map
|
||||
1
node_modules/@sentry-internal/tracing/esm/node/integrations/graphql.js.map
generated
vendored
Normal file
1
node_modules/@sentry-internal/tracing/esm/node/integrations/graphql.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
49
node_modules/@sentry-internal/tracing/esm/node/integrations/lazy.js
generated
vendored
Normal file
49
node_modules/@sentry-internal/tracing/esm/node/integrations/lazy.js
generated
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
import { dynamicRequire } from '@sentry/utils';
|
||||
|
||||
const lazyLoadedNodePerformanceMonitoringIntegrations = [
|
||||
() => {
|
||||
const integration = dynamicRequire(module, './apollo')
|
||||
|
||||
;
|
||||
return new integration.Apollo();
|
||||
},
|
||||
() => {
|
||||
const integration = dynamicRequire(module, './apollo')
|
||||
|
||||
;
|
||||
return new integration.Apollo({ useNestjs: true });
|
||||
},
|
||||
() => {
|
||||
const integration = dynamicRequire(module, './graphql')
|
||||
|
||||
;
|
||||
return new integration.GraphQL();
|
||||
},
|
||||
() => {
|
||||
const integration = dynamicRequire(module, './mongo')
|
||||
|
||||
;
|
||||
return new integration.Mongo();
|
||||
},
|
||||
() => {
|
||||
const integration = dynamicRequire(module, './mongo')
|
||||
|
||||
;
|
||||
return new integration.Mongo({ mongoose: true });
|
||||
},
|
||||
() => {
|
||||
const integration = dynamicRequire(module, './mysql')
|
||||
|
||||
;
|
||||
return new integration.Mysql();
|
||||
},
|
||||
() => {
|
||||
const integration = dynamicRequire(module, './postgres')
|
||||
|
||||
;
|
||||
return new integration.Postgres();
|
||||
},
|
||||
];
|
||||
|
||||
export { lazyLoadedNodePerformanceMonitoringIntegrations };
|
||||
//# sourceMappingURL=lazy.js.map
|
||||
1
node_modules/@sentry-internal/tracing/esm/node/integrations/lazy.js.map
generated
vendored
Normal file
1
node_modules/@sentry-internal/tracing/esm/node/integrations/lazy.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"lazy.js","sources":["../../../../src/node/integrations/lazy.ts"],"sourcesContent":["import type { Integration, IntegrationClass } from '@sentry/types';\nimport { dynamicRequire } from '@sentry/utils';\n\nexport interface LazyLoadedIntegration<T = object> extends Integration {\n /**\n * Loads the integration's dependency and caches it so it doesn't have to be loaded again.\n *\n * If this returns undefined, the dependency could not be loaded.\n */\n loadDependency(): T | undefined;\n}\n\nexport const lazyLoadedNodePerformanceMonitoringIntegrations: (() => LazyLoadedIntegration)[] = [\n () => {\n const integration = dynamicRequire(module, './apollo') as {\n Apollo: IntegrationClass<LazyLoadedIntegration>;\n };\n return new integration.Apollo();\n },\n () => {\n const integration = dynamicRequire(module, './apollo') as {\n Apollo: IntegrationClass<LazyLoadedIntegration>;\n };\n return new integration.Apollo({ useNestjs: true });\n },\n () => {\n const integration = dynamicRequire(module, './graphql') as {\n GraphQL: IntegrationClass<LazyLoadedIntegration>;\n };\n return new integration.GraphQL();\n },\n () => {\n const integration = dynamicRequire(module, './mongo') as {\n Mongo: IntegrationClass<LazyLoadedIntegration>;\n };\n return new integration.Mongo();\n },\n () => {\n const integration = dynamicRequire(module, './mongo') as {\n Mongo: IntegrationClass<LazyLoadedIntegration>;\n };\n return new integration.Mongo({ mongoose: true });\n },\n () => {\n const integration = dynamicRequire(module, './mysql') as {\n Mysql: IntegrationClass<LazyLoadedIntegration>;\n };\n return new integration.Mysql();\n },\n () => {\n const integration = dynamicRequire(module, './postgres') as {\n Postgres: IntegrationClass<LazyLoadedIntegration>;\n };\n return new integration.Postgres();\n },\n];\n"],"names":[],"mappings":";;AAYO,MAAM,+CAA+C,GAAoC;AAChG,EAAE,MAAM;AACR,IAAI,MAAM,cAAc,cAAc,CAAC,MAAM,EAAE,UAAU,CAAE;;AAEvD,CAAA;AACJ,IAAI,OAAO,IAAI,WAAW,CAAC,MAAM,EAAE,CAAA;AACnC,GAAG;AACH,EAAE,MAAM;AACR,IAAI,MAAM,cAAc,cAAc,CAAC,MAAM,EAAE,UAAU,CAAE;;AAEvD,CAAA;AACJ,IAAI,OAAO,IAAI,WAAW,CAAC,MAAM,CAAC,EAAE,SAAS,EAAE,IAAK,EAAC,CAAC,CAAA;AACtD,GAAG;AACH,EAAE,MAAM;AACR,IAAI,MAAM,cAAc,cAAc,CAAC,MAAM,EAAE,WAAW,CAAE;;AAExD,CAAA;AACJ,IAAI,OAAO,IAAI,WAAW,CAAC,OAAO,EAAE,CAAA;AACpC,GAAG;AACH,EAAE,MAAM;AACR,IAAI,MAAM,cAAc,cAAc,CAAC,MAAM,EAAE,SAAS,CAAE;;AAEtD,CAAA;AACJ,IAAI,OAAO,IAAI,WAAW,CAAC,KAAK,EAAE,CAAA;AAClC,GAAG;AACH,EAAE,MAAM;AACR,IAAI,MAAM,cAAc,cAAc,CAAC,MAAM,EAAE,SAAS,CAAE;;AAEtD,CAAA;AACJ,IAAI,OAAO,IAAI,WAAW,CAAC,KAAK,CAAC,EAAE,QAAQ,EAAE,IAAK,EAAC,CAAC,CAAA;AACpD,GAAG;AACH,EAAE,MAAM;AACR,IAAI,MAAM,cAAc,cAAc,CAAC,MAAM,EAAE,SAAS,CAAE;;AAEtD,CAAA;AACJ,IAAI,OAAO,IAAI,WAAW,CAAC,KAAK,EAAE,CAAA;AAClC,GAAG;AACH,EAAE,MAAM;AACR,IAAI,MAAM,cAAc,cAAc,CAAC,MAAM,EAAE,YAAY,CAAE;;AAEzD,CAAA;AACJ,IAAI,OAAO,IAAI,WAAW,CAAC,QAAQ,EAAE,CAAA;AACrC,GAAG;AACH;;;;"}
|
||||
260
node_modules/@sentry-internal/tracing/esm/node/integrations/mongo.js
generated
vendored
Normal file
260
node_modules/@sentry-internal/tracing/esm/node/integrations/mongo.js
generated
vendored
Normal file
@@ -0,0 +1,260 @@
|
||||
import { _optionalChain } from '@sentry/utils';
|
||||
import { loadModule, logger, fill, isThenable } from '@sentry/utils';
|
||||
import { DEBUG_BUILD } from '../../common/debug-build.js';
|
||||
import { shouldDisableAutoInstrumentation } from './utils/node-utils.js';
|
||||
|
||||
// This allows us to use the same array for both defaults options and the type itself.
|
||||
// (note `as const` at the end to make it a union of string literal types (i.e. "a" | "b" | ... )
|
||||
// and not just a string[])
|
||||
|
||||
const OPERATIONS = [
|
||||
'aggregate', // aggregate(pipeline, options, callback)
|
||||
'bulkWrite', // bulkWrite(operations, options, callback)
|
||||
'countDocuments', // countDocuments(query, options, callback)
|
||||
'createIndex', // createIndex(fieldOrSpec, options, callback)
|
||||
'createIndexes', // createIndexes(indexSpecs, options, callback)
|
||||
'deleteMany', // deleteMany(filter, options, callback)
|
||||
'deleteOne', // deleteOne(filter, options, callback)
|
||||
'distinct', // distinct(key, query, options, callback)
|
||||
'drop', // drop(options, callback)
|
||||
'dropIndex', // dropIndex(indexName, options, callback)
|
||||
'dropIndexes', // dropIndexes(options, callback)
|
||||
'estimatedDocumentCount', // estimatedDocumentCount(options, callback)
|
||||
'find', // find(query, options, callback)
|
||||
'findOne', // findOne(query, options, callback)
|
||||
'findOneAndDelete', // findOneAndDelete(filter, options, callback)
|
||||
'findOneAndReplace', // findOneAndReplace(filter, replacement, options, callback)
|
||||
'findOneAndUpdate', // findOneAndUpdate(filter, update, options, callback)
|
||||
'indexes', // indexes(options, callback)
|
||||
'indexExists', // indexExists(indexes, options, callback)
|
||||
'indexInformation', // indexInformation(options, callback)
|
||||
'initializeOrderedBulkOp', // initializeOrderedBulkOp(options, callback)
|
||||
'insertMany', // insertMany(docs, options, callback)
|
||||
'insertOne', // insertOne(doc, options, callback)
|
||||
'isCapped', // isCapped(options, callback)
|
||||
'mapReduce', // mapReduce(map, reduce, options, callback)
|
||||
'options', // options(options, callback)
|
||||
'parallelCollectionScan', // parallelCollectionScan(options, callback)
|
||||
'rename', // rename(newName, options, callback)
|
||||
'replaceOne', // replaceOne(filter, doc, options, callback)
|
||||
'stats', // stats(options, callback)
|
||||
'updateMany', // updateMany(filter, update, options, callback)
|
||||
'updateOne', // updateOne(filter, update, options, callback)
|
||||
] ;
|
||||
|
||||
// All of the operations above take `options` and `callback` as their final parameters, but some of them
|
||||
// take additional parameters as well. For those operations, this is a map of
|
||||
// { <operation name>: [<names of additional parameters>] }, as a way to know what to call the operation's
|
||||
// positional arguments when we add them to the span's `data` object later
|
||||
const OPERATION_SIGNATURES
|
||||
|
||||
= {
|
||||
// aggregate intentionally not included because `pipeline` arguments are too complex to serialize well
|
||||
// see https://github.com/getsentry/sentry-javascript/pull/3102
|
||||
bulkWrite: ['operations'],
|
||||
countDocuments: ['query'],
|
||||
createIndex: ['fieldOrSpec'],
|
||||
createIndexes: ['indexSpecs'],
|
||||
deleteMany: ['filter'],
|
||||
deleteOne: ['filter'],
|
||||
distinct: ['key', 'query'],
|
||||
dropIndex: ['indexName'],
|
||||
find: ['query'],
|
||||
findOne: ['query'],
|
||||
findOneAndDelete: ['filter'],
|
||||
findOneAndReplace: ['filter', 'replacement'],
|
||||
findOneAndUpdate: ['filter', 'update'],
|
||||
indexExists: ['indexes'],
|
||||
insertMany: ['docs'],
|
||||
insertOne: ['doc'],
|
||||
mapReduce: ['map', 'reduce'],
|
||||
rename: ['newName'],
|
||||
replaceOne: ['filter', 'doc'],
|
||||
updateMany: ['filter', 'update'],
|
||||
updateOne: ['filter', 'update'],
|
||||
};
|
||||
|
||||
function isCursor(maybeCursor) {
|
||||
return maybeCursor && typeof maybeCursor === 'object' && maybeCursor.once && typeof maybeCursor.once === 'function';
|
||||
}
|
||||
|
||||
/** Tracing integration for mongo package */
|
||||
class Mongo {
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
static __initStatic() {this.id = 'Mongo';}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
constructor(options = {}) {
|
||||
this.name = Mongo.id;
|
||||
this._operations = Array.isArray(options.operations) ? options.operations : (OPERATIONS );
|
||||
this._describeOperations = 'describeOperations' in options ? options.describeOperations : true;
|
||||
this._useMongoose = !!options.useMongoose;
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
loadDependency() {
|
||||
const moduleName = this._useMongoose ? 'mongoose' : 'mongodb';
|
||||
return (this._module = this._module || loadModule(moduleName));
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
setupOnce(_, getCurrentHub) {
|
||||
if (shouldDisableAutoInstrumentation(getCurrentHub)) {
|
||||
DEBUG_BUILD && logger.log('Mongo Integration is skipped because of instrumenter configuration.');
|
||||
return;
|
||||
}
|
||||
|
||||
const pkg = this.loadDependency();
|
||||
|
||||
if (!pkg) {
|
||||
const moduleName = this._useMongoose ? 'mongoose' : 'mongodb';
|
||||
DEBUG_BUILD && logger.error(`Mongo Integration was unable to require \`${moduleName}\` package.`);
|
||||
return;
|
||||
}
|
||||
|
||||
this._instrumentOperations(pkg.Collection, this._operations, getCurrentHub);
|
||||
}
|
||||
|
||||
/**
|
||||
* Patches original collection methods
|
||||
*/
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
_instrumentOperations(collection, operations, getCurrentHub) {
|
||||
operations.forEach((operation) => this._patchOperation(collection, operation, getCurrentHub));
|
||||
}
|
||||
|
||||
/**
|
||||
* Patches original collection to utilize our tracing functionality
|
||||
*/
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
_patchOperation(collection, operation, getCurrentHub) {
|
||||
if (!(operation in collection.prototype)) return;
|
||||
|
||||
const getSpanContext = this._getSpanContextFromOperationArguments.bind(this);
|
||||
|
||||
fill(collection.prototype, operation, function (orig) {
|
||||
return function ( ...args) {
|
||||
const lastArg = args[args.length - 1];
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
const hub = getCurrentHub();
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
const scope = hub.getScope();
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
const client = hub.getClient();
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
const parentSpan = scope.getSpan();
|
||||
|
||||
const sendDefaultPii = _optionalChain([client, 'optionalAccess', _2 => _2.getOptions, 'call', _3 => _3(), 'access', _4 => _4.sendDefaultPii]);
|
||||
|
||||
// Check if the operation was passed a callback. (mapReduce requires a different check, as
|
||||
// its (non-callback) arguments can also be functions.)
|
||||
if (typeof lastArg !== 'function' || (operation === 'mapReduce' && args.length === 2)) {
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
const span = _optionalChain([parentSpan, 'optionalAccess', _5 => _5.startChild, 'call', _6 => _6(getSpanContext(this, operation, args, sendDefaultPii))]);
|
||||
const maybePromiseOrCursor = orig.call(this, ...args);
|
||||
|
||||
if (isThenable(maybePromiseOrCursor)) {
|
||||
return maybePromiseOrCursor.then((res) => {
|
||||
_optionalChain([span, 'optionalAccess', _7 => _7.end, 'call', _8 => _8()]);
|
||||
return res;
|
||||
});
|
||||
}
|
||||
// If the operation returns a Cursor
|
||||
// we need to attach a listener to it to finish the span when the cursor is closed.
|
||||
else if (isCursor(maybePromiseOrCursor)) {
|
||||
const cursor = maybePromiseOrCursor ;
|
||||
|
||||
try {
|
||||
cursor.once('close', () => {
|
||||
_optionalChain([span, 'optionalAccess', _9 => _9.end, 'call', _10 => _10()]);
|
||||
});
|
||||
} catch (e) {
|
||||
// If the cursor is already closed, `once` will throw an error. In that case, we can
|
||||
// finish the span immediately.
|
||||
_optionalChain([span, 'optionalAccess', _11 => _11.end, 'call', _12 => _12()]);
|
||||
}
|
||||
|
||||
return cursor;
|
||||
} else {
|
||||
_optionalChain([span, 'optionalAccess', _13 => _13.end, 'call', _14 => _14()]);
|
||||
return maybePromiseOrCursor;
|
||||
}
|
||||
}
|
||||
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
const span = _optionalChain([parentSpan, 'optionalAccess', _15 => _15.startChild, 'call', _16 => _16(getSpanContext(this, operation, args.slice(0, -1)))]);
|
||||
|
||||
return orig.call(this, ...args.slice(0, -1), function (err, result) {
|
||||
_optionalChain([span, 'optionalAccess', _17 => _17.end, 'call', _18 => _18()]);
|
||||
lastArg(err, result);
|
||||
});
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Form a SpanContext based on the user input to a given operation.
|
||||
*/
|
||||
_getSpanContextFromOperationArguments(
|
||||
collection,
|
||||
operation,
|
||||
args,
|
||||
sendDefaultPii = false,
|
||||
) {
|
||||
const data = {
|
||||
'db.system': 'mongodb',
|
||||
'db.name': collection.dbName,
|
||||
'db.operation': operation,
|
||||
'db.mongodb.collection': collection.collectionName,
|
||||
};
|
||||
const spanContext = {
|
||||
op: 'db',
|
||||
// TODO v8: Use `${collection.collectionName}.${operation}`
|
||||
origin: 'auto.db.mongo',
|
||||
description: operation,
|
||||
data,
|
||||
};
|
||||
|
||||
// If the operation takes no arguments besides `options` and `callback`, or if argument
|
||||
// collection is disabled for this operation, just return early.
|
||||
const signature = OPERATION_SIGNATURES[operation];
|
||||
const shouldDescribe = Array.isArray(this._describeOperations)
|
||||
? this._describeOperations.includes(operation)
|
||||
: this._describeOperations;
|
||||
|
||||
if (!signature || !shouldDescribe || !sendDefaultPii) {
|
||||
return spanContext;
|
||||
}
|
||||
|
||||
try {
|
||||
// Special case for `mapReduce`, as the only one accepting functions as arguments.
|
||||
if (operation === 'mapReduce') {
|
||||
const [map, reduce] = args ;
|
||||
data[signature[0]] = typeof map === 'string' ? map : map.name || '<anonymous>';
|
||||
data[signature[1]] = typeof reduce === 'string' ? reduce : reduce.name || '<anonymous>';
|
||||
} else {
|
||||
for (let i = 0; i < signature.length; i++) {
|
||||
data[`db.mongodb.${signature[i]}`] = JSON.stringify(args[i]);
|
||||
}
|
||||
}
|
||||
} catch (_oO) {
|
||||
// no-empty
|
||||
}
|
||||
|
||||
return spanContext;
|
||||
}
|
||||
}Mongo.__initStatic();
|
||||
|
||||
export { Mongo };
|
||||
//# sourceMappingURL=mongo.js.map
|
||||
1
node_modules/@sentry-internal/tracing/esm/node/integrations/mongo.js.map
generated
vendored
Normal file
1
node_modules/@sentry-internal/tracing/esm/node/integrations/mongo.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
131
node_modules/@sentry-internal/tracing/esm/node/integrations/mysql.js
generated
vendored
Normal file
131
node_modules/@sentry-internal/tracing/esm/node/integrations/mysql.js
generated
vendored
Normal file
@@ -0,0 +1,131 @@
|
||||
import { _optionalChain } from '@sentry/utils';
|
||||
import { loadModule, logger, fill } from '@sentry/utils';
|
||||
import { DEBUG_BUILD } from '../../common/debug-build.js';
|
||||
import { shouldDisableAutoInstrumentation } from './utils/node-utils.js';
|
||||
|
||||
/** Tracing integration for node-mysql package */
|
||||
class Mysql {
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
static __initStatic() {this.id = 'Mysql';}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
constructor() {
|
||||
this.name = Mysql.id;
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
loadDependency() {
|
||||
return (this._module = this._module || loadModule('mysql/lib/Connection.js'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
setupOnce(_, getCurrentHub) {
|
||||
if (shouldDisableAutoInstrumentation(getCurrentHub)) {
|
||||
DEBUG_BUILD && logger.log('Mysql Integration is skipped because of instrumenter configuration.');
|
||||
return;
|
||||
}
|
||||
|
||||
const pkg = this.loadDependency();
|
||||
|
||||
if (!pkg) {
|
||||
DEBUG_BUILD && logger.error('Mysql Integration was unable to require `mysql` package.');
|
||||
return;
|
||||
}
|
||||
|
||||
let mySqlConfig = undefined;
|
||||
|
||||
try {
|
||||
pkg.prototype.connect = new Proxy(pkg.prototype.connect, {
|
||||
apply(wrappingTarget, thisArg, args) {
|
||||
if (!mySqlConfig) {
|
||||
mySqlConfig = thisArg.config;
|
||||
}
|
||||
return wrappingTarget.apply(thisArg, args);
|
||||
},
|
||||
});
|
||||
} catch (e) {
|
||||
DEBUG_BUILD && logger.error('Mysql Integration was unable to instrument `mysql` config.');
|
||||
}
|
||||
|
||||
function spanDataFromConfig() {
|
||||
if (!mySqlConfig) {
|
||||
return {};
|
||||
}
|
||||
return {
|
||||
'server.address': mySqlConfig.host,
|
||||
'server.port': mySqlConfig.port,
|
||||
'db.user': mySqlConfig.user,
|
||||
};
|
||||
}
|
||||
|
||||
function finishSpan(span) {
|
||||
if (!span) {
|
||||
return;
|
||||
}
|
||||
|
||||
const data = spanDataFromConfig();
|
||||
Object.keys(data).forEach(key => {
|
||||
span.setAttribute(key, data[key]);
|
||||
});
|
||||
|
||||
span.end();
|
||||
}
|
||||
|
||||
// The original function will have one of these signatures:
|
||||
// function (callback) => void
|
||||
// function (options, callback) => void
|
||||
// function (options, values, callback) => void
|
||||
fill(pkg, 'createQuery', function (orig) {
|
||||
return function ( options, values, callback) {
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
const scope = getCurrentHub().getScope();
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
const parentSpan = scope.getSpan();
|
||||
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
const span = _optionalChain([parentSpan, 'optionalAccess', _2 => _2.startChild, 'call', _3 => _3({
|
||||
description: typeof options === 'string' ? options : (options ).sql,
|
||||
op: 'db',
|
||||
origin: 'auto.db.mysql',
|
||||
data: {
|
||||
'db.system': 'mysql',
|
||||
},
|
||||
})]);
|
||||
|
||||
if (typeof callback === 'function') {
|
||||
return orig.call(this, options, values, function (err, result, fields) {
|
||||
finishSpan(span);
|
||||
callback(err, result, fields);
|
||||
});
|
||||
}
|
||||
|
||||
if (typeof values === 'function') {
|
||||
return orig.call(this, options, function (err, result, fields) {
|
||||
finishSpan(span);
|
||||
values(err, result, fields);
|
||||
});
|
||||
}
|
||||
|
||||
// streaming, no callback!
|
||||
const query = orig.call(this, options, values) ;
|
||||
|
||||
query.on('end', () => {
|
||||
finishSpan(span);
|
||||
});
|
||||
|
||||
return query;
|
||||
};
|
||||
});
|
||||
}
|
||||
}Mysql.__initStatic();
|
||||
|
||||
export { Mysql };
|
||||
//# sourceMappingURL=mysql.js.map
|
||||
1
node_modules/@sentry-internal/tracing/esm/node/integrations/mysql.js.map
generated
vendored
Normal file
1
node_modules/@sentry-internal/tracing/esm/node/integrations/mysql.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
126
node_modules/@sentry-internal/tracing/esm/node/integrations/postgres.js
generated
vendored
Normal file
126
node_modules/@sentry-internal/tracing/esm/node/integrations/postgres.js
generated
vendored
Normal file
@@ -0,0 +1,126 @@
|
||||
import { _optionalChain } from '@sentry/utils';
|
||||
import { loadModule, logger, fill, isThenable } from '@sentry/utils';
|
||||
import { DEBUG_BUILD } from '../../common/debug-build.js';
|
||||
import { shouldDisableAutoInstrumentation } from './utils/node-utils.js';
|
||||
|
||||
/** Tracing integration for node-postgres package */
|
||||
class Postgres {
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
static __initStatic() {this.id = 'Postgres';}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
constructor(options = {}) {
|
||||
this.name = Postgres.id;
|
||||
this._usePgNative = !!options.usePgNative;
|
||||
this._module = options.module;
|
||||
}
|
||||
|
||||
/** @inheritdoc */
|
||||
loadDependency() {
|
||||
return (this._module = this._module || loadModule('pg'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
setupOnce(_, getCurrentHub) {
|
||||
if (shouldDisableAutoInstrumentation(getCurrentHub)) {
|
||||
DEBUG_BUILD && logger.log('Postgres Integration is skipped because of instrumenter configuration.');
|
||||
return;
|
||||
}
|
||||
|
||||
const pkg = this.loadDependency();
|
||||
|
||||
if (!pkg) {
|
||||
DEBUG_BUILD && logger.error('Postgres Integration was unable to require `pg` package.');
|
||||
return;
|
||||
}
|
||||
|
||||
const Client = this._usePgNative ? _optionalChain([pkg, 'access', _2 => _2.native, 'optionalAccess', _3 => _3.Client]) : pkg.Client;
|
||||
|
||||
if (!Client) {
|
||||
DEBUG_BUILD && logger.error("Postgres Integration was unable to access 'pg-native' bindings.");
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* function (query, callback) => void
|
||||
* function (query, params, callback) => void
|
||||
* function (query) => Promise
|
||||
* function (query, params) => Promise
|
||||
* function (pg.Cursor) => pg.Cursor
|
||||
*/
|
||||
fill(Client.prototype, 'query', function (orig) {
|
||||
return function ( config, values, callback) {
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
const scope = getCurrentHub().getScope();
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
const parentSpan = scope.getSpan();
|
||||
|
||||
const data = {
|
||||
'db.system': 'postgresql',
|
||||
};
|
||||
|
||||
try {
|
||||
if (this.database) {
|
||||
data['db.name'] = this.database;
|
||||
}
|
||||
if (this.host) {
|
||||
data['server.address'] = this.host;
|
||||
}
|
||||
if (this.port) {
|
||||
data['server.port'] = this.port;
|
||||
}
|
||||
if (this.user) {
|
||||
data['db.user'] = this.user;
|
||||
}
|
||||
} catch (e) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
const span = _optionalChain([parentSpan, 'optionalAccess', _4 => _4.startChild, 'call', _5 => _5({
|
||||
description: typeof config === 'string' ? config : (config ).text,
|
||||
op: 'db',
|
||||
origin: 'auto.db.postgres',
|
||||
data,
|
||||
})]);
|
||||
|
||||
if (typeof callback === 'function') {
|
||||
return orig.call(this, config, values, function (err, result) {
|
||||
_optionalChain([span, 'optionalAccess', _6 => _6.end, 'call', _7 => _7()]);
|
||||
callback(err, result);
|
||||
});
|
||||
}
|
||||
|
||||
if (typeof values === 'function') {
|
||||
return orig.call(this, config, function (err, result) {
|
||||
_optionalChain([span, 'optionalAccess', _8 => _8.end, 'call', _9 => _9()]);
|
||||
values(err, result);
|
||||
});
|
||||
}
|
||||
|
||||
const rv = typeof values !== 'undefined' ? orig.call(this, config, values) : orig.call(this, config);
|
||||
|
||||
if (isThenable(rv)) {
|
||||
return rv.then((res) => {
|
||||
_optionalChain([span, 'optionalAccess', _10 => _10.end, 'call', _11 => _11()]);
|
||||
return res;
|
||||
});
|
||||
}
|
||||
|
||||
_optionalChain([span, 'optionalAccess', _12 => _12.end, 'call', _13 => _13()]);
|
||||
return rv;
|
||||
};
|
||||
});
|
||||
}
|
||||
}Postgres.__initStatic();
|
||||
|
||||
export { Postgres };
|
||||
//# sourceMappingURL=postgres.js.map
|
||||
1
node_modules/@sentry-internal/tracing/esm/node/integrations/postgres.js.map
generated
vendored
Normal file
1
node_modules/@sentry-internal/tracing/esm/node/integrations/postgres.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
89
node_modules/@sentry-internal/tracing/esm/node/integrations/prisma.js
generated
vendored
Normal file
89
node_modules/@sentry-internal/tracing/esm/node/integrations/prisma.js
generated
vendored
Normal file
@@ -0,0 +1,89 @@
|
||||
import { startSpan, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, getCurrentHub } from '@sentry/core';
|
||||
import { addNonEnumerableProperty, logger } from '@sentry/utils';
|
||||
import { DEBUG_BUILD } from '../../common/debug-build.js';
|
||||
import { shouldDisableAutoInstrumentation } from './utils/node-utils.js';
|
||||
|
||||
function isValidPrismaClient(possibleClient) {
|
||||
return !!possibleClient && !!(possibleClient )['$use'];
|
||||
}
|
||||
|
||||
/** Tracing integration for @prisma/client package */
|
||||
class Prisma {
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
static __initStatic() {this.id = 'Prisma';}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
constructor(options = {}) {
|
||||
this.name = Prisma.id;
|
||||
|
||||
// We instrument the PrismaClient inside the constructor and not inside `setupOnce` because in some cases of server-side
|
||||
// bundling (Next.js) multiple Prisma clients can be instantiated, even though users don't intend to. When instrumenting
|
||||
// in setupOnce we can only ever instrument one client.
|
||||
// https://github.com/getsentry/sentry-javascript/issues/7216#issuecomment-1602375012
|
||||
// In the future we might explore providing a dedicated PrismaClient middleware instead of this hack.
|
||||
if (isValidPrismaClient(options.client) && !options.client._sentryInstrumented) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
addNonEnumerableProperty(options.client , '_sentryInstrumented', true);
|
||||
|
||||
const clientData = {};
|
||||
try {
|
||||
const engineConfig = (options.client )._engineConfig;
|
||||
if (engineConfig) {
|
||||
const { activeProvider, clientVersion } = engineConfig;
|
||||
if (activeProvider) {
|
||||
clientData['db.system'] = activeProvider;
|
||||
}
|
||||
if (clientVersion) {
|
||||
clientData['db.prisma.version'] = clientVersion;
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
options.client.$use((params, next) => {
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
if (shouldDisableAutoInstrumentation(getCurrentHub)) {
|
||||
return next(params);
|
||||
}
|
||||
|
||||
const action = params.action;
|
||||
const model = params.model;
|
||||
|
||||
return startSpan(
|
||||
{
|
||||
name: model ? `${model} ${action}` : action,
|
||||
onlyIfParent: true,
|
||||
op: 'db.prisma',
|
||||
attributes: {
|
||||
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.db.prisma',
|
||||
},
|
||||
data: { ...clientData, 'db.operation': action },
|
||||
},
|
||||
() => next(params),
|
||||
);
|
||||
});
|
||||
} else {
|
||||
DEBUG_BUILD &&
|
||||
logger.warn('Unsupported Prisma client provided to PrismaIntegration. Provided client:', options.client);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
setupOnce() {
|
||||
// Noop - here for backwards compatibility
|
||||
}
|
||||
} Prisma.__initStatic();
|
||||
|
||||
export { Prisma };
|
||||
//# sourceMappingURL=prisma.js.map
|
||||
1
node_modules/@sentry-internal/tracing/esm/node/integrations/prisma.js.map
generated
vendored
Normal file
1
node_modules/@sentry-internal/tracing/esm/node/integrations/prisma.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
19
node_modules/@sentry-internal/tracing/esm/node/integrations/utils/node-utils.js
generated
vendored
Normal file
19
node_modules/@sentry-internal/tracing/esm/node/integrations/utils/node-utils.js
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
import { _optionalChain } from '@sentry/utils';
|
||||
|
||||
/**
|
||||
* Check if Sentry auto-instrumentation should be disabled.
|
||||
*
|
||||
* @param getCurrentHub A method to fetch the current hub
|
||||
* @returns boolean
|
||||
*/
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
function shouldDisableAutoInstrumentation(getCurrentHub) {
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
const clientOptions = _optionalChain([getCurrentHub, 'call', _ => _(), 'access', _2 => _2.getClient, 'call', _3 => _3(), 'optionalAccess', _4 => _4.getOptions, 'call', _5 => _5()]);
|
||||
const instrumenter = _optionalChain([clientOptions, 'optionalAccess', _6 => _6.instrumenter]) || 'sentry';
|
||||
|
||||
return instrumenter !== 'sentry';
|
||||
}
|
||||
|
||||
export { shouldDisableAutoInstrumentation };
|
||||
//# sourceMappingURL=node-utils.js.map
|
||||
1
node_modules/@sentry-internal/tracing/esm/node/integrations/utils/node-utils.js.map
generated
vendored
Normal file
1
node_modules/@sentry-internal/tracing/esm/node/integrations/utils/node-utils.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"node-utils.js","sources":["../../../../../src/node/integrations/utils/node-utils.ts"],"sourcesContent":["import type { Hub } from '@sentry/types';\n\n/**\n * Check if Sentry auto-instrumentation should be disabled.\n *\n * @param getCurrentHub A method to fetch the current hub\n * @returns boolean\n */\n// eslint-disable-next-line deprecation/deprecation\nexport function shouldDisableAutoInstrumentation(getCurrentHub: () => Hub): boolean {\n // eslint-disable-next-line deprecation/deprecation\n const clientOptions = getCurrentHub().getClient()?.getOptions();\n const instrumenter = clientOptions?.instrumenter || 'sentry';\n\n return instrumenter !== 'sentry';\n}\n"],"names":[],"mappings":";;AAEA,CAAA,CAAA;CACA,EAAA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;CACA;CACA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,EAAA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,CAAA;CACA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;CACA,CAAA;AACA,CAAA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;AACO,CAAS,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAgC,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAa,EAAsB;EACpF,CAAA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA;EACE,CAAA,CAAA,CAAA,CAAA,EAAM,cAAgB,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAa,EAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,EAAA,CAAA,EAAA,CAAA,EAAC,EAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,EAAA,CAAA,EAAA,CAAA,CAAA,CAAA,CAAS,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAC,MAAA,EAAA,CAAA,KAAA,CAAA,CAAA,CAAA,CAAC,EAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,GAAA,CAAA,EAAA,CAAA,CAAA,CAAA,CAAU,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,oBAAE,CAAA,CAAA;EAC/D,MAAM,CAAa,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,EAAA,cAAA,CAAA,CAAE,aAAa,EAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,EAAA,CAAA,EAAA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,EAAgB,QAAQ;;EAE5D,CAAO,CAAA,CAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EAAiB,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ;AAClC;;"}
|
||||
Reference in New Issue
Block a user