@sentry/browser 10.47.0 → 10.49.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/npm/cjs/dev/index.js +7 -0
- package/build/npm/cjs/dev/index.js.map +1 -1
- package/build/npm/cjs/dev/integrations/spanstreaming.js +67 -0
- package/build/npm/cjs/dev/integrations/spanstreaming.js.map +1 -0
- package/build/npm/cjs/dev/integrations/view-hierarchy.js +101 -0
- package/build/npm/cjs/dev/integrations/view-hierarchy.js.map +1 -0
- package/build/npm/cjs/dev/tracing/browserTracingIntegration.js +18 -7
- package/build/npm/cjs/dev/tracing/browserTracingIntegration.js.map +1 -1
- package/build/npm/cjs/dev/tracing/request.js +45 -7
- package/build/npm/cjs/dev/tracing/request.js.map +1 -1
- package/build/npm/cjs/dev/utils/lazyLoadIntegration.js +1 -0
- package/build/npm/cjs/dev/utils/lazyLoadIntegration.js.map +1 -1
- package/build/npm/cjs/prod/index.js +7 -0
- package/build/npm/cjs/prod/index.js.map +1 -1
- package/build/npm/cjs/prod/integrations/spanstreaming.js +67 -0
- package/build/npm/cjs/prod/integrations/spanstreaming.js.map +1 -0
- package/build/npm/cjs/prod/integrations/view-hierarchy.js +101 -0
- package/build/npm/cjs/prod/integrations/view-hierarchy.js.map +1 -0
- package/build/npm/cjs/prod/tracing/browserTracingIntegration.js +18 -7
- package/build/npm/cjs/prod/tracing/browserTracingIntegration.js.map +1 -1
- package/build/npm/cjs/prod/tracing/request.js +45 -7
- package/build/npm/cjs/prod/tracing/request.js.map +1 -1
- package/build/npm/cjs/prod/utils/lazyLoadIntegration.js +1 -0
- package/build/npm/cjs/prod/utils/lazyLoadIntegration.js.map +1 -1
- package/build/npm/esm/dev/index.js +4 -2
- package/build/npm/esm/dev/index.js.map +1 -1
- package/build/npm/esm/dev/integrations/spanstreaming.js +65 -0
- package/build/npm/esm/dev/integrations/spanstreaming.js.map +1 -0
- package/build/npm/esm/dev/integrations/view-hierarchy.js +99 -0
- package/build/npm/esm/dev/integrations/view-hierarchy.js.map +1 -0
- package/build/npm/esm/dev/package.json +1 -1
- package/build/npm/esm/dev/tracing/browserTracingIntegration.js +20 -10
- package/build/npm/esm/dev/tracing/browserTracingIntegration.js.map +1 -1
- package/build/npm/esm/dev/tracing/request.js +46 -8
- package/build/npm/esm/dev/tracing/request.js.map +1 -1
- package/build/npm/esm/dev/utils/lazyLoadIntegration.js +1 -0
- package/build/npm/esm/dev/utils/lazyLoadIntegration.js.map +1 -1
- package/build/npm/esm/prod/index.js +4 -2
- package/build/npm/esm/prod/index.js.map +1 -1
- package/build/npm/esm/prod/integrations/spanstreaming.js +65 -0
- package/build/npm/esm/prod/integrations/spanstreaming.js.map +1 -0
- package/build/npm/esm/prod/integrations/view-hierarchy.js +99 -0
- package/build/npm/esm/prod/integrations/view-hierarchy.js.map +1 -0
- package/build/npm/esm/prod/package.json +1 -1
- package/build/npm/esm/prod/tracing/browserTracingIntegration.js +20 -10
- package/build/npm/esm/prod/tracing/browserTracingIntegration.js.map +1 -1
- package/build/npm/esm/prod/tracing/request.js +46 -8
- package/build/npm/esm/prod/tracing/request.js.map +1 -1
- package/build/npm/esm/prod/utils/lazyLoadIntegration.js +1 -0
- package/build/npm/esm/prod/utils/lazyLoadIntegration.js.map +1 -1
- package/build/npm/types/exports.d.ts +1 -1
- package/build/npm/types/exports.d.ts.map +1 -1
- package/build/npm/types/index.bundle.tracing.d.ts +1 -1
- package/build/npm/types/index.bundle.tracing.d.ts.map +1 -1
- package/build/npm/types/index.bundle.tracing.logs.metrics.d.ts +1 -1
- package/build/npm/types/index.bundle.tracing.logs.metrics.d.ts.map +1 -1
- package/build/npm/types/index.bundle.tracing.replay.d.ts +1 -1
- package/build/npm/types/index.bundle.tracing.replay.d.ts.map +1 -1
- package/build/npm/types/index.bundle.tracing.replay.feedback.d.ts +1 -1
- package/build/npm/types/index.bundle.tracing.replay.feedback.d.ts.map +1 -1
- package/build/npm/types/index.bundle.tracing.replay.feedback.logs.metrics.d.ts +1 -1
- package/build/npm/types/index.bundle.tracing.replay.feedback.logs.metrics.d.ts.map +1 -1
- package/build/npm/types/index.bundle.tracing.replay.logs.metrics.d.ts +1 -1
- package/build/npm/types/index.bundle.tracing.replay.logs.metrics.d.ts.map +1 -1
- package/build/npm/types/index.d.ts +4 -2
- package/build/npm/types/index.d.ts.map +1 -1
- package/build/npm/types/integrations/spanstreaming.d.ts +2 -0
- package/build/npm/types/integrations/spanstreaming.d.ts.map +1 -0
- package/build/npm/types/integrations/view-hierarchy.d.ts +49 -0
- package/build/npm/types/integrations/view-hierarchy.d.ts.map +1 -0
- package/build/npm/types/integrations-bundle/index.instrumentlangchainembeddings.d.ts +2 -0
- package/build/npm/types/integrations-bundle/index.instrumentlangchainembeddings.d.ts.map +1 -0
- package/build/npm/types/tracing/browserTracingIntegration.d.ts +1 -0
- package/build/npm/types/tracing/browserTracingIntegration.d.ts.map +1 -1
- package/build/npm/types/tracing/request.d.ts.map +1 -1
- package/build/npm/types/utils/lazyLoadIntegration.d.ts +1 -1
- package/build/npm/types/utils/lazyLoadIntegration.d.ts.map +1 -1
- package/build/npm/types-ts3.8/exports.d.ts +1 -1
- package/build/npm/types-ts3.8/index.bundle.tracing.d.ts +1 -1
- package/build/npm/types-ts3.8/index.bundle.tracing.logs.metrics.d.ts +1 -1
- package/build/npm/types-ts3.8/index.bundle.tracing.replay.d.ts +1 -1
- package/build/npm/types-ts3.8/index.bundle.tracing.replay.feedback.d.ts +1 -1
- package/build/npm/types-ts3.8/index.bundle.tracing.replay.feedback.logs.metrics.d.ts +1 -1
- package/build/npm/types-ts3.8/index.bundle.tracing.replay.logs.metrics.d.ts +1 -1
- package/build/npm/types-ts3.8/index.d.ts +4 -2
- package/build/npm/types-ts3.8/integrations/spanstreaming.d.ts +2 -0
- package/build/npm/types-ts3.8/integrations/view-hierarchy.d.ts +49 -0
- package/build/npm/types-ts3.8/integrations-bundle/index.instrumentlangchainembeddings.d.ts +2 -0
- package/build/npm/types-ts3.8/tracing/browserTracingIntegration.d.ts +1 -0
- package/build/npm/types-ts3.8/utils/lazyLoadIntegration.d.ts +2 -1
- package/package.json +7 -7
|
@@ -92,7 +92,7 @@ function instrumentOutgoingRequests(client, _options) {
|
|
|
92
92
|
});
|
|
93
93
|
|
|
94
94
|
if (enableHTTPTimings) {
|
|
95
|
-
addHTTPTimings(createdSpan);
|
|
95
|
+
addHTTPTimings(createdSpan, client);
|
|
96
96
|
}
|
|
97
97
|
|
|
98
98
|
onRequestSpanStart?.(createdSpan, { headers: handlerData.headers });
|
|
@@ -113,7 +113,7 @@ function instrumentOutgoingRequests(client, _options) {
|
|
|
113
113
|
|
|
114
114
|
if (createdSpan) {
|
|
115
115
|
if (enableHTTPTimings) {
|
|
116
|
-
addHTTPTimings(createdSpan);
|
|
116
|
+
addHTTPTimings(createdSpan, client);
|
|
117
117
|
}
|
|
118
118
|
|
|
119
119
|
onRequestSpanStart?.(createdSpan, {
|
|
@@ -124,26 +124,64 @@ function instrumentOutgoingRequests(client, _options) {
|
|
|
124
124
|
}
|
|
125
125
|
}
|
|
126
126
|
|
|
127
|
+
/**
|
|
128
|
+
* The maximum time (ms) to wait for PerformanceResourceTiming data before ending the span.
|
|
129
|
+
* Same approach is used by OTel's browser fetch instrumentation:
|
|
130
|
+
* See {@link https://github.com/open-telemetry/opentelemetry-js/blob/30f94fe99339287b1e4d3c8bb90172c2523f06f4/experimental/packages/opentelemetry-instrumentation-fetch/src/fetch.ts#L352-L372}
|
|
131
|
+
*/
|
|
132
|
+
const HTTP_TIMING_WAIT_MS = 300;
|
|
133
|
+
|
|
127
134
|
/**
|
|
128
135
|
* Creates a temporary observer to listen to the next fetch/xhr resourcing timings,
|
|
129
136
|
* so that when timings hit their per-browser limit they don't need to be removed.
|
|
130
137
|
*
|
|
131
138
|
* @param span A span that has yet to be finished, must contain `url` on data.
|
|
132
139
|
*/
|
|
133
|
-
function addHTTPTimings(span) {
|
|
140
|
+
function addHTTPTimings(span, client) {
|
|
134
141
|
const { url } = core.spanToJSON(span).data;
|
|
135
142
|
|
|
136
143
|
if (!url || typeof url !== 'string') {
|
|
137
144
|
return;
|
|
138
145
|
}
|
|
139
146
|
|
|
140
|
-
|
|
147
|
+
// Clean up the performance observer and other resources
|
|
148
|
+
// We have to wait here because otherwise this cleans itself up before it is fully done.
|
|
149
|
+
// Default (non-streaming): just deregister the observer.
|
|
150
|
+
let onEntryFound = () => void setTimeout(unsubscribePerformanceObsever);
|
|
151
|
+
|
|
152
|
+
// For streamed spans, we have to artificially delay the ending of the span until we
|
|
153
|
+
// either receive the timing data, or HTTP_TIMING_WAIT_MS elapses.
|
|
154
|
+
if (core.hasSpanStreamingEnabled(client)) {
|
|
155
|
+
const originalEnd = span.end.bind(span);
|
|
156
|
+
|
|
157
|
+
span.end = (endTimestamp) => {
|
|
158
|
+
const capturedEndTimestamp = endTimestamp ?? core.timestampInSeconds();
|
|
159
|
+
let isEnded = false;
|
|
160
|
+
|
|
161
|
+
const endSpanAndCleanup = () => {
|
|
162
|
+
if (isEnded) {
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
isEnded = true;
|
|
166
|
+
setTimeout(unsubscribePerformanceObsever);
|
|
167
|
+
originalEnd(capturedEndTimestamp);
|
|
168
|
+
clearTimeout(fallbackTimeout);
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
onEntryFound = endSpanAndCleanup;
|
|
172
|
+
|
|
173
|
+
// Fallback: always end the span after HTTP_TIMING_WAIT_MS even if no
|
|
174
|
+
// PerformanceResourceTiming entry arrives (e.g. cross-origin without
|
|
175
|
+
// Timing-Allow-Origin, or the browser didn't fire the observer in time).
|
|
176
|
+
const fallbackTimeout = setTimeout(endSpanAndCleanup, HTTP_TIMING_WAIT_MS);
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
const unsubscribePerformanceObsever = browserUtils.addPerformanceInstrumentationHandler('resource', ({ entries }) => {
|
|
141
181
|
entries.forEach(entry => {
|
|
142
182
|
if (utils.isPerformanceResourceTiming(entry) && entry.name.endsWith(url)) {
|
|
143
183
|
span.setAttributes(browserUtils.resourceTimingToSpanAttributes(entry));
|
|
144
|
-
|
|
145
|
-
// We have to wait here because otherwise this cleans itself up before it is fully done
|
|
146
|
-
setTimeout(cleanup);
|
|
184
|
+
onEntryFound();
|
|
147
185
|
}
|
|
148
186
|
});
|
|
149
187
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"request.js","sources":["../../../../../src/tracing/request.ts"],"sourcesContent":["import type {\n Client,\n HandlerDataXhr,\n RequestHookInfo,\n ResponseHookInfo,\n SentryWrappedXMLHttpRequest,\n Span,\n} from '@sentry/core';\nimport {\n addFetchEndInstrumentationHandler,\n addFetchInstrumentationHandler,\n getActiveSpan,\n getClient,\n getLocationHref,\n getTraceData,\n hasSpansEnabled,\n instrumentFetchRequest,\n parseUrl,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n SentryNonRecordingSpan,\n setHttpStatus,\n spanToJSON,\n startInactiveSpan,\n stringMatchesSomePattern,\n stripDataUrlContent,\n stripUrlQueryAndFragment,\n} from '@sentry/core';\nimport type { XhrHint } from '@sentry-internal/browser-utils';\nimport {\n addPerformanceInstrumentationHandler,\n addXhrInstrumentationHandler,\n parseXhrResponseHeaders,\n resourceTimingToSpanAttributes,\n SENTRY_XHR_DATA_KEY,\n} from '@sentry-internal/browser-utils';\nimport type { BrowserClient } from '../client';\nimport { baggageHeaderHasSentryValues, createHeadersSafely, getFullURL, isPerformanceResourceTiming } from './utils';\n\n/** Options for Request Instrumentation */\nexport interface RequestInstrumentationOptions {\n /**\n * List of strings and/or Regular Expressions used to determine which outgoing requests will have `sentry-trace` and `baggage`\n * headers attached.\n *\n * **Default:** If this option is not provided, tracing headers will be attached to all outgoing requests.\n * If you are using a browser SDK, by default, tracing headers will only be attached to outgoing requests to the same origin.\n *\n * **Disclaimer:** Carelessly setting this option in browser environments may result into CORS errors!\n * Only attach tracing headers to requests to the same origin, or to requests to services you can control CORS headers of.\n * Cross-origin requests, meaning requests to a different domain, for example a request to `https://api.example.com/` while you're on `https://example.com/`, take special care.\n * If you are attaching headers to cross-origin requests, make sure the backend handling the request returns a `\"Access-Control-Allow-Headers: sentry-trace, baggage\"` header to ensure your requests aren't blocked.\n *\n * If you provide a `tracePropagationTargets` array, the entries you provide will be matched against the entire URL of the outgoing request.\n * If you are using a browser SDK, the entries will also be matched against the pathname of the outgoing requests.\n * This is so you can have matchers for relative requests, for example, `/^\\/api/` if you want to trace requests to your `/api` routes on the same domain.\n *\n * If any of the two match any of the provided values, tracing headers will be attached to the outgoing request.\n * Both, the string values, and the RegExes you provide in the array will match if they partially match the URL or pathname.\n *\n * Examples:\n * - `tracePropagationTargets: [/^\\/api/]` and request to `https://same-origin.com/api/posts`:\n * - Tracing headers will be attached because the request is sent to the same origin and the regex matches the pathname \"/api/posts\".\n * - `tracePropagationTargets: [/^\\/api/]` and request to `https://different-origin.com/api/posts`:\n * - Tracing headers will not be attached because the pathname will only be compared when the request target lives on the same origin.\n * - `tracePropagationTargets: [/^\\/api/, 'https://external-api.com']` and request to `https://external-api.com/v1/data`:\n * - Tracing headers will be attached because the request URL matches the string `'https://external-api.com'`.\n */\n tracePropagationTargets?: Array<string | RegExp>;\n\n /**\n * Flag to disable patching all together for fetch requests.\n *\n * Default: true\n */\n traceFetch: boolean;\n\n /**\n * Flag to disable patching all together for xhr requests.\n *\n * Default: true\n */\n traceXHR: boolean;\n\n /**\n * Flag to disable tracking of long-lived streams, like server-sent events (SSE) via fetch.\n * Do not enable this in case you have live streams or very long running streams.\n *\n * Disabled by default since it can lead to issues with streams using the `cancel()` api\n * (https://github.com/getsentry/sentry-javascript/issues/13950)\n *\n * Default: false\n */\n trackFetchStreamPerformance: boolean;\n\n /**\n * If true, Sentry will capture http timings and add them to the corresponding http spans.\n *\n * Default: true\n */\n enableHTTPTimings: boolean;\n\n /**\n * This function will be called before creating a span for a request with the given url.\n * Return false if you don't want a span for the given url.\n *\n * Default: (url: string) => true\n */\n shouldCreateSpanForRequest?(this: void, url: string): boolean;\n\n /**\n * Is called when spans are started for outgoing requests.\n */\n onRequestSpanStart?(span: Span, requestInformation: RequestHookInfo): void;\n\n /**\n * Is called when spans end for outgoing requests, providing access to response headers.\n */\n onRequestSpanEnd?(span: Span, responseInformation: ResponseHookInfo): void;\n}\n\nconst responseToSpanId = new WeakMap<object, string>();\nconst spanIdToEndTimestamp = new Map<string, number>();\n\nexport const defaultRequestInstrumentationOptions: RequestInstrumentationOptions = {\n traceFetch: true,\n traceXHR: true,\n enableHTTPTimings: true,\n trackFetchStreamPerformance: false,\n};\n\n/** Registers span creators for xhr and fetch requests */\nexport function instrumentOutgoingRequests(client: Client, _options?: Partial<RequestInstrumentationOptions>): void {\n const {\n traceFetch,\n traceXHR,\n trackFetchStreamPerformance,\n shouldCreateSpanForRequest,\n enableHTTPTimings,\n tracePropagationTargets,\n onRequestSpanStart,\n onRequestSpanEnd,\n } = {\n ...defaultRequestInstrumentationOptions,\n ..._options,\n };\n\n const shouldCreateSpan =\n typeof shouldCreateSpanForRequest === 'function' ? shouldCreateSpanForRequest : (_: string) => true;\n\n const shouldAttachHeadersWithTargets = (url: string): boolean => shouldAttachHeaders(url, tracePropagationTargets);\n\n const spans: Record<string, Span> = {};\n\n const propagateTraceparent = (client as BrowserClient).getOptions().propagateTraceparent;\n\n if (traceFetch) {\n // Keeping track of http requests, whose body payloads resolved later than the initial resolved request\n // e.g. streaming using server sent events (SSE)\n client.addEventProcessor(event => {\n if (event.type === 'transaction' && event.spans) {\n event.spans.forEach(span => {\n if (span.op === 'http.client') {\n const updatedTimestamp = spanIdToEndTimestamp.get(span.span_id);\n if (updatedTimestamp) {\n span.timestamp = updatedTimestamp / 1000;\n spanIdToEndTimestamp.delete(span.span_id);\n }\n }\n });\n }\n return event;\n });\n\n if (trackFetchStreamPerformance) {\n addFetchEndInstrumentationHandler(handlerData => {\n if (handlerData.response) {\n const span = responseToSpanId.get(handlerData.response);\n if (span && handlerData.endTimestamp) {\n spanIdToEndTimestamp.set(span, handlerData.endTimestamp);\n }\n }\n });\n }\n\n addFetchInstrumentationHandler(handlerData => {\n const createdSpan = instrumentFetchRequest(handlerData, shouldCreateSpan, shouldAttachHeadersWithTargets, spans, {\n propagateTraceparent,\n onRequestSpanEnd,\n });\n\n if (handlerData.response && handlerData.fetchData.__span) {\n responseToSpanId.set(handlerData.response, handlerData.fetchData.__span);\n }\n\n // We cannot use `window.location` in the generic fetch instrumentation,\n // but we need it for reliable `server.address` attribute.\n // so we extend this in here\n if (createdSpan) {\n const fullUrl = getFullURL(handlerData.fetchData.url);\n const host = fullUrl ? parseUrl(fullUrl).host : undefined;\n createdSpan.setAttributes({\n 'http.url': fullUrl ? stripDataUrlContent(fullUrl) : undefined,\n 'server.address': host,\n });\n\n if (enableHTTPTimings) {\n addHTTPTimings(createdSpan);\n }\n\n onRequestSpanStart?.(createdSpan, { headers: handlerData.headers });\n }\n });\n }\n\n if (traceXHR) {\n addXhrInstrumentationHandler(handlerData => {\n const createdSpan = xhrCallback(\n handlerData,\n shouldCreateSpan,\n shouldAttachHeadersWithTargets,\n spans,\n propagateTraceparent,\n onRequestSpanEnd,\n );\n\n if (createdSpan) {\n if (enableHTTPTimings) {\n addHTTPTimings(createdSpan);\n }\n\n onRequestSpanStart?.(createdSpan, {\n headers: createHeadersSafely(handlerData.xhr.__sentry_xhr_v3__?.request_headers),\n });\n }\n });\n }\n}\n\n/**\n * Creates a temporary observer to listen to the next fetch/xhr resourcing timings,\n * so that when timings hit their per-browser limit they don't need to be removed.\n *\n * @param span A span that has yet to be finished, must contain `url` on data.\n */\nfunction addHTTPTimings(span: Span): void {\n const { url } = spanToJSON(span).data;\n\n if (!url || typeof url !== 'string') {\n return;\n }\n\n const cleanup = addPerformanceInstrumentationHandler('resource', ({ entries }) => {\n entries.forEach(entry => {\n if (isPerformanceResourceTiming(entry) && entry.name.endsWith(url)) {\n span.setAttributes(resourceTimingToSpanAttributes(entry));\n // In the next tick, clean this handler up\n // We have to wait here because otherwise this cleans itself up before it is fully done\n setTimeout(cleanup);\n }\n });\n });\n}\n\n/**\n * A function that determines whether to attach tracing headers to a request.\n * We only export this function for testing purposes.\n */\nexport function shouldAttachHeaders(\n targetUrl: string,\n tracePropagationTargets: (string | RegExp)[] | undefined,\n): boolean {\n // window.location.href not being defined is an edge case in the browser but we need to handle it.\n // Potentially dangerous situations where it may not be defined: Browser Extensions, Web Workers, patching of the location obj\n const href = getLocationHref();\n\n if (!href) {\n // If there is no window.location.origin, we default to only attaching tracing headers to relative requests, i.e. ones that start with `/`\n // BIG DISCLAIMER: Users can call URLs with a double slash (fetch(\"//example.com/api\")), this is a shorthand for \"send to the same protocol\",\n // so we need a to exclude those requests, because they might be cross origin.\n const isRelativeSameOriginRequest = !!targetUrl.match(/^\\/(?!\\/)/);\n if (!tracePropagationTargets) {\n return isRelativeSameOriginRequest;\n } else {\n return stringMatchesSomePattern(targetUrl, tracePropagationTargets);\n }\n } else {\n let resolvedUrl;\n let currentOrigin;\n\n // URL parsing may fail, we default to not attaching trace headers in that case.\n try {\n resolvedUrl = new URL(targetUrl, href);\n currentOrigin = new URL(href).origin;\n } catch {\n return false;\n }\n\n const isSameOriginRequest = resolvedUrl.origin === currentOrigin;\n if (!tracePropagationTargets) {\n return isSameOriginRequest;\n } else {\n return (\n stringMatchesSomePattern(resolvedUrl.toString(), tracePropagationTargets) ||\n (isSameOriginRequest && stringMatchesSomePattern(resolvedUrl.pathname, tracePropagationTargets))\n );\n }\n }\n}\n\n/**\n * Create and track xhr request spans\n *\n * @returns Span if a span was created, otherwise void.\n */\nfunction xhrCallback(\n handlerData: HandlerDataXhr,\n shouldCreateSpan: (url: string) => boolean,\n shouldAttachHeaders: (url: string) => boolean,\n spans: Record<string, Span>,\n propagateTraceparent?: boolean,\n onRequestSpanEnd?: RequestInstrumentationOptions['onRequestSpanEnd'],\n): Span | undefined {\n const xhr = handlerData.xhr;\n const sentryXhrData = xhr?.[SENTRY_XHR_DATA_KEY];\n\n if (!xhr || xhr.__sentry_own_request__ || !sentryXhrData) {\n return undefined;\n }\n\n const { url, method } = sentryXhrData;\n\n const shouldCreateSpanResult = hasSpansEnabled() && shouldCreateSpan(url);\n\n // Handle XHR completion - clean up spans from the record\n if (handlerData.endTimestamp) {\n const spanId = xhr.__sentry_xhr_span_id__;\n if (!spanId) return;\n\n const span = spans[spanId];\n\n if (span) {\n if (shouldCreateSpanResult && sentryXhrData.status_code !== undefined) {\n setHttpStatus(span, sentryXhrData.status_code);\n span.end();\n\n onRequestSpanEnd?.(span, {\n headers: createHeadersSafely(parseXhrResponseHeaders(xhr as XMLHttpRequest & SentryWrappedXMLHttpRequest)),\n error: handlerData.error,\n });\n }\n\n // eslint-disable-next-line @typescript-eslint/no-dynamic-delete\n delete spans[spanId];\n }\n\n return undefined;\n }\n\n const fullUrl = getFullURL(url);\n const parsedUrl = fullUrl ? parseUrl(fullUrl) : parseUrl(url);\n\n const urlForSpanName = stripDataUrlContent(stripUrlQueryAndFragment(url));\n\n const hasParent = !!getActiveSpan();\n\n const span =\n shouldCreateSpanResult && hasParent\n ? startInactiveSpan({\n name: `${method} ${urlForSpanName}`,\n attributes: {\n url: stripDataUrlContent(url),\n type: 'xhr',\n 'http.method': method,\n 'http.url': fullUrl ? stripDataUrlContent(fullUrl) : undefined,\n 'server.address': parsedUrl?.host,\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.browser',\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'http.client',\n ...(parsedUrl?.search && { 'http.query': parsedUrl?.search }),\n ...(parsedUrl?.hash && { 'http.fragment': parsedUrl?.hash }),\n },\n })\n : new SentryNonRecordingSpan();\n\n xhr.__sentry_xhr_span_id__ = span.spanContext().spanId;\n spans[xhr.__sentry_xhr_span_id__] = span;\n\n if (shouldAttachHeaders(url)) {\n addTracingHeadersToXhrRequest(\n xhr,\n // If performance is disabled (TWP) or there's no active root span (pageload/navigation/interaction),\n // we do not want to use the span as base for the trace headers,\n // which means that the headers will be generated from the scope and the sampling decision is deferred\n hasSpansEnabled() && hasParent ? span : undefined,\n propagateTraceparent,\n );\n }\n\n const client = getClient();\n if (client) {\n client.emit('beforeOutgoingRequestSpan', span, handlerData as XhrHint);\n }\n\n return span;\n}\n\nfunction addTracingHeadersToXhrRequest(\n xhr: SentryWrappedXMLHttpRequest,\n span?: Span,\n propagateTraceparent?: boolean,\n): void {\n const { 'sentry-trace': sentryTrace, baggage, traceparent } = getTraceData({ span, propagateTraceparent });\n\n if (sentryTrace) {\n setHeaderOnXhr(xhr, sentryTrace, baggage, traceparent);\n }\n}\n\nfunction setHeaderOnXhr(\n xhr: SentryWrappedXMLHttpRequest,\n sentryTraceHeader: string,\n sentryBaggageHeader: string | undefined,\n traceparentHeader: string | undefined,\n): void {\n const originalHeaders = xhr.__sentry_xhr_v3__?.request_headers;\n\n if (originalHeaders?.['sentry-trace'] || !xhr.setRequestHeader) {\n // bail if a sentry-trace header is already set\n return;\n }\n\n try {\n xhr.setRequestHeader('sentry-trace', sentryTraceHeader);\n\n if (traceparentHeader && !originalHeaders?.['traceparent']) {\n xhr.setRequestHeader('traceparent', traceparentHeader);\n }\n\n if (sentryBaggageHeader) {\n // only add our headers if\n // - no pre-existing baggage header exists\n // - or it is set and doesn't yet contain sentry values\n const originalBaggageHeader = originalHeaders?.['baggage'];\n if (!originalBaggageHeader || !baggageHeaderHasSentryValues(originalBaggageHeader)) {\n // From MDN: \"If this method is called several times with the same header, the values are merged into one single request header.\"\n // We can therefore simply set a baggage header without checking what was there before\n // https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/setRequestHeader\n xhr.setRequestHeader('baggage', sentryBaggageHeader);\n }\n }\n } catch {\n // Error: InvalidStateError: Failed to execute 'setRequestHeader' on 'XMLHttpRequest': The object's state must be OPENED.\n }\n}\n"],"names":["addFetchEndInstrumentationHandler","addFetchInstrumentationHandler","instrumentFetchRequest","getFullURL","parseUrl","stripDataUrlContent","addXhrInstrumentationHandler","createHeadersSafely","spanToJSON","addPerformanceInstrumentationHandler","isPerformanceResourceTiming","resourceTimingToSpanAttributes","getLocationHref","stringMatchesSomePattern","SENTRY_XHR_DATA_KEY","hasSpansEnabled","setHttpStatus","parseXhrResponseHeaders","stripUrlQueryAndFragment","getActiveSpan","startInactiveSpan","SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN","SEMANTIC_ATTRIBUTE_SENTRY_OP","SentryNonRecordingSpan","getClient","getTraceData","baggageHeaderHasSentryValues"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"request.js","sources":["../../../../../src/tracing/request.ts"],"sourcesContent":["/* eslint-disable max-lines */\nimport type {\n Client,\n HandlerDataXhr,\n RequestHookInfo,\n ResponseHookInfo,\n SentryWrappedXMLHttpRequest,\n Span,\n SpanTimeInput,\n} from '@sentry/core';\nimport {\n addFetchEndInstrumentationHandler,\n addFetchInstrumentationHandler,\n getActiveSpan,\n getClient,\n getLocationHref,\n getTraceData,\n hasSpansEnabled,\n hasSpanStreamingEnabled,\n instrumentFetchRequest,\n parseUrl,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n SentryNonRecordingSpan,\n setHttpStatus,\n spanToJSON,\n startInactiveSpan,\n stringMatchesSomePattern,\n stripDataUrlContent,\n stripUrlQueryAndFragment,\n timestampInSeconds,\n} from '@sentry/core';\nimport type { XhrHint } from '@sentry-internal/browser-utils';\nimport {\n addPerformanceInstrumentationHandler,\n addXhrInstrumentationHandler,\n parseXhrResponseHeaders,\n resourceTimingToSpanAttributes,\n SENTRY_XHR_DATA_KEY,\n} from '@sentry-internal/browser-utils';\nimport type { BrowserClient } from '../client';\nimport { baggageHeaderHasSentryValues, createHeadersSafely, getFullURL, isPerformanceResourceTiming } from './utils';\n\n/** Options for Request Instrumentation */\nexport interface RequestInstrumentationOptions {\n /**\n * List of strings and/or Regular Expressions used to determine which outgoing requests will have `sentry-trace` and `baggage`\n * headers attached.\n *\n * **Default:** If this option is not provided, tracing headers will be attached to all outgoing requests.\n * If you are using a browser SDK, by default, tracing headers will only be attached to outgoing requests to the same origin.\n *\n * **Disclaimer:** Carelessly setting this option in browser environments may result into CORS errors!\n * Only attach tracing headers to requests to the same origin, or to requests to services you can control CORS headers of.\n * Cross-origin requests, meaning requests to a different domain, for example a request to `https://api.example.com/` while you're on `https://example.com/`, take special care.\n * If you are attaching headers to cross-origin requests, make sure the backend handling the request returns a `\"Access-Control-Allow-Headers: sentry-trace, baggage\"` header to ensure your requests aren't blocked.\n *\n * If you provide a `tracePropagationTargets` array, the entries you provide will be matched against the entire URL of the outgoing request.\n * If you are using a browser SDK, the entries will also be matched against the pathname of the outgoing requests.\n * This is so you can have matchers for relative requests, for example, `/^\\/api/` if you want to trace requests to your `/api` routes on the same domain.\n *\n * If any of the two match any of the provided values, tracing headers will be attached to the outgoing request.\n * Both, the string values, and the RegExes you provide in the array will match if they partially match the URL or pathname.\n *\n * Examples:\n * - `tracePropagationTargets: [/^\\/api/]` and request to `https://same-origin.com/api/posts`:\n * - Tracing headers will be attached because the request is sent to the same origin and the regex matches the pathname \"/api/posts\".\n * - `tracePropagationTargets: [/^\\/api/]` and request to `https://different-origin.com/api/posts`:\n * - Tracing headers will not be attached because the pathname will only be compared when the request target lives on the same origin.\n * - `tracePropagationTargets: [/^\\/api/, 'https://external-api.com']` and request to `https://external-api.com/v1/data`:\n * - Tracing headers will be attached because the request URL matches the string `'https://external-api.com'`.\n */\n tracePropagationTargets?: Array<string | RegExp>;\n\n /**\n * Flag to disable patching all together for fetch requests.\n *\n * Default: true\n */\n traceFetch: boolean;\n\n /**\n * Flag to disable patching all together for xhr requests.\n *\n * Default: true\n */\n traceXHR: boolean;\n\n /**\n * Flag to disable tracking of long-lived streams, like server-sent events (SSE) via fetch.\n * Do not enable this in case you have live streams or very long running streams.\n *\n * Disabled by default since it can lead to issues with streams using the `cancel()` api\n * (https://github.com/getsentry/sentry-javascript/issues/13950)\n *\n * Default: false\n */\n trackFetchStreamPerformance: boolean;\n\n /**\n * If true, Sentry will capture http timings and add them to the corresponding http spans.\n *\n * Default: true\n */\n enableHTTPTimings: boolean;\n\n /**\n * This function will be called before creating a span for a request with the given url.\n * Return false if you don't want a span for the given url.\n *\n * Default: (url: string) => true\n */\n shouldCreateSpanForRequest?(this: void, url: string): boolean;\n\n /**\n * Is called when spans are started for outgoing requests.\n */\n onRequestSpanStart?(span: Span, requestInformation: RequestHookInfo): void;\n\n /**\n * Is called when spans end for outgoing requests, providing access to response headers.\n */\n onRequestSpanEnd?(span: Span, responseInformation: ResponseHookInfo): void;\n}\n\nconst responseToSpanId = new WeakMap<object, string>();\nconst spanIdToEndTimestamp = new Map<string, number>();\n\nexport const defaultRequestInstrumentationOptions: RequestInstrumentationOptions = {\n traceFetch: true,\n traceXHR: true,\n enableHTTPTimings: true,\n trackFetchStreamPerformance: false,\n};\n\n/** Registers span creators for xhr and fetch requests */\nexport function instrumentOutgoingRequests(client: Client, _options?: Partial<RequestInstrumentationOptions>): void {\n const {\n traceFetch,\n traceXHR,\n trackFetchStreamPerformance,\n shouldCreateSpanForRequest,\n enableHTTPTimings,\n tracePropagationTargets,\n onRequestSpanStart,\n onRequestSpanEnd,\n } = {\n ...defaultRequestInstrumentationOptions,\n ..._options,\n };\n\n const shouldCreateSpan =\n typeof shouldCreateSpanForRequest === 'function' ? shouldCreateSpanForRequest : (_: string) => true;\n\n const shouldAttachHeadersWithTargets = (url: string): boolean => shouldAttachHeaders(url, tracePropagationTargets);\n\n const spans: Record<string, Span> = {};\n\n const propagateTraceparent = (client as BrowserClient).getOptions().propagateTraceparent;\n\n if (traceFetch) {\n // Keeping track of http requests, whose body payloads resolved later than the initial resolved request\n // e.g. streaming using server sent events (SSE)\n client.addEventProcessor(event => {\n if (event.type === 'transaction' && event.spans) {\n event.spans.forEach(span => {\n if (span.op === 'http.client') {\n const updatedTimestamp = spanIdToEndTimestamp.get(span.span_id);\n if (updatedTimestamp) {\n span.timestamp = updatedTimestamp / 1000;\n spanIdToEndTimestamp.delete(span.span_id);\n }\n }\n });\n }\n return event;\n });\n\n if (trackFetchStreamPerformance) {\n addFetchEndInstrumentationHandler(handlerData => {\n if (handlerData.response) {\n const span = responseToSpanId.get(handlerData.response);\n if (span && handlerData.endTimestamp) {\n spanIdToEndTimestamp.set(span, handlerData.endTimestamp);\n }\n }\n });\n }\n\n addFetchInstrumentationHandler(handlerData => {\n const createdSpan = instrumentFetchRequest(handlerData, shouldCreateSpan, shouldAttachHeadersWithTargets, spans, {\n propagateTraceparent,\n onRequestSpanEnd,\n });\n\n if (handlerData.response && handlerData.fetchData.__span) {\n responseToSpanId.set(handlerData.response, handlerData.fetchData.__span);\n }\n\n // We cannot use `window.location` in the generic fetch instrumentation,\n // but we need it for reliable `server.address` attribute.\n // so we extend this in here\n if (createdSpan) {\n const fullUrl = getFullURL(handlerData.fetchData.url);\n const host = fullUrl ? parseUrl(fullUrl).host : undefined;\n createdSpan.setAttributes({\n 'http.url': fullUrl ? stripDataUrlContent(fullUrl) : undefined,\n 'server.address': host,\n });\n\n if (enableHTTPTimings) {\n addHTTPTimings(createdSpan, client);\n }\n\n onRequestSpanStart?.(createdSpan, { headers: handlerData.headers });\n }\n });\n }\n\n if (traceXHR) {\n addXhrInstrumentationHandler(handlerData => {\n const createdSpan = xhrCallback(\n handlerData,\n shouldCreateSpan,\n shouldAttachHeadersWithTargets,\n spans,\n propagateTraceparent,\n onRequestSpanEnd,\n );\n\n if (createdSpan) {\n if (enableHTTPTimings) {\n addHTTPTimings(createdSpan, client);\n }\n\n onRequestSpanStart?.(createdSpan, {\n headers: createHeadersSafely(handlerData.xhr.__sentry_xhr_v3__?.request_headers),\n });\n }\n });\n }\n}\n\n/**\n * The maximum time (ms) to wait for PerformanceResourceTiming data before ending the span.\n * Same approach is used by OTel's browser fetch instrumentation:\n * See {@link https://github.com/open-telemetry/opentelemetry-js/blob/30f94fe99339287b1e4d3c8bb90172c2523f06f4/experimental/packages/opentelemetry-instrumentation-fetch/src/fetch.ts#L352-L372}\n */\nconst HTTP_TIMING_WAIT_MS = 300;\n\n/**\n * Creates a temporary observer to listen to the next fetch/xhr resourcing timings,\n * so that when timings hit their per-browser limit they don't need to be removed.\n *\n * @param span A span that has yet to be finished, must contain `url` on data.\n */\nfunction addHTTPTimings(span: Span, client: Client): void {\n const { url } = spanToJSON(span).data;\n\n if (!url || typeof url !== 'string') {\n return;\n }\n\n // Clean up the performance observer and other resources\n // We have to wait here because otherwise this cleans itself up before it is fully done.\n // Default (non-streaming): just deregister the observer.\n let onEntryFound = (): void => void setTimeout(unsubscribePerformanceObsever);\n\n // For streamed spans, we have to artificially delay the ending of the span until we\n // either receive the timing data, or HTTP_TIMING_WAIT_MS elapses.\n if (hasSpanStreamingEnabled(client)) {\n const originalEnd = span.end.bind(span);\n\n span.end = (endTimestamp?: SpanTimeInput) => {\n const capturedEndTimestamp = endTimestamp ?? timestampInSeconds();\n let isEnded = false;\n\n const endSpanAndCleanup = (): void => {\n if (isEnded) {\n return;\n }\n isEnded = true;\n setTimeout(unsubscribePerformanceObsever);\n originalEnd(capturedEndTimestamp);\n clearTimeout(fallbackTimeout);\n };\n\n onEntryFound = endSpanAndCleanup;\n\n // Fallback: always end the span after HTTP_TIMING_WAIT_MS even if no\n // PerformanceResourceTiming entry arrives (e.g. cross-origin without\n // Timing-Allow-Origin, or the browser didn't fire the observer in time).\n const fallbackTimeout = setTimeout(endSpanAndCleanup, HTTP_TIMING_WAIT_MS);\n };\n }\n\n const unsubscribePerformanceObsever = addPerformanceInstrumentationHandler('resource', ({ entries }) => {\n entries.forEach(entry => {\n if (isPerformanceResourceTiming(entry) && entry.name.endsWith(url)) {\n span.setAttributes(resourceTimingToSpanAttributes(entry));\n onEntryFound();\n }\n });\n });\n}\n\n/**\n * A function that determines whether to attach tracing headers to a request.\n * We only export this function for testing purposes.\n */\nexport function shouldAttachHeaders(\n targetUrl: string,\n tracePropagationTargets: (string | RegExp)[] | undefined,\n): boolean {\n // window.location.href not being defined is an edge case in the browser but we need to handle it.\n // Potentially dangerous situations where it may not be defined: Browser Extensions, Web Workers, patching of the location obj\n const href = getLocationHref();\n\n if (!href) {\n // If there is no window.location.origin, we default to only attaching tracing headers to relative requests, i.e. ones that start with `/`\n // BIG DISCLAIMER: Users can call URLs with a double slash (fetch(\"//example.com/api\")), this is a shorthand for \"send to the same protocol\",\n // so we need a to exclude those requests, because they might be cross origin.\n const isRelativeSameOriginRequest = !!targetUrl.match(/^\\/(?!\\/)/);\n if (!tracePropagationTargets) {\n return isRelativeSameOriginRequest;\n } else {\n return stringMatchesSomePattern(targetUrl, tracePropagationTargets);\n }\n } else {\n let resolvedUrl;\n let currentOrigin;\n\n // URL parsing may fail, we default to not attaching trace headers in that case.\n try {\n resolvedUrl = new URL(targetUrl, href);\n currentOrigin = new URL(href).origin;\n } catch {\n return false;\n }\n\n const isSameOriginRequest = resolvedUrl.origin === currentOrigin;\n if (!tracePropagationTargets) {\n return isSameOriginRequest;\n } else {\n return (\n stringMatchesSomePattern(resolvedUrl.toString(), tracePropagationTargets) ||\n (isSameOriginRequest && stringMatchesSomePattern(resolvedUrl.pathname, tracePropagationTargets))\n );\n }\n }\n}\n\n/**\n * Create and track xhr request spans\n *\n * @returns Span if a span was created, otherwise void.\n */\nfunction xhrCallback(\n handlerData: HandlerDataXhr,\n shouldCreateSpan: (url: string) => boolean,\n shouldAttachHeaders: (url: string) => boolean,\n spans: Record<string, Span>,\n propagateTraceparent?: boolean,\n onRequestSpanEnd?: RequestInstrumentationOptions['onRequestSpanEnd'],\n): Span | undefined {\n const xhr = handlerData.xhr;\n const sentryXhrData = xhr?.[SENTRY_XHR_DATA_KEY];\n\n if (!xhr || xhr.__sentry_own_request__ || !sentryXhrData) {\n return undefined;\n }\n\n const { url, method } = sentryXhrData;\n\n const shouldCreateSpanResult = hasSpansEnabled() && shouldCreateSpan(url);\n\n // Handle XHR completion - clean up spans from the record\n if (handlerData.endTimestamp) {\n const spanId = xhr.__sentry_xhr_span_id__;\n if (!spanId) return;\n\n const span = spans[spanId];\n\n if (span) {\n if (shouldCreateSpanResult && sentryXhrData.status_code !== undefined) {\n setHttpStatus(span, sentryXhrData.status_code);\n span.end();\n\n onRequestSpanEnd?.(span, {\n headers: createHeadersSafely(parseXhrResponseHeaders(xhr as XMLHttpRequest & SentryWrappedXMLHttpRequest)),\n error: handlerData.error,\n });\n }\n\n // eslint-disable-next-line @typescript-eslint/no-dynamic-delete\n delete spans[spanId];\n }\n\n return undefined;\n }\n\n const fullUrl = getFullURL(url);\n const parsedUrl = fullUrl ? parseUrl(fullUrl) : parseUrl(url);\n\n const urlForSpanName = stripDataUrlContent(stripUrlQueryAndFragment(url));\n\n const hasParent = !!getActiveSpan();\n\n const span =\n shouldCreateSpanResult && hasParent\n ? startInactiveSpan({\n name: `${method} ${urlForSpanName}`,\n attributes: {\n url: stripDataUrlContent(url),\n type: 'xhr',\n 'http.method': method,\n 'http.url': fullUrl ? stripDataUrlContent(fullUrl) : undefined,\n 'server.address': parsedUrl?.host,\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.browser',\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'http.client',\n ...(parsedUrl?.search && { 'http.query': parsedUrl?.search }),\n ...(parsedUrl?.hash && { 'http.fragment': parsedUrl?.hash }),\n },\n })\n : new SentryNonRecordingSpan();\n\n xhr.__sentry_xhr_span_id__ = span.spanContext().spanId;\n spans[xhr.__sentry_xhr_span_id__] = span;\n\n if (shouldAttachHeaders(url)) {\n addTracingHeadersToXhrRequest(\n xhr,\n // If performance is disabled (TWP) or there's no active root span (pageload/navigation/interaction),\n // we do not want to use the span as base for the trace headers,\n // which means that the headers will be generated from the scope and the sampling decision is deferred\n hasSpansEnabled() && hasParent ? span : undefined,\n propagateTraceparent,\n );\n }\n\n const client = getClient();\n if (client) {\n client.emit('beforeOutgoingRequestSpan', span, handlerData as XhrHint);\n }\n\n return span;\n}\n\nfunction addTracingHeadersToXhrRequest(\n xhr: SentryWrappedXMLHttpRequest,\n span?: Span,\n propagateTraceparent?: boolean,\n): void {\n const { 'sentry-trace': sentryTrace, baggage, traceparent } = getTraceData({ span, propagateTraceparent });\n\n if (sentryTrace) {\n setHeaderOnXhr(xhr, sentryTrace, baggage, traceparent);\n }\n}\n\nfunction setHeaderOnXhr(\n xhr: SentryWrappedXMLHttpRequest,\n sentryTraceHeader: string,\n sentryBaggageHeader: string | undefined,\n traceparentHeader: string | undefined,\n): void {\n const originalHeaders = xhr.__sentry_xhr_v3__?.request_headers;\n\n if (originalHeaders?.['sentry-trace'] || !xhr.setRequestHeader) {\n // bail if a sentry-trace header is already set\n return;\n }\n\n try {\n xhr.setRequestHeader('sentry-trace', sentryTraceHeader);\n\n if (traceparentHeader && !originalHeaders?.['traceparent']) {\n xhr.setRequestHeader('traceparent', traceparentHeader);\n }\n\n if (sentryBaggageHeader) {\n // only add our headers if\n // - no pre-existing baggage header exists\n // - or it is set and doesn't yet contain sentry values\n const originalBaggageHeader = originalHeaders?.['baggage'];\n if (!originalBaggageHeader || !baggageHeaderHasSentryValues(originalBaggageHeader)) {\n // From MDN: \"If this method is called several times with the same header, the values are merged into one single request header.\"\n // We can therefore simply set a baggage header without checking what was there before\n // https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/setRequestHeader\n xhr.setRequestHeader('baggage', sentryBaggageHeader);\n }\n }\n } catch {\n // Error: InvalidStateError: Failed to execute 'setRequestHeader' on 'XMLHttpRequest': The object's state must be OPENED.\n }\n}\n"],"names":["addFetchEndInstrumentationHandler","addFetchInstrumentationHandler","instrumentFetchRequest","getFullURL","parseUrl","stripDataUrlContent","addXhrInstrumentationHandler","createHeadersSafely","spanToJSON","hasSpanStreamingEnabled","timestampInSeconds","addPerformanceInstrumentationHandler","isPerformanceResourceTiming","resourceTimingToSpanAttributes","getLocationHref","stringMatchesSomePattern","SENTRY_XHR_DATA_KEY","hasSpansEnabled","setHttpStatus","parseXhrResponseHeaders","stripUrlQueryAndFragment","getActiveSpan","startInactiveSpan","SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN","SEMANTIC_ATTRIBUTE_SENTRY_OP","SentryNonRecordingSpan","getClient","getTraceData","baggageHeaderHasSentryValues"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lazyLoadIntegration.js","sources":["../../../../../src/utils/lazyLoadIntegration.ts"],"sourcesContent":["import type { IntegrationFn } from '@sentry/core';\nimport { getClient, SDK_VERSION } from '@sentry/core';\nimport type { BrowserClient } from '../client';\nimport { WINDOW } from '../helpers';\n\n// Single source of truth: as const array provides both the runtime list and the type.\n// Bundle file names are derived: strip 'Integration' suffix, lowercase.\n// Exceptions (hyphenated bundle names) are listed in HYPHENATED_BUNDLES.\nconst LAZY_LOADABLE_NAMES = [\n 'replayIntegration',\n 'replayCanvasIntegration',\n 'feedbackIntegration',\n 'feedbackModalIntegration',\n 'feedbackScreenshotIntegration',\n 'captureConsoleIntegration',\n 'contextLinesIntegration',\n 'linkedErrorsIntegration',\n 'dedupeIntegration',\n 'extraErrorDataIntegration',\n 'graphqlClientIntegration',\n 'httpClientIntegration',\n 'reportingObserverIntegration',\n 'rewriteFramesIntegration',\n 'browserProfilingIntegration',\n 'moduleMetadataIntegration',\n 'instrumentAnthropicAiClient',\n 'instrumentOpenAiClient',\n 'instrumentGoogleGenAIClient',\n 'instrumentLangGraph',\n 'createLangChainCallbackHandler',\n] as const;\n\ntype ElementOf<T extends readonly unknown[]> = T[number];\ntype LazyLoadableIntegrationName = ElementOf<typeof LAZY_LOADABLE_NAMES>;\n\nconst HYPHENATED_BUNDLES: Partial<Record<LazyLoadableIntegrationName, string>> = {\n replayCanvasIntegration: 'replay-canvas',\n feedbackModalIntegration: 'feedback-modal',\n feedbackScreenshotIntegration: 'feedback-screenshot',\n};\n\nfunction getBundleName(name: string): string {\n return HYPHENATED_BUNDLES[name as LazyLoadableIntegrationName] || name.replace('Integration', '').toLowerCase();\n}\n\nconst WindowWithMaybeIntegration = WINDOW as {\n Sentry?: Partial<Record<LazyLoadableIntegrationName, IntegrationFn>>;\n};\n\n/**\n * Lazy load an integration from the CDN.\n * Rejects if the integration cannot be loaded.\n */\nexport async function lazyLoadIntegration(\n name: LazyLoadableIntegrationName,\n scriptNonce?: string,\n): Promise<IntegrationFn> {\n const bundle = LAZY_LOADABLE_NAMES.includes(name) ? getBundleName(name) : undefined;\n\n // `window.Sentry` is only set when using a CDN bundle, but this method can also be used via the NPM package\n const sentryOnWindow = (WindowWithMaybeIntegration.Sentry = WindowWithMaybeIntegration.Sentry || {});\n\n if (!bundle) {\n throw new Error(`Cannot lazy load integration: ${name}`);\n }\n\n // Bail if the integration already exists\n const existing = sentryOnWindow[name];\n // The `feedbackIntegration` is loaded by default in the CDN bundles,\n // so we need to differentiate between the real integration and the shim.\n // if only the shim exists, we still want to lazy load the real integration.\n if (typeof existing === 'function' && !('_isShim' in existing)) {\n return existing;\n }\n\n const url = getScriptURL(bundle);\n const script = WINDOW.document.createElement('script');\n script.src = url;\n script.crossOrigin = 'anonymous';\n script.referrerPolicy = 'strict-origin';\n\n if (scriptNonce) {\n script.setAttribute('nonce', scriptNonce);\n }\n\n const waitForLoad = new Promise<void>((resolve, reject) => {\n script.addEventListener('load', () => resolve());\n script.addEventListener('error', reject);\n });\n\n const currentScript = WINDOW.document.currentScript;\n const parent = WINDOW.document.body || WINDOW.document.head || currentScript?.parentElement;\n\n if (parent) {\n parent.appendChild(script);\n } else {\n throw new Error(`Could not find parent element to insert lazy-loaded ${name} script`);\n }\n\n try {\n await waitForLoad;\n } catch {\n throw new Error(`Error when loading integration: ${name}`);\n }\n\n const integrationFn = sentryOnWindow[name];\n\n if (typeof integrationFn !== 'function') {\n throw new Error(`Could not load integration: ${name}`);\n }\n\n return integrationFn;\n}\n\nfunction getScriptURL(bundle: string): string {\n const client = getClient<BrowserClient>();\n const baseURL = client?.getOptions()?.cdnBaseUrl || 'https://browser.sentry-cdn.com';\n\n return new URL(`/${SDK_VERSION}/${bundle}.min.js`, baseURL).toString();\n}\n"],"names":["WINDOW","getClient","SDK_VERSION"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"lazyLoadIntegration.js","sources":["../../../../../src/utils/lazyLoadIntegration.ts"],"sourcesContent":["import type { IntegrationFn } from '@sentry/core';\nimport { getClient, SDK_VERSION } from '@sentry/core';\nimport type { BrowserClient } from '../client';\nimport { WINDOW } from '../helpers';\n\n// Single source of truth: as const array provides both the runtime list and the type.\n// Bundle file names are derived: strip 'Integration' suffix, lowercase.\n// Exceptions (hyphenated bundle names) are listed in HYPHENATED_BUNDLES.\nconst LAZY_LOADABLE_NAMES = [\n 'replayIntegration',\n 'replayCanvasIntegration',\n 'feedbackIntegration',\n 'feedbackModalIntegration',\n 'feedbackScreenshotIntegration',\n 'captureConsoleIntegration',\n 'contextLinesIntegration',\n 'linkedErrorsIntegration',\n 'dedupeIntegration',\n 'extraErrorDataIntegration',\n 'graphqlClientIntegration',\n 'httpClientIntegration',\n 'reportingObserverIntegration',\n 'rewriteFramesIntegration',\n 'browserProfilingIntegration',\n 'moduleMetadataIntegration',\n 'instrumentAnthropicAiClient',\n 'instrumentOpenAiClient',\n 'instrumentGoogleGenAIClient',\n 'instrumentLangGraph',\n 'createLangChainCallbackHandler',\n 'instrumentLangChainEmbeddings',\n] as const;\n\ntype ElementOf<T extends readonly unknown[]> = T[number];\ntype LazyLoadableIntegrationName = ElementOf<typeof LAZY_LOADABLE_NAMES>;\n\nconst HYPHENATED_BUNDLES: Partial<Record<LazyLoadableIntegrationName, string>> = {\n replayCanvasIntegration: 'replay-canvas',\n feedbackModalIntegration: 'feedback-modal',\n feedbackScreenshotIntegration: 'feedback-screenshot',\n};\n\nfunction getBundleName(name: string): string {\n return HYPHENATED_BUNDLES[name as LazyLoadableIntegrationName] || name.replace('Integration', '').toLowerCase();\n}\n\nconst WindowWithMaybeIntegration = WINDOW as {\n Sentry?: Partial<Record<LazyLoadableIntegrationName, IntegrationFn>>;\n};\n\n/**\n * Lazy load an integration from the CDN.\n * Rejects if the integration cannot be loaded.\n */\nexport async function lazyLoadIntegration(\n name: LazyLoadableIntegrationName,\n scriptNonce?: string,\n): Promise<IntegrationFn> {\n const bundle = LAZY_LOADABLE_NAMES.includes(name) ? getBundleName(name) : undefined;\n\n // `window.Sentry` is only set when using a CDN bundle, but this method can also be used via the NPM package\n const sentryOnWindow = (WindowWithMaybeIntegration.Sentry = WindowWithMaybeIntegration.Sentry || {});\n\n if (!bundle) {\n throw new Error(`Cannot lazy load integration: ${name}`);\n }\n\n // Bail if the integration already exists\n const existing = sentryOnWindow[name];\n // The `feedbackIntegration` is loaded by default in the CDN bundles,\n // so we need to differentiate between the real integration and the shim.\n // if only the shim exists, we still want to lazy load the real integration.\n if (typeof existing === 'function' && !('_isShim' in existing)) {\n return existing;\n }\n\n const url = getScriptURL(bundle);\n const script = WINDOW.document.createElement('script');\n script.src = url;\n script.crossOrigin = 'anonymous';\n script.referrerPolicy = 'strict-origin';\n\n if (scriptNonce) {\n script.setAttribute('nonce', scriptNonce);\n }\n\n const waitForLoad = new Promise<void>((resolve, reject) => {\n script.addEventListener('load', () => resolve());\n script.addEventListener('error', reject);\n });\n\n const currentScript = WINDOW.document.currentScript;\n const parent = WINDOW.document.body || WINDOW.document.head || currentScript?.parentElement;\n\n if (parent) {\n parent.appendChild(script);\n } else {\n throw new Error(`Could not find parent element to insert lazy-loaded ${name} script`);\n }\n\n try {\n await waitForLoad;\n } catch {\n throw new Error(`Error when loading integration: ${name}`);\n }\n\n const integrationFn = sentryOnWindow[name];\n\n if (typeof integrationFn !== 'function') {\n throw new Error(`Could not load integration: ${name}`);\n }\n\n return integrationFn;\n}\n\nfunction getScriptURL(bundle: string): string {\n const client = getClient<BrowserClient>();\n const baseURL = client?.getOptions()?.cdnBaseUrl || 'https://browser.sentry-cdn.com';\n\n return new URL(`/${SDK_VERSION}/${bundle}.min.js`, baseURL).toString();\n}\n"],"names":["WINDOW","getClient","SDK_VERSION"],"mappings":"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"}
|
|
@@ -23,6 +23,7 @@ const reportingobserver = require('./integrations/reportingobserver.js');
|
|
|
23
23
|
const httpclient = require('./integrations/httpclient.js');
|
|
24
24
|
const contextlines = require('./integrations/contextlines.js');
|
|
25
25
|
const graphqlClient = require('./integrations/graphqlClient.js');
|
|
26
|
+
const viewHierarchy = require('./integrations/view-hierarchy.js');
|
|
26
27
|
const replay = require('@sentry-internal/replay');
|
|
27
28
|
const replayCanvas = require('@sentry-internal/replay-canvas');
|
|
28
29
|
const feedback = require('@sentry-internal/feedback');
|
|
@@ -31,6 +32,7 @@ const browserTracingIntegration = require('./tracing/browserTracingIntegration.j
|
|
|
31
32
|
const browserUtils = require('@sentry-internal/browser-utils');
|
|
32
33
|
const reportPageLoaded = require('./tracing/reportPageLoaded.js');
|
|
33
34
|
const setActiveSpan = require('./tracing/setActiveSpan.js');
|
|
35
|
+
const spanstreaming = require('./integrations/spanstreaming.js');
|
|
34
36
|
const offline = require('./transports/offline.js');
|
|
35
37
|
const integration$1 = require('./profiling/integration.js');
|
|
36
38
|
const spotlight = require('./integrations/spotlight.js');
|
|
@@ -89,6 +91,7 @@ exports.getTraceData = core.getTraceData;
|
|
|
89
91
|
exports.inboundFiltersIntegration = core.inboundFiltersIntegration;
|
|
90
92
|
exports.instrumentAnthropicAiClient = core.instrumentAnthropicAiClient;
|
|
91
93
|
exports.instrumentGoogleGenAIClient = core.instrumentGoogleGenAIClient;
|
|
94
|
+
exports.instrumentLangChainEmbeddings = core.instrumentLangChainEmbeddings;
|
|
92
95
|
exports.instrumentLangGraph = core.instrumentLangGraph;
|
|
93
96
|
exports.instrumentOpenAiClient = core.instrumentOpenAiClient;
|
|
94
97
|
exports.instrumentSupabaseClient = core.instrumentSupabaseClient;
|
|
@@ -127,6 +130,7 @@ exports.updateSpanName = core.updateSpanName;
|
|
|
127
130
|
exports.withActiveSpan = core.withActiveSpan;
|
|
128
131
|
exports.withIsolationScope = core.withIsolationScope;
|
|
129
132
|
exports.withScope = core.withScope;
|
|
133
|
+
exports.withStreamedSpan = core.withStreamedSpan;
|
|
130
134
|
exports.zodErrorsIntegration = core.zodErrorsIntegration;
|
|
131
135
|
exports.WINDOW = helpers.WINDOW;
|
|
132
136
|
exports.BrowserClient = client.BrowserClient;
|
|
@@ -159,6 +163,7 @@ exports.reportingObserverIntegration = reportingobserver.reportingObserverIntegr
|
|
|
159
163
|
exports.httpClientIntegration = httpclient.httpClientIntegration;
|
|
160
164
|
exports.contextLinesIntegration = contextlines.contextLinesIntegration;
|
|
161
165
|
exports.graphqlClientIntegration = graphqlClient.graphqlClientIntegration;
|
|
166
|
+
exports.viewHierarchyIntegration = viewHierarchy.viewHierarchyIntegration;
|
|
162
167
|
exports.getReplay = replay.getReplay;
|
|
163
168
|
exports.replayIntegration = replay.replayIntegration;
|
|
164
169
|
exports.replayCanvasIntegration = replayCanvas.replayCanvasIntegration;
|
|
@@ -167,11 +172,13 @@ exports.sendFeedback = feedback.sendFeedback;
|
|
|
167
172
|
exports.defaultRequestInstrumentationOptions = request.defaultRequestInstrumentationOptions;
|
|
168
173
|
exports.instrumentOutgoingRequests = request.instrumentOutgoingRequests;
|
|
169
174
|
exports.browserTracingIntegration = browserTracingIntegration.browserTracingIntegration;
|
|
175
|
+
exports.isBotUserAgent = browserTracingIntegration.isBotUserAgent;
|
|
170
176
|
exports.startBrowserTracingNavigationSpan = browserTracingIntegration.startBrowserTracingNavigationSpan;
|
|
171
177
|
exports.startBrowserTracingPageLoadSpan = browserTracingIntegration.startBrowserTracingPageLoadSpan;
|
|
172
178
|
exports.elementTimingIntegration = browserUtils.elementTimingIntegration;
|
|
173
179
|
exports.reportPageLoaded = reportPageLoaded.reportPageLoaded;
|
|
174
180
|
exports.setActiveSpanInBrowser = setActiveSpan.setActiveSpanInBrowser;
|
|
181
|
+
exports.spanStreamingIntegration = spanstreaming.spanStreamingIntegration;
|
|
175
182
|
exports.makeBrowserOfflineTransport = offline.makeBrowserOfflineTransport;
|
|
176
183
|
exports.browserProfilingIntegration = integration$1.browserProfilingIntegration;
|
|
177
184
|
exports.spotlightBrowserIntegration = spotlight.spotlightBrowserIntegration;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
|
|
3
|
+
const core = require('@sentry/core');
|
|
4
|
+
const debugBuild = require('../debug-build.js');
|
|
5
|
+
|
|
6
|
+
const spanStreamingIntegration = core.defineIntegration(() => {
|
|
7
|
+
return {
|
|
8
|
+
name: 'SpanStreaming',
|
|
9
|
+
|
|
10
|
+
beforeSetup(client) {
|
|
11
|
+
// If users only set spanStreamingIntegration, without traceLifecycle, we set it to "stream" for them.
|
|
12
|
+
// This avoids the classic double-opt-in problem we'd otherwise have in the browser SDK.
|
|
13
|
+
const clientOptions = client.getOptions();
|
|
14
|
+
if (!clientOptions.traceLifecycle) {
|
|
15
|
+
debugBuild.DEBUG_BUILD && core.debug.log('[SpanStreaming] setting `traceLifecycle` to "stream"');
|
|
16
|
+
clientOptions.traceLifecycle = 'stream';
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
|
|
20
|
+
setup(client) {
|
|
21
|
+
const initialMessage = 'SpanStreaming integration requires';
|
|
22
|
+
const fallbackMsg = 'Falling back to static trace lifecycle.';
|
|
23
|
+
const clientOptions = client.getOptions();
|
|
24
|
+
|
|
25
|
+
if (!core.hasSpanStreamingEnabled(client)) {
|
|
26
|
+
clientOptions.traceLifecycle = 'static';
|
|
27
|
+
debugBuild.DEBUG_BUILD && core.debug.warn(`${initialMessage} \`traceLifecycle\` to be set to "stream"! ${fallbackMsg}`);
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const beforeSendSpan = clientOptions.beforeSendSpan;
|
|
32
|
+
// If users misconfigure their SDK by opting into span streaming but
|
|
33
|
+
// using an incompatible beforeSendSpan callback, we fall back to the static trace lifecycle.
|
|
34
|
+
if (beforeSendSpan && !core.isStreamedBeforeSendSpanCallback(beforeSendSpan)) {
|
|
35
|
+
clientOptions.traceLifecycle = 'static';
|
|
36
|
+
debugBuild.DEBUG_BUILD &&
|
|
37
|
+
core.debug.warn(`${initialMessage} a beforeSendSpan callback using \`withStreamedSpan\`! ${fallbackMsg}`);
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const buffer = new core.SpanBuffer(client);
|
|
42
|
+
|
|
43
|
+
client.on('afterSpanEnd', span => {
|
|
44
|
+
// Negatively sampled spans must not be captured.
|
|
45
|
+
// This happens because OTel and we create non-recording spans for negatively sampled spans
|
|
46
|
+
// that go through the same life cycle as recording spans.
|
|
47
|
+
if (!core.spanIsSampled(span)) {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
buffer.add(core.captureSpan(span, client));
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
// In addition to capturing the span, we also flush the trace when the segment
|
|
54
|
+
// span ends to ensure things are sent timely. We never know when the browser
|
|
55
|
+
// is closed, users navigate away, etc.
|
|
56
|
+
client.on('afterSegmentSpanEnd', segmentSpan => {
|
|
57
|
+
const traceId = segmentSpan.spanContext().traceId;
|
|
58
|
+
setTimeout(() => {
|
|
59
|
+
buffer.flush(traceId);
|
|
60
|
+
}, 500);
|
|
61
|
+
});
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
}) ;
|
|
65
|
+
|
|
66
|
+
exports.spanStreamingIntegration = spanStreamingIntegration;
|
|
67
|
+
//# sourceMappingURL=spanstreaming.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spanstreaming.js","sources":["../../../../../src/integrations/spanstreaming.ts"],"sourcesContent":["import type { IntegrationFn } from '@sentry/core';\nimport {\n captureSpan,\n debug,\n defineIntegration,\n hasSpanStreamingEnabled,\n isStreamedBeforeSendSpanCallback,\n SpanBuffer,\n spanIsSampled,\n} from '@sentry/core';\nimport { DEBUG_BUILD } from '../debug-build';\n\nexport const spanStreamingIntegration = defineIntegration(() => {\n return {\n name: 'SpanStreaming',\n\n beforeSetup(client) {\n // If users only set spanStreamingIntegration, without traceLifecycle, we set it to \"stream\" for them.\n // This avoids the classic double-opt-in problem we'd otherwise have in the browser SDK.\n const clientOptions = client.getOptions();\n if (!clientOptions.traceLifecycle) {\n DEBUG_BUILD && debug.log('[SpanStreaming] setting `traceLifecycle` to \"stream\"');\n clientOptions.traceLifecycle = 'stream';\n }\n },\n\n setup(client) {\n const initialMessage = 'SpanStreaming integration requires';\n const fallbackMsg = 'Falling back to static trace lifecycle.';\n const clientOptions = client.getOptions();\n\n if (!hasSpanStreamingEnabled(client)) {\n clientOptions.traceLifecycle = 'static';\n DEBUG_BUILD && debug.warn(`${initialMessage} \\`traceLifecycle\\` to be set to \"stream\"! ${fallbackMsg}`);\n return;\n }\n\n const beforeSendSpan = clientOptions.beforeSendSpan;\n // If users misconfigure their SDK by opting into span streaming but\n // using an incompatible beforeSendSpan callback, we fall back to the static trace lifecycle.\n if (beforeSendSpan && !isStreamedBeforeSendSpanCallback(beforeSendSpan)) {\n clientOptions.traceLifecycle = 'static';\n DEBUG_BUILD &&\n debug.warn(`${initialMessage} a beforeSendSpan callback using \\`withStreamedSpan\\`! ${fallbackMsg}`);\n return;\n }\n\n const buffer = new SpanBuffer(client);\n\n client.on('afterSpanEnd', span => {\n // Negatively sampled spans must not be captured.\n // This happens because OTel and we create non-recording spans for negatively sampled spans\n // that go through the same life cycle as recording spans.\n if (!spanIsSampled(span)) {\n return;\n }\n buffer.add(captureSpan(span, client));\n });\n\n // In addition to capturing the span, we also flush the trace when the segment\n // span ends to ensure things are sent timely. We never know when the browser\n // is closed, users navigate away, etc.\n client.on('afterSegmentSpanEnd', segmentSpan => {\n const traceId = segmentSpan.spanContext().traceId;\n setTimeout(() => {\n buffer.flush(traceId);\n }, 500);\n });\n },\n };\n}) satisfies IntegrationFn;\n"],"names":["defineIntegration","DEBUG_BUILD","debug","hasSpanStreamingEnabled","isStreamedBeforeSendSpanCallback","SpanBuffer","spanIsSampled","captureSpan"],"mappings":";;;;;MAYa,wBAAA,GAA2BA,sBAAiB,CAAC,MAAM;AAChE,EAAE,OAAO;AACT,IAAI,IAAI,EAAE,eAAe;;AAEzB,IAAI,WAAW,CAAC,MAAM,EAAE;AACxB;AACA;AACA,MAAM,MAAM,aAAA,GAAgB,MAAM,CAAC,UAAU,EAAE;AAC/C,MAAM,IAAI,CAAC,aAAa,CAAC,cAAc,EAAE;AACzC,QAAQC,0BAAeC,UAAK,CAAC,GAAG,CAAC,sDAAsD,CAAC;AACxF,QAAQ,aAAa,CAAC,cAAA,GAAiB,QAAQ;AAC/C,MAAM;AACN,IAAI,CAAC;;AAEL,IAAI,KAAK,CAAC,MAAM,EAAE;AAClB,MAAM,MAAM,cAAA,GAAiB,oCAAoC;AACjE,MAAM,MAAM,WAAA,GAAc,yCAAyC;AACnE,MAAM,MAAM,aAAA,GAAgB,MAAM,CAAC,UAAU,EAAE;;AAE/C,MAAM,IAAI,CAACC,4BAAuB,CAAC,MAAM,CAAC,EAAE;AAC5C,QAAQ,aAAa,CAAC,cAAA,GAAiB,QAAQ;AAC/C,QAAQF,0BAAeC,UAAK,CAAC,IAAI,CAAC,CAAC,EAAA,cAAA,CAAA,2CAAA,EAAA,WAAA,CAAA,CAAA,CAAA;AACA,QAAA;AACA,MAAA;;AAEA,MAAA,MAAA,cAAA,GAAA,aAAA,CAAA,cAAA;AACA;AACA;AACA,MAAA,IAAA,cAAA,IAAA,CAAAE,qCAAA,CAAA,cAAA,CAAA,EAAA;AACA,QAAA,aAAA,CAAA,cAAA,GAAA,QAAA;AACA,QAAAH,sBAAA;AACA,UAAAC,UAAA,CAAA,IAAA,CAAA,CAAA,EAAA,cAAA,CAAA,uDAAA,EAAA,WAAA,CAAA,CAAA,CAAA;AACA,QAAA;AACA,MAAA;;AAEA,MAAA,MAAA,MAAA,GAAA,IAAAG,eAAA,CAAA,MAAA,CAAA;;AAEA,MAAA,MAAA,CAAA,EAAA,CAAA,cAAA,EAAA,IAAA,IAAA;AACA;AACA;AACA;AACA,QAAA,IAAA,CAAAC,kBAAA,CAAA,IAAA,CAAA,EAAA;AACA,UAAA;AACA,QAAA;AACA,QAAA,MAAA,CAAA,GAAA,CAAAC,gBAAA,CAAA,IAAA,EAAA,MAAA,CAAA,CAAA;AACA,MAAA,CAAA,CAAA;;AAEA;AACA;AACA;AACA,MAAA,MAAA,CAAA,EAAA,CAAA,qBAAA,EAAA,WAAA,IAAA;AACA,QAAA,MAAA,OAAA,GAAA,WAAA,CAAA,WAAA,EAAA,CAAA,OAAA;AACA,QAAA,UAAA,CAAA,MAAA;AACA,UAAA,MAAA,CAAA,KAAA,CAAA,OAAA,CAAA;AACA,QAAA,CAAA,EAAA,GAAA,CAAA;AACA,MAAA,CAAA,CAAA;AACA,IAAA,CAAA;AACA,GAAA;AACA,CAAA,CAAA;;;;"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
|
|
3
|
+
const core = require('@sentry/core');
|
|
4
|
+
const helpers = require('../helpers.js');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* An integration to include a view hierarchy attachment which contains the DOM.
|
|
8
|
+
*/
|
|
9
|
+
const viewHierarchyIntegration = core.defineIntegration((options = {}) => {
|
|
10
|
+
const skipHtmlTags = ['script'];
|
|
11
|
+
|
|
12
|
+
/** Walk an element */
|
|
13
|
+
function walk(element, windows, depth = 0) {
|
|
14
|
+
if (!element) {
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// With Web Components, we need to walk into shadow DOMs
|
|
19
|
+
const children = 'shadowRoot' in element && element.shadowRoot ? element.shadowRoot.children : element.children;
|
|
20
|
+
|
|
21
|
+
for (const child of children) {
|
|
22
|
+
if (!(child instanceof HTMLElement)) {
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const componentName = core.getComponentName(child, 1) || undefined;
|
|
27
|
+
const tagName = child.tagName.toLowerCase();
|
|
28
|
+
|
|
29
|
+
if (skipHtmlTags.includes(tagName)) {
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const result = options.onElement?.({ element: child, componentName, tagName, depth }) || {};
|
|
34
|
+
|
|
35
|
+
if (result === 'skip') {
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Skip this element but include its children
|
|
40
|
+
if (result === 'children') {
|
|
41
|
+
walk(child, windows, depth + 1);
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const { x, y, width, height } = child.getBoundingClientRect();
|
|
46
|
+
|
|
47
|
+
const window = {
|
|
48
|
+
identifier: (child.id || undefined) ,
|
|
49
|
+
type: componentName || tagName,
|
|
50
|
+
visible: true,
|
|
51
|
+
alpha: 1,
|
|
52
|
+
height,
|
|
53
|
+
width,
|
|
54
|
+
x,
|
|
55
|
+
y,
|
|
56
|
+
...result,
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const children = [];
|
|
60
|
+
window.children = children;
|
|
61
|
+
|
|
62
|
+
// Recursively walk the children
|
|
63
|
+
walk(child, window.children, depth + 1);
|
|
64
|
+
|
|
65
|
+
windows.push(window);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return {
|
|
70
|
+
name: 'ViewHierarchy',
|
|
71
|
+
processEvent: (event, hint) => {
|
|
72
|
+
// only capture for error events
|
|
73
|
+
if (event.type !== undefined || options.shouldAttach?.(event, hint) === false) {
|
|
74
|
+
return event;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const root = {
|
|
78
|
+
rendering_system: 'DOM',
|
|
79
|
+
positioning: 'absolute',
|
|
80
|
+
windows: [],
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
walk(options.rootElement?.() || helpers.WINDOW.document.body, root.windows);
|
|
84
|
+
|
|
85
|
+
const attachment = {
|
|
86
|
+
filename: 'view-hierarchy.json',
|
|
87
|
+
attachmentType: 'event.view_hierarchy',
|
|
88
|
+
contentType: 'application/json',
|
|
89
|
+
data: JSON.stringify(root),
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
hint.attachments = hint.attachments || [];
|
|
93
|
+
hint.attachments.push(attachment);
|
|
94
|
+
|
|
95
|
+
return event;
|
|
96
|
+
},
|
|
97
|
+
};
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
exports.viewHierarchyIntegration = viewHierarchyIntegration;
|
|
101
|
+
//# sourceMappingURL=view-hierarchy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"view-hierarchy.js","sources":["../../../../../src/integrations/view-hierarchy.ts"],"sourcesContent":["import type { Attachment, Event, EventHint, ViewHierarchyData, ViewHierarchyWindow } from '@sentry/core';\nimport { defineIntegration, getComponentName } from '@sentry/core';\nimport { WINDOW } from '../helpers';\n\ninterface OnElementArgs {\n /**\n * The element being processed.\n */\n element: HTMLElement;\n /**\n * Lowercase tag name of the element.\n */\n tagName: string;\n /**\n * The component name of the element.\n */\n componentName?: string;\n\n /**\n * The current depth of the element in the view hierarchy. The root element will have a depth of 0.\n *\n * This allows you to limit the traversal depth for large DOM trees.\n */\n depth?: number;\n}\n\ninterface Options {\n /**\n * Whether to attach the view hierarchy to the event.\n *\n * Default: Always attach.\n */\n shouldAttach?: (event: Event, hint: EventHint) => boolean;\n\n /**\n * A function that returns the root element to start walking the DOM from.\n *\n * Default: `window.document.body`\n */\n rootElement?: () => HTMLElement | undefined;\n\n /**\n * Called for each HTMLElement as we walk the DOM.\n *\n * Return an object to include the element with any additional properties.\n * Return `skip` to exclude the element and its children.\n * Return `children` to skip the element but include its children.\n */\n onElement?: (prop: OnElementArgs) => Record<string, string | number | boolean> | 'skip' | 'children';\n}\n\n/**\n * An integration to include a view hierarchy attachment which contains the DOM.\n */\nexport const viewHierarchyIntegration = defineIntegration((options: Options = {}) => {\n const skipHtmlTags = ['script'];\n\n /** Walk an element */\n function walk(element: HTMLElement, windows: ViewHierarchyWindow[], depth = 0): void {\n if (!element) {\n return;\n }\n\n // With Web Components, we need to walk into shadow DOMs\n const children = 'shadowRoot' in element && element.shadowRoot ? element.shadowRoot.children : element.children;\n\n for (const child of children) {\n if (!(child instanceof HTMLElement)) {\n continue;\n }\n\n const componentName = getComponentName(child, 1) || undefined;\n const tagName = child.tagName.toLowerCase();\n\n if (skipHtmlTags.includes(tagName)) {\n continue;\n }\n\n const result = options.onElement?.({ element: child, componentName, tagName, depth }) || {};\n\n if (result === 'skip') {\n continue;\n }\n\n // Skip this element but include its children\n if (result === 'children') {\n walk(child, windows, depth + 1);\n continue;\n }\n\n const { x, y, width, height } = child.getBoundingClientRect();\n\n const window: ViewHierarchyWindow = {\n identifier: (child.id || undefined) as string,\n type: componentName || tagName,\n visible: true,\n alpha: 1,\n height,\n width,\n x,\n y,\n ...result,\n };\n\n const children: ViewHierarchyWindow[] = [];\n window.children = children;\n\n // Recursively walk the children\n walk(child, window.children, depth + 1);\n\n windows.push(window);\n }\n }\n\n return {\n name: 'ViewHierarchy',\n processEvent: (event, hint) => {\n // only capture for error events\n if (event.type !== undefined || options.shouldAttach?.(event, hint) === false) {\n return event;\n }\n\n const root: ViewHierarchyData = {\n rendering_system: 'DOM',\n positioning: 'absolute',\n windows: [],\n };\n\n walk(options.rootElement?.() || WINDOW.document.body, root.windows);\n\n const attachment: Attachment = {\n filename: 'view-hierarchy.json',\n attachmentType: 'event.view_hierarchy',\n contentType: 'application/json',\n data: JSON.stringify(root),\n };\n\n hint.attachments = hint.attachments || [];\n hint.attachments.push(attachment);\n\n return event;\n },\n };\n});\n"],"names":["defineIntegration","getComponentName","WINDOW"],"mappings":"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"}
|
|
@@ -18,7 +18,7 @@ const BROWSER_TRACING_INTEGRATION_ID = 'BrowserTracing';
|
|
|
18
18
|
const BOT_USER_AGENT_RE =
|
|
19
19
|
/Googlebot|Google-InspectionTool|Storebot-Google|Bingbot|Slurp|DuckDuckBot|Baiduspider|YandexBot|Facebot|facebookexternalhit|LinkedInBot|Twitterbot|Applebot/i;
|
|
20
20
|
|
|
21
|
-
function
|
|
21
|
+
function isBotUserAgent() {
|
|
22
22
|
const nav = helpers.WINDOW.navigator ;
|
|
23
23
|
if (!nav?.userAgent) {
|
|
24
24
|
return false;
|
|
@@ -104,7 +104,7 @@ const browserTracingIntegration = ((options = {}) => {
|
|
|
104
104
|
...options,
|
|
105
105
|
};
|
|
106
106
|
|
|
107
|
-
const _isBot =
|
|
107
|
+
const _isBot = isBotUserAgent();
|
|
108
108
|
|
|
109
109
|
let _collectWebVitals;
|
|
110
110
|
let lastInteractionTimestamp;
|
|
@@ -152,11 +152,13 @@ const browserTracingIntegration = ((options = {}) => {
|
|
|
152
152
|
// This will generally always be defined here, because it is set in `setup()` of the integration
|
|
153
153
|
// but technically, it is optional, so we guard here to be extra safe
|
|
154
154
|
_collectWebVitals?.();
|
|
155
|
+
const spanStreamingEnabled = core.hasSpanStreamingEnabled(client);
|
|
155
156
|
browserUtils.addPerformanceEntries(span, {
|
|
156
|
-
recordClsOnPageloadSpan: !enableStandaloneClsSpans,
|
|
157
|
-
recordLcpOnPageloadSpan: !enableStandaloneLcpSpans,
|
|
157
|
+
recordClsOnPageloadSpan: !spanStreamingEnabled && !enableStandaloneClsSpans,
|
|
158
|
+
recordLcpOnPageloadSpan: !spanStreamingEnabled && !enableStandaloneLcpSpans,
|
|
158
159
|
ignoreResourceSpans,
|
|
159
160
|
ignorePerformanceApiSpans,
|
|
161
|
+
spanStreamingEnabled,
|
|
160
162
|
});
|
|
161
163
|
setActiveIdleSpan(client, undefined);
|
|
162
164
|
|
|
@@ -213,13 +215,21 @@ const browserTracingIntegration = ((options = {}) => {
|
|
|
213
215
|
|
|
214
216
|
core.registerSpanErrorInstrumentation();
|
|
215
217
|
|
|
218
|
+
const spanStreamingEnabled = core.hasSpanStreamingEnabled(client);
|
|
219
|
+
|
|
216
220
|
_collectWebVitals = browserUtils.startTrackingWebVitals({
|
|
217
|
-
recordClsStandaloneSpans: enableStandaloneClsSpans || false,
|
|
218
|
-
recordLcpStandaloneSpans: enableStandaloneLcpSpans || false,
|
|
221
|
+
recordClsStandaloneSpans: spanStreamingEnabled ? undefined : enableStandaloneClsSpans || false,
|
|
222
|
+
recordLcpStandaloneSpans: spanStreamingEnabled ? undefined : enableStandaloneLcpSpans || false,
|
|
219
223
|
client,
|
|
220
224
|
});
|
|
221
225
|
|
|
222
|
-
if (
|
|
226
|
+
if (spanStreamingEnabled) {
|
|
227
|
+
browserUtils.trackLcpAsSpan(client);
|
|
228
|
+
browserUtils.trackClsAsSpan(client);
|
|
229
|
+
if (enableInp) {
|
|
230
|
+
browserUtils.trackInpAsSpan();
|
|
231
|
+
}
|
|
232
|
+
} else if (enableInp) {
|
|
223
233
|
browserUtils.startTrackingINP();
|
|
224
234
|
}
|
|
225
235
|
|
|
@@ -610,6 +620,7 @@ exports.BROWSER_TRACING_INTEGRATION_ID = BROWSER_TRACING_INTEGRATION_ID;
|
|
|
610
620
|
exports.browserTracingIntegration = browserTracingIntegration;
|
|
611
621
|
exports.getMetaContent = getMetaContent;
|
|
612
622
|
exports.getServerTiming = getServerTiming;
|
|
623
|
+
exports.isBotUserAgent = isBotUserAgent;
|
|
613
624
|
exports.startBrowserTracingNavigationSpan = startBrowserTracingNavigationSpan;
|
|
614
625
|
exports.startBrowserTracingPageLoadSpan = startBrowserTracingPageLoadSpan;
|
|
615
626
|
//# sourceMappingURL=browserTracingIntegration.js.map
|