forked from off-topic/apps.apple.com
init commit
This commit is contained in:
36
shared/logger/node_modules/@sentry-internal/tracing/esm/browser/backgroundtab.js
generated
vendored
Normal file
36
shared/logger/node_modules/@sentry-internal/tracing/esm/browser/backgroundtab.js
generated
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
import { getActiveTransaction } from '@sentry/core';
|
||||
import { logger } from '@sentry/utils';
|
||||
import { WINDOW } from './types.js';
|
||||
|
||||
/**
|
||||
* Add a listener that cancels and finishes a transaction when the global
|
||||
* document is hidden.
|
||||
*/
|
||||
function registerBackgroundTabDetection() {
|
||||
if (WINDOW && WINDOW.document) {
|
||||
WINDOW.document.addEventListener('visibilitychange', () => {
|
||||
const activeTransaction = getActiveTransaction() ;
|
||||
if (WINDOW.document.hidden && activeTransaction) {
|
||||
const statusType = 'cancelled';
|
||||
|
||||
(typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) &&
|
||||
logger.log(
|
||||
`[Tracing] Transaction: ${statusType} -> since tab moved to the background, op: ${activeTransaction.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 (!activeTransaction.status) {
|
||||
activeTransaction.setStatus(statusType);
|
||||
}
|
||||
activeTransaction.setTag('visibilitychange', 'document.hidden');
|
||||
activeTransaction.finish();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
(typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) &&
|
||||
logger.warn('[Tracing] Could not set up background tab detection due to lack of global document');
|
||||
}
|
||||
}
|
||||
|
||||
export { registerBackgroundTabDetection };
|
||||
//# sourceMappingURL=backgroundtab.js.map
|
||||
300
shared/logger/node_modules/@sentry-internal/tracing/esm/browser/browsertracing.js
generated
vendored
Normal file
300
shared/logger/node_modules/@sentry-internal/tracing/esm/browser/browsertracing.js
generated
vendored
Normal file
@@ -0,0 +1,300 @@
|
||||
import { TRACING_DEFAULTS, addTracingExtensions, extractTraceparentData, startIdleTransaction, getActiveTransaction } from '@sentry/core';
|
||||
import { logger, baggageHeaderToDynamicSamplingContext, getDomElement } from '@sentry/utils';
|
||||
import { registerBackgroundTabDetection } from './backgroundtab.js';
|
||||
import { startTrackingWebVitals, 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,
|
||||
...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.
|
||||
*/
|
||||
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
|
||||
*/
|
||||
__init() {this.name = BROWSER_TRACING_INTEGRATION_ID;}
|
||||
|
||||
__init2() {this._hasSetTracePropagationTargets = false;}
|
||||
|
||||
constructor(_options) {BrowserTracing.prototype.__init.call(this);BrowserTracing.prototype.__init2.call(this);
|
||||
addTracingExtensions();
|
||||
|
||||
if ((typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__)) {
|
||||
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();
|
||||
if (this.options.enableLongTask) {
|
||||
startTrackingLongTasks();
|
||||
}
|
||||
if (this.options._experiments.enableInteractions) {
|
||||
startTrackingInteractions();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
setupOnce(_, getCurrentHub) {
|
||||
this._getCurrentHub = getCurrentHub;
|
||||
const hub = getCurrentHub();
|
||||
const client = hub.getClient();
|
||||
const clientOptions = client && client.getOptions();
|
||||
|
||||
const {
|
||||
routingInstrumentation: instrumentRouting,
|
||||
startTransactionOnLocationChange,
|
||||
startTransactionOnPageLoad,
|
||||
markBackgroundTransactions,
|
||||
traceFetch,
|
||||
traceXHR,
|
||||
shouldCreateSpanForRequest,
|
||||
_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.
|
||||
const tracePropagationTargets = clientOptionsTracePropagationTargets || this.options.tracePropagationTargets;
|
||||
if ((typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && 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();
|
||||
}
|
||||
|
||||
instrumentOutgoingRequests({
|
||||
traceFetch,
|
||||
traceXHR,
|
||||
tracePropagationTargets,
|
||||
shouldCreateSpanForRequest,
|
||||
_experiments: {
|
||||
enableHTTPTimings: _experiments.enableHTTPTimings,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/** Create routing idle transaction. */
|
||||
_createRouteTransaction(context) {
|
||||
if (!this._getCurrentHub) {
|
||||
(typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) &&
|
||||
logger.warn(`[Tracing] Did not create ${context.op} transaction because _getCurrentHub is invalid.`);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const { beforeNavigate, idleTimeout, finalTimeout, heartbeatInterval } = this.options;
|
||||
|
||||
const isPageloadTransaction = context.op === 'pageload';
|
||||
|
||||
const sentryTraceMetaTagValue = isPageloadTransaction ? getMetaContent('sentry-trace') : null;
|
||||
const baggageMetaTagValue = isPageloadTransaction ? getMetaContent('baggage') : null;
|
||||
|
||||
const traceParentData = sentryTraceMetaTagValue ? extractTraceparentData(sentryTraceMetaTagValue) : undefined;
|
||||
const dynamicSamplingContext = baggageMetaTagValue
|
||||
? baggageHeaderToDynamicSamplingContext(baggageMetaTagValue)
|
||||
: undefined;
|
||||
|
||||
const expandedContext = {
|
||||
...context,
|
||||
...traceParentData,
|
||||
metadata: {
|
||||
...context.metadata,
|
||||
dynamicSamplingContext: traceParentData && !dynamicSamplingContext ? {} : dynamicSamplingContext,
|
||||
},
|
||||
trimEnd: true,
|
||||
};
|
||||
|
||||
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
|
||||
finalContext.metadata =
|
||||
finalContext.name !== expandedContext.name
|
||||
? { ...finalContext.metadata, source: 'custom' }
|
||||
: finalContext.metadata;
|
||||
|
||||
this._latestRouteName = finalContext.name;
|
||||
this._latestRouteSource = finalContext.metadata && finalContext.metadata.source;
|
||||
|
||||
if (finalContext.sampled === false) {
|
||||
(typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) &&
|
||||
logger.log(`[Tracing] Will not send ${finalContext.op} transaction because of beforeNavigate.`);
|
||||
}
|
||||
|
||||
(typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && logger.log(`[Tracing] Starting ${finalContext.op} transaction on scope`);
|
||||
|
||||
const hub = this._getCurrentHub();
|
||||
const { location } = WINDOW;
|
||||
|
||||
const idleTransaction = startIdleTransaction(
|
||||
hub,
|
||||
finalContext,
|
||||
idleTimeout,
|
||||
finalTimeout,
|
||||
true,
|
||||
{ location }, // for use in the tracesSampler
|
||||
heartbeatInterval,
|
||||
);
|
||||
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';
|
||||
|
||||
const currentTransaction = getActiveTransaction();
|
||||
if (currentTransaction && currentTransaction.op && ['navigation', 'pageload'].includes(currentTransaction.op)) {
|
||||
(typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) &&
|
||||
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.finish();
|
||||
inflightInteractionTransaction = undefined;
|
||||
}
|
||||
|
||||
if (!this._getCurrentHub) {
|
||||
(typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && logger.warn(`[Tracing] Did not create ${op} transaction because _getCurrentHub is invalid.`);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (!this._latestRouteName) {
|
||||
(typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) &&
|
||||
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._latestRouteName,
|
||||
op,
|
||||
trimEnd: true,
|
||||
metadata: {
|
||||
source: this._latestRouteSource || 'url',
|
||||
},
|
||||
};
|
||||
|
||||
inflightInteractionTransaction = startIdleTransaction(
|
||||
hub,
|
||||
context,
|
||||
idleTimeout,
|
||||
finalTimeout,
|
||||
true,
|
||||
{ location }, // for use in the tracesSampler
|
||||
heartbeatInterval,
|
||||
);
|
||||
};
|
||||
|
||||
['click'].forEach(type => {
|
||||
addEventListener(type, registerInteractionTransaction, { once: false, capture: true });
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/** 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') : null;
|
||||
}
|
||||
|
||||
export { BROWSER_TRACING_INTEGRATION_ID, BrowserTracing, getMetaContent };
|
||||
//# sourceMappingURL=browsertracing.js.map
|
||||
484
shared/logger/node_modules/@sentry-internal/tracing/esm/browser/metrics/index.js
generated
vendored
Normal file
484
shared/logger/node_modules/@sentry-internal/tracing/esm/browser/metrics/index.js
generated
vendored
Normal file
@@ -0,0 +1,484 @@
|
||||
import { getActiveTransaction } from '@sentry/core';
|
||||
import { browserPerformanceTimeOrigin, logger, htmlTreeAsString } from '@sentry/utils';
|
||||
import { WINDOW } from '../types.js';
|
||||
import { onCLS } from '../web-vitals/getCLS.js';
|
||||
import { onFID } from '../web-vitals/getFID.js';
|
||||
import { onLCP } from '../web-vitals/getLCP.js';
|
||||
import { getVisibilityWatcher } from '../web-vitals/lib/getVisibilityWatcher.js';
|
||||
import { observe } from '../web-vitals/lib/observe.js';
|
||||
import { _startChild, isMeasurementValue } from './utils.js';
|
||||
|
||||
/**
|
||||
* Converts from milliseconds to seconds
|
||||
* @param time time in ms
|
||||
*/
|
||||
function msToSec(time) {
|
||||
return time / 1000;
|
||||
}
|
||||
|
||||
function getBrowserPerformanceAPI() {
|
||||
// @ts-ignore 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
|
||||
*
|
||||
* @returns A function that forces web vitals collection
|
||||
*/
|
||||
function startTrackingWebVitals() {
|
||||
const performance = getBrowserPerformanceAPI();
|
||||
if (performance && browserPerformanceTimeOrigin) {
|
||||
// @ts-ignore 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');
|
||||
}
|
||||
_trackFID();
|
||||
const clsCallback = _trackCLS();
|
||||
const lcpCallback = _trackLCP();
|
||||
|
||||
return () => {
|
||||
if (clsCallback) {
|
||||
clsCallback();
|
||||
}
|
||||
if (lcpCallback) {
|
||||
lcpCallback();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return () => undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start tracking long tasks.
|
||||
*/
|
||||
function startTrackingLongTasks() {
|
||||
const entryHandler = (entries) => {
|
||||
for (const entry of entries) {
|
||||
const transaction = getActiveTransaction() ;
|
||||
if (!transaction) {
|
||||
return;
|
||||
}
|
||||
const startTime = msToSec((browserPerformanceTimeOrigin ) + entry.startTime);
|
||||
const duration = msToSec(entry.duration);
|
||||
|
||||
transaction.startChild({
|
||||
description: 'Main UI thread blocked',
|
||||
op: 'ui.long-task',
|
||||
startTimestamp: startTime,
|
||||
endTimestamp: startTime + duration,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
observe('longtask', entryHandler);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start tracking interaction events.
|
||||
*/
|
||||
function startTrackingInteractions() {
|
||||
const entryHandler = (entries) => {
|
||||
for (const entry of entries) {
|
||||
const transaction = getActiveTransaction() ;
|
||||
if (!transaction) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (entry.name === 'click') {
|
||||
const startTime = msToSec((browserPerformanceTimeOrigin ) + entry.startTime);
|
||||
const duration = msToSec(entry.duration);
|
||||
|
||||
transaction.startChild({
|
||||
description: htmlTreeAsString(entry.target),
|
||||
op: `ui.interaction.${entry.name}`,
|
||||
startTimestamp: startTime,
|
||||
endTimestamp: startTime + duration,
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
observe('event', entryHandler, { durationThreshold: 0 });
|
||||
}
|
||||
|
||||
/** Starts tracking the Cumulative Layout Shift on the current page. */
|
||||
function _trackCLS() {
|
||||
// See:
|
||||
// https://web.dev/evolving-cls/
|
||||
// https://web.dev/cls-web-tooling/
|
||||
return onCLS(metric => {
|
||||
const entry = metric.entries.pop();
|
||||
if (!entry) {
|
||||
return;
|
||||
}
|
||||
|
||||
(typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && logger.log('[Measurements] Adding CLS');
|
||||
_measurements['cls'] = { value: metric.value, unit: '' };
|
||||
_clsEntry = entry ;
|
||||
});
|
||||
}
|
||||
|
||||
/** Starts tracking the Largest Contentful Paint on the current page. */
|
||||
function _trackLCP() {
|
||||
return onLCP(metric => {
|
||||
const entry = metric.entries.pop();
|
||||
if (!entry) {
|
||||
return;
|
||||
}
|
||||
|
||||
(typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && logger.log('[Measurements] Adding LCP');
|
||||
_measurements['lcp'] = { value: metric.value, unit: 'millisecond' };
|
||||
_lcpEntry = entry ;
|
||||
});
|
||||
}
|
||||
|
||||
/** Starts tracking the First Input Delay on the current page. */
|
||||
function _trackFID() {
|
||||
onFID(metric => {
|
||||
const entry = metric.entries.pop();
|
||||
if (!entry) {
|
||||
return;
|
||||
}
|
||||
|
||||
const timeOrigin = msToSec(browserPerformanceTimeOrigin );
|
||||
const startTime = msToSec(entry.startTime);
|
||||
(typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && logger.log('[Measurements] Adding FID');
|
||||
_measurements['fid'] = { value: metric.value, unit: 'millisecond' };
|
||||
_measurements['mark.fid'] = { value: timeOrigin + startTime, unit: 'second' };
|
||||
});
|
||||
}
|
||||
|
||||
/** 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;
|
||||
}
|
||||
|
||||
(typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && logger.log('[Tracing] Adding & adjusting spans using Performance API');
|
||||
const timeOrigin = msToSec(browserPerformanceTimeOrigin);
|
||||
|
||||
const performanceEntries = performance.getEntries();
|
||||
|
||||
let responseStartTimestamp;
|
||||
let requestStartTimestamp;
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
performanceEntries.slice(_performanceCursor).forEach((entry) => {
|
||||
const startTime = msToSec(entry.startTime);
|
||||
const duration = msToSec(entry.duration);
|
||||
|
||||
if (transaction.op === 'navigation' && timeOrigin + startTime < transaction.startTimestamp) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (entry.entryType) {
|
||||
case 'navigation': {
|
||||
_addNavigationSpans(transaction, entry, timeOrigin);
|
||||
responseStartTimestamp = timeOrigin + msToSec(entry.responseStart);
|
||||
requestStartTimestamp = timeOrigin + msToSec(entry.requestStart);
|
||||
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) {
|
||||
(typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && logger.log('[Measurements] Adding FP');
|
||||
_measurements['fp'] = { value: entry.startTime, unit: 'millisecond' };
|
||||
}
|
||||
if (entry.name === 'first-contentful-paint' && shouldRecord) {
|
||||
(typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && logger.log('[Measurements] Adding FCP');
|
||||
_measurements['fcp'] = { value: entry.startTime, unit: 'millisecond' };
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'resource': {
|
||||
const resourceName = (entry.name ).replace(WINDOW.location.origin, '');
|
||||
_addResourceSpans(transaction, entry, resourceName, 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 (transaction.op === 'pageload') {
|
||||
// Generate TTFB (Time to First Byte), which measured as the time between the beginning of the transaction and the
|
||||
// start of the response in milliseconds
|
||||
if (typeof responseStartTimestamp === 'number') {
|
||||
(typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && logger.log('[Measurements] Adding TTFB');
|
||||
_measurements['ttfb'] = {
|
||||
value: (responseStartTimestamp - transaction.startTimestamp) * 1000,
|
||||
unit: 'millisecond',
|
||||
};
|
||||
|
||||
if (typeof requestStartTimestamp === 'number' && requestStartTimestamp <= responseStartTimestamp) {
|
||||
// Capture the time spent making the request and receiving the first byte of the response.
|
||||
// This is the time between the start of the request and the start of the response in milliseconds.
|
||||
_measurements['ttfb.requestTime'] = {
|
||||
value: (responseStartTimestamp - requestStartTimestamp) * 1000,
|
||||
unit: 'millisecond',
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
['fcp', 'fp', 'lcp'].forEach(name => {
|
||||
if (!_measurements[name] || timeOrigin >= transaction.startTimestamp) {
|
||||
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 - transaction.startTimestamp) * 1000);
|
||||
const delta = normalizedValue - oldValue;
|
||||
|
||||
(typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) &&
|
||||
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',
|
||||
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 => {
|
||||
transaction.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 ,
|
||||
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',
|
||||
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) {
|
||||
_startChild(transaction, {
|
||||
op: 'browser',
|
||||
description: 'request',
|
||||
startTimestamp: timeOrigin + msToSec(entry.requestStart ),
|
||||
endTimestamp: timeOrigin + msToSec(entry.responseEnd ),
|
||||
});
|
||||
|
||||
_startChild(transaction, {
|
||||
op: 'browser',
|
||||
description: 'response',
|
||||
startTimestamp: timeOrigin + msToSec(entry.responseStart ),
|
||||
endTimestamp: timeOrigin + msToSec(entry.responseEnd ),
|
||||
});
|
||||
}
|
||||
|
||||
/** Create resource-related spans */
|
||||
function _addResourceSpans(
|
||||
transaction,
|
||||
entry,
|
||||
resourceName,
|
||||
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;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const data = {};
|
||||
if ('transferSize' in entry) {
|
||||
data['http.response_transfer_size'] = entry.transferSize;
|
||||
}
|
||||
if ('encodedBodySize' in entry) {
|
||||
data['http.response_content_length'] = entry.encodedBodySize;
|
||||
}
|
||||
if ('decodedBodySize' in entry) {
|
||||
data['http.decoded_response_content_length'] = entry.decodedBodySize;
|
||||
}
|
||||
if ('renderBlockingStatus' in entry) {
|
||||
data['resource.render_blocking_status'] = entry.renderBlockingStatus;
|
||||
}
|
||||
|
||||
const startTimestamp = timeOrigin + startTime;
|
||||
const endTimestamp = startTimestamp + duration;
|
||||
|
||||
_startChild(transaction, {
|
||||
description: resourceName,
|
||||
endTimestamp,
|
||||
op: entry.initiatorType ? `resource.${entry.initiatorType}` : 'resource.other',
|
||||
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) {
|
||||
transaction.setTag('effectiveConnectionType', connection.effectiveType);
|
||||
}
|
||||
|
||||
if (connection.type) {
|
||||
transaction.setTag('connectionType', connection.type);
|
||||
}
|
||||
|
||||
if (isMeasurementValue(connection.rtt)) {
|
||||
_measurements['connection.rtt'] = { value: connection.rtt, unit: 'millisecond' };
|
||||
}
|
||||
}
|
||||
|
||||
if (isMeasurementValue(navigator.deviceMemory)) {
|
||||
transaction.setTag('deviceMemory', `${navigator.deviceMemory} GB`);
|
||||
}
|
||||
|
||||
if (isMeasurementValue(navigator.hardwareConcurrency)) {
|
||||
transaction.setTag('hardwareConcurrency', String(navigator.hardwareConcurrency));
|
||||
}
|
||||
}
|
||||
|
||||
/** Add LCP / CLS data to transaction to allow debugging */
|
||||
function _tagMetricInfo(transaction) {
|
||||
if (_lcpEntry) {
|
||||
(typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && logger.log('[Measurements] Adding LCP Data');
|
||||
|
||||
// Capture Properties of the LCP element that contributes to the LCP.
|
||||
|
||||
if (_lcpEntry.element) {
|
||||
transaction.setTag('lcp.element', htmlTreeAsString(_lcpEntry.element));
|
||||
}
|
||||
|
||||
if (_lcpEntry.id) {
|
||||
transaction.setTag('lcp.id', _lcpEntry.id);
|
||||
}
|
||||
|
||||
if (_lcpEntry.url) {
|
||||
// Trim URL to the first 200 characters.
|
||||
transaction.setTag('lcp.url', _lcpEntry.url.trim().slice(0, 200));
|
||||
}
|
||||
|
||||
transaction.setTag('lcp.size', _lcpEntry.size);
|
||||
}
|
||||
|
||||
// See: https://developer.mozilla.org/en-US/docs/Web/API/LayoutShift
|
||||
if (_clsEntry && _clsEntry.sources) {
|
||||
(typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && logger.log('[Measurements] Adding CLS Data');
|
||||
_clsEntry.sources.forEach((source, index) =>
|
||||
transaction.setTag(`cls.source.${index + 1}`, htmlTreeAsString(source.node)),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export { _addMeasureSpans, _addResourceSpans, addPerformanceEntries, startTrackingInteractions, startTrackingLongTasks, startTrackingWebVitals };
|
||||
//# sourceMappingURL=index.js.map
|
||||
25
shared/logger/node_modules/@sentry-internal/tracing/esm/browser/metrics/utils.js
generated
vendored
Normal file
25
shared/logger/node_modules/@sentry-internal/tracing/esm/browser/metrics/utils.js
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
function _startChild(transaction, { startTimestamp, ...ctx }) {
|
||||
if (startTimestamp && transaction.startTimestamp > startTimestamp) {
|
||||
transaction.startTimestamp = startTimestamp;
|
||||
}
|
||||
|
||||
return transaction.startChild({
|
||||
startTimestamp,
|
||||
...ctx,
|
||||
});
|
||||
}
|
||||
|
||||
export { _startChild, isMeasurementValue };
|
||||
//# sourceMappingURL=utils.js.map
|
||||
335
shared/logger/node_modules/@sentry-internal/tracing/esm/browser/request.js
generated
vendored
Normal file
335
shared/logger/node_modules/@sentry-internal/tracing/esm/browser/request.js
generated
vendored
Normal file
@@ -0,0 +1,335 @@
|
||||
import { _optionalChain } from '@sentry/utils/esm/buildPolyfills';
|
||||
import { hasTracingEnabled, getCurrentHub } from '@sentry/core';
|
||||
import { addInstrumentationHandler, browserPerformanceTimeOrigin, dynamicSamplingContextToSentryBaggageHeader, isInstanceOf, BAGGAGE_HEADER_NAME, SENTRY_XHR_DATA_KEY, stringMatchesSomePattern } from '@sentry/utils';
|
||||
|
||||
/* eslint-disable max-lines */
|
||||
|
||||
const DEFAULT_TRACE_PROPAGATION_TARGETS = ['localhost', /^\/(?!\/)/];
|
||||
|
||||
/** Options for Request Instrumentation */
|
||||
|
||||
const defaultRequestInstrumentationOptions = {
|
||||
traceFetch: true,
|
||||
traceXHR: true,
|
||||
// TODO (v8): Remove this property
|
||||
tracingOrigins: DEFAULT_TRACE_PROPAGATION_TARGETS,
|
||||
tracePropagationTargets: DEFAULT_TRACE_PROPAGATION_TARGETS,
|
||||
_experiments: {},
|
||||
};
|
||||
|
||||
/** Registers span creators for xhr and fetch requests */
|
||||
function instrumentOutgoingRequests(_options) {
|
||||
// eslint-disable-next-line deprecation/deprecation
|
||||
const { traceFetch, traceXHR, tracePropagationTargets, tracingOrigins, shouldCreateSpanForRequest, _experiments } = {
|
||||
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) {
|
||||
addInstrumentationHandler('fetch', (handlerData) => {
|
||||
const createdSpan = fetchCallback(handlerData, shouldCreateSpan, shouldAttachHeadersWithTargets, spans);
|
||||
if (_optionalChain([_experiments, 'optionalAccess', _2 => _2.enableHTTPTimings]) && createdSpan) {
|
||||
addHTTPTimings(createdSpan);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (traceXHR) {
|
||||
addInstrumentationHandler('xhr', (handlerData) => {
|
||||
const createdSpan = xhrCallback(handlerData, shouldCreateSpan, shouldAttachHeadersWithTargets, spans);
|
||||
if (_optionalChain([_experiments, 'optionalAccess', _3 => _3.enableHTTPTimings]) && createdSpan) {
|
||||
addHTTPTimings(createdSpan);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 = span.data.url;
|
||||
const observer = new PerformanceObserver(list => {
|
||||
const entries = list.getEntries() ;
|
||||
entries.forEach(entry => {
|
||||
if ((entry.initiatorType === 'fetch' || entry.initiatorType === 'xmlhttprequest') && entry.name.endsWith(url)) {
|
||||
const spanData = resourceTimingEntryToSpanData(entry);
|
||||
spanData.forEach(data => span.setData(...data));
|
||||
observer.disconnect();
|
||||
}
|
||||
});
|
||||
});
|
||||
observer.observe({
|
||||
entryTypes: ['resource'],
|
||||
});
|
||||
}
|
||||
|
||||
function resourceTimingEntryToSpanData(resourceTiming) {
|
||||
const version = resourceTiming.nextHopProtocol.split('/')[1] || 'none';
|
||||
|
||||
const timingSpanData = [];
|
||||
if (version) {
|
||||
timingSpanData.push(['network.protocol.version', version]);
|
||||
}
|
||||
|
||||
if (!browserPerformanceTimeOrigin) {
|
||||
return timingSpanData;
|
||||
}
|
||||
return [
|
||||
...timingSpanData,
|
||||
['http.request.connect_start', (browserPerformanceTimeOrigin + resourceTiming.connectStart) / 1000],
|
||||
['http.request.request_start', (browserPerformanceTimeOrigin + resourceTiming.requestStart) / 1000],
|
||||
['http.request.response_start', (browserPerformanceTimeOrigin + resourceTiming.responseStart) / 1000],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 fetch request spans
|
||||
*
|
||||
* @returns Span if a span was created, otherwise void.
|
||||
*/
|
||||
function fetchCallback(
|
||||
handlerData,
|
||||
shouldCreateSpan,
|
||||
shouldAttachHeaders,
|
||||
spans,
|
||||
) {
|
||||
if (!hasTracingEnabled() || !(handlerData.fetchData && shouldCreateSpan(handlerData.fetchData.url))) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (handlerData.endTimestamp) {
|
||||
const spanId = handlerData.fetchData.__span;
|
||||
if (!spanId) return;
|
||||
|
||||
const span = spans[spanId];
|
||||
if (span) {
|
||||
if (handlerData.response) {
|
||||
// TODO (kmclb) remove this once types PR goes through
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
||||
span.setHttpStatus(handlerData.response.status);
|
||||
|
||||
const contentLength =
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
||||
handlerData.response && handlerData.response.headers && handlerData.response.headers.get('content-length');
|
||||
|
||||
const contentLengthNum = parseInt(contentLength);
|
||||
if (contentLengthNum > 0) {
|
||||
span.setData('http.response_content_length', contentLengthNum);
|
||||
}
|
||||
} else if (handlerData.error) {
|
||||
span.setStatus('internal_error');
|
||||
}
|
||||
span.finish();
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
|
||||
delete spans[spanId];
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const currentSpan = getCurrentHub().getScope().getSpan();
|
||||
const activeTransaction = currentSpan && currentSpan.transaction;
|
||||
|
||||
if (currentSpan && activeTransaction) {
|
||||
const { method, url } = handlerData.fetchData;
|
||||
const span = currentSpan.startChild({
|
||||
data: {
|
||||
url,
|
||||
type: 'fetch',
|
||||
'http.method': method,
|
||||
},
|
||||
description: `${method} ${url}`,
|
||||
op: 'http.client',
|
||||
});
|
||||
|
||||
handlerData.fetchData.__span = span.spanId;
|
||||
spans[span.spanId] = span;
|
||||
|
||||
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];
|
||||
|
||||
if (shouldAttachHeaders(handlerData.fetchData.url)) {
|
||||
options.headers = addTracingHeadersToFetchRequest(
|
||||
request,
|
||||
activeTransaction.getDynamicSamplingContext(),
|
||||
span,
|
||||
options,
|
||||
);
|
||||
}
|
||||
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,
|
||||
dynamicSamplingContext,
|
||||
span,
|
||||
options
|
||||
|
||||
,
|
||||
) {
|
||||
const sentryBaggageHeader = dynamicSamplingContextToSentryBaggageHeader(dynamicSamplingContext);
|
||||
const sentryTraceHeader = span.toTraceparent();
|
||||
|
||||
const headers =
|
||||
typeof Request !== 'undefined' && isInstanceOf(request, Request) ? (request ).headers : options.headers;
|
||||
|
||||
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,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and track xhr request spans
|
||||
*
|
||||
* @returns Span if a span was created, otherwise void.
|
||||
*/
|
||||
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__) ||
|
||||
!(xhr && sentryXhrData && shouldCreateSpan(sentryXhrData.url))
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
// check first if the request has finished and is tracked by an existing span which should now end
|
||||
if (handlerData.endTimestamp) {
|
||||
const spanId = xhr.__sentry_xhr_span_id__;
|
||||
if (!spanId) return;
|
||||
|
||||
const span = spans[spanId];
|
||||
if (span) {
|
||||
span.setHttpStatus(sentryXhrData.status_code);
|
||||
span.finish();
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
|
||||
delete spans[spanId];
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const currentSpan = getCurrentHub().getScope().getSpan();
|
||||
const activeTransaction = currentSpan && currentSpan.transaction;
|
||||
|
||||
if (currentSpan && activeTransaction) {
|
||||
const span = currentSpan.startChild({
|
||||
data: {
|
||||
...sentryXhrData.data,
|
||||
type: 'xhr',
|
||||
'http.method': sentryXhrData.method,
|
||||
url: sentryXhrData.url,
|
||||
},
|
||||
description: `${sentryXhrData.method} ${sentryXhrData.url}`,
|
||||
op: 'http.client',
|
||||
});
|
||||
|
||||
xhr.__sentry_xhr_span_id__ = span.spanId;
|
||||
spans[xhr.__sentry_xhr_span_id__] = span;
|
||||
|
||||
if (xhr.setRequestHeader && shouldAttachHeaders(sentryXhrData.url)) {
|
||||
try {
|
||||
xhr.setRequestHeader('sentry-trace', span.toTraceparent());
|
||||
|
||||
const dynamicSamplingContext = activeTransaction.getDynamicSamplingContext();
|
||||
const sentryBaggageHeader = dynamicSamplingContextToSentryBaggageHeader(dynamicSamplingContext);
|
||||
|
||||
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
|
||||
xhr.setRequestHeader(BAGGAGE_HEADER_NAME, sentryBaggageHeader);
|
||||
}
|
||||
} catch (_) {
|
||||
// Error: InvalidStateError: Failed to execute 'setRequestHeader' on 'XMLHttpRequest': The object's state must be OPENED.
|
||||
}
|
||||
}
|
||||
|
||||
return span;
|
||||
}
|
||||
}
|
||||
|
||||
export { DEFAULT_TRACE_PROPAGATION_TARGETS, addTracingHeadersToFetchRequest, defaultRequestInstrumentationOptions, instrumentOutgoingRequests, shouldAttachHeaders };
|
||||
//# sourceMappingURL=request.js.map
|
||||
64
shared/logger/node_modules/@sentry-internal/tracing/esm/browser/router.js
generated
vendored
Normal file
64
shared/logger/node_modules/@sentry-internal/tracing/esm/browser/router.js
generated
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
import { logger, browserPerformanceTimeOrigin, addInstrumentationHandler } from '@sentry/utils';
|
||||
import { WINDOW } from './types.js';
|
||||
|
||||
/**
|
||||
* Default function implementing pageload and navigation transactions
|
||||
*/
|
||||
function instrumentRoutingWithDefaults(
|
||||
customStartTransaction,
|
||||
startTransactionOnPageLoad = true,
|
||||
startTransactionOnLocationChange = true,
|
||||
) {
|
||||
if (!WINDOW || !WINDOW.location) {
|
||||
(typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && 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',
|
||||
metadata: { source: 'url' },
|
||||
});
|
||||
}
|
||||
|
||||
if (startTransactionOnLocationChange) {
|
||||
addInstrumentationHandler('history', ({ 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) {
|
||||
(typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__) && 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.finish();
|
||||
}
|
||||
activeTransaction = customStartTransaction({
|
||||
name: WINDOW.location.pathname,
|
||||
op: 'navigation',
|
||||
metadata: { source: 'url' },
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export { instrumentRoutingWithDefaults };
|
||||
//# sourceMappingURL=router.js.map
|
||||
6
shared/logger/node_modules/@sentry-internal/tracing/esm/browser/types.js
generated
vendored
Normal file
6
shared/logger/node_modules/@sentry-internal/tracing/esm/browser/types.js
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
import { GLOBAL_OBJ } from '@sentry/utils';
|
||||
|
||||
const WINDOW = GLOBAL_OBJ ;
|
||||
|
||||
export { WINDOW };
|
||||
//# sourceMappingURL=types.js.map
|
||||
105
shared/logger/node_modules/@sentry-internal/tracing/esm/browser/web-vitals/getCLS.js
generated
vendored
Normal file
105
shared/logger/node_modules/@sentry-internal/tracing/esm/browser/web-vitals/getCLS.js
generated
vendored
Normal file
@@ -0,0 +1,105 @@
|
||||
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) => {
|
||||
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);
|
||||
|
||||
const stopListening = () => {
|
||||
handleEntries(po.takeRecords() );
|
||||
report(true);
|
||||
};
|
||||
|
||||
onHidden(stopListening);
|
||||
|
||||
return stopListening;
|
||||
}
|
||||
|
||||
return;
|
||||
};
|
||||
|
||||
export { onCLS };
|
||||
//# sourceMappingURL=getCLS.js.map
|
||||
63
shared/logger/node_modules/@sentry-internal/tracing/esm/browser/web-vitals/getFID.js
generated
vendored
Normal file
63
shared/logger/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
|
||||
85
shared/logger/node_modules/@sentry-internal/tracing/esm/browser/web-vitals/getLCP.js
generated
vendored
Normal file
85
shared/logger/node_modules/@sentry-internal/tracing/esm/browser/web-vitals/getLCP.js
generated
vendored
Normal file
@@ -0,0 +1,85 @@
|
||||
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 => {
|
||||
addEventListener(type, stopListening, { once: true, capture: true });
|
||||
});
|
||||
|
||||
onHidden(stopListening, true);
|
||||
|
||||
return stopListening;
|
||||
}
|
||||
|
||||
return;
|
||||
};
|
||||
|
||||
export { onLCP };
|
||||
//# sourceMappingURL=getLCP.js.map
|
||||
28
shared/logger/node_modules/@sentry-internal/tracing/esm/browser/web-vitals/lib/bindReporter.js
generated
vendored
Normal file
28
shared/logger/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
|
||||
27
shared/logger/node_modules/@sentry-internal/tracing/esm/browser/web-vitals/lib/generateUniqueID.js
generated
vendored
Normal file
27
shared/logger/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
|
||||
25
shared/logger/node_modules/@sentry-internal/tracing/esm/browser/web-vitals/lib/getActivationStart.js
generated
vendored
Normal file
25
shared/logger/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
|
||||
53
shared/logger/node_modules/@sentry-internal/tracing/esm/browser/web-vitals/lib/getNavigationEntry.js
generated
vendored
Normal file
53
shared/logger/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
|
||||
54
shared/logger/node_modules/@sentry-internal/tracing/esm/browser/web-vitals/lib/getVisibilityWatcher.js
generated
vendored
Normal file
54
shared/logger/node_modules/@sentry-internal/tracing/esm/browser/web-vitals/lib/getVisibilityWatcher.js
generated
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
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.
|
||||
return 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.
|
||||
firstHiddenTime = initHiddenTime();
|
||||
trackChanges();
|
||||
}
|
||||
return {
|
||||
get firstHiddenTime() {
|
||||
return firstHiddenTime;
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export { getVisibilityWatcher };
|
||||
//# sourceMappingURL=getVisibilityWatcher.js.map
|
||||
46
shared/logger/node_modules/@sentry-internal/tracing/esm/browser/web-vitals/lib/initMetric.js
generated
vendored
Normal file
46
shared/logger/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.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
|
||||
37
shared/logger/node_modules/@sentry-internal/tracing/esm/browser/web-vitals/lib/observe.js
generated
vendored
Normal file
37
shared/logger/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
|
||||
36
shared/logger/node_modules/@sentry-internal/tracing/esm/browser/web-vitals/lib/onHidden.js
generated
vendored
Normal file
36
shared/logger/node_modules/@sentry-internal/tracing/esm/browser/web-vitals/lib/onHidden.js
generated
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
};
|
||||
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
|
||||
Reference in New Issue
Block a user