{"version":3,"file":"fetch.js","sources":["../../src/fetch.ts"],"sourcesContent":["import type { Client, HandlerDataFetch, Scope, Span, SpanOrigin } from '@sentry/types';\nimport {\n BAGGAGE_HEADER_NAME,\n SENTRY_BAGGAGE_KEY_PREFIX,\n dynamicSamplingContextToSentryBaggageHeader,\n generateSentryTraceHeader,\n isInstanceOf,\n parseUrl,\n} from '@sentry/utils';\nimport { getClient, getCurrentScope, getIsolationScope } from './currentScopes';\nimport { SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN } from './semanticAttributes';\nimport {\n SPAN_STATUS_ERROR,\n getDynamicSamplingContextFromClient,\n getDynamicSamplingContextFromSpan,\n setHttpStatus,\n startInactiveSpan,\n} from './tracing';\nimport { SentryNonRecordingSpan } from './tracing/sentryNonRecordingSpan';\nimport { hasTracingEnabled } from './utils/hasTracingEnabled';\nimport { getActiveSpan, spanToTraceHeader } from './utils/spanUtils';\n\ntype PolymorphicRequestHeaders =\n | Record\n | Array<[string, string]>\n // the below is not precisely the Header type used in Request, but it'll pass duck-typing\n | {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n [key: string]: any;\n append: (key: string, value: string) => void;\n get: (key: string) => string | null | undefined;\n };\n\n/**\n * Create and track fetch request spans for usage in combination with `addFetchInstrumentationHandler`.\n *\n * @returns Span if a span was created, otherwise void.\n */\nexport function instrumentFetchRequest(\n handlerData: HandlerDataFetch,\n shouldCreateSpan: (url: string) => boolean,\n shouldAttachHeaders: (url: string) => boolean,\n spans: Record,\n spanOrigin: SpanOrigin = 'auto.http.browser',\n): Span | undefined {\n if (!handlerData.fetchData) {\n return undefined;\n }\n\n const shouldCreateSpanResult = hasTracingEnabled() && shouldCreateSpan(handlerData.fetchData.url);\n\n if (handlerData.endTimestamp && shouldCreateSpanResult) {\n const spanId = handlerData.fetchData.__span;\n if (!spanId) return;\n\n const span = spans[spanId];\n if (span) {\n endSpan(span, handlerData);\n\n // eslint-disable-next-line @typescript-eslint/no-dynamic-delete\n delete spans[spanId];\n }\n return undefined;\n }\n\n const scope = getCurrentScope();\n const client = getClient();\n\n const { method, url } = handlerData.fetchData;\n\n const fullUrl = getFullURL(url);\n const host = fullUrl ? parseUrl(fullUrl).host : undefined;\n\n const hasParent = !!getActiveSpan();\n\n const span =\n shouldCreateSpanResult && hasParent\n ? startInactiveSpan({\n name: `${method} ${url}`,\n attributes: {\n url,\n type: 'fetch',\n 'http.method': method,\n 'http.url': fullUrl,\n 'server.address': host,\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: spanOrigin,\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'http.client',\n },\n })\n : new SentryNonRecordingSpan();\n\n handlerData.fetchData.__span = span.spanContext().spanId;\n spans[span.spanContext().spanId] = span;\n\n if (shouldAttachHeaders(handlerData.fetchData.url) && client) {\n const request: string | Request = handlerData.args[0];\n\n // In case the user hasn't set the second argument of a fetch call we default it to `{}`.\n handlerData.args[1] = handlerData.args[1] || {};\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const options: { [key: string]: any } = handlerData.args[1];\n\n options.headers = addTracingHeadersToFetchRequest(\n request,\n client,\n scope,\n options,\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 hasTracingEnabled() && hasParent ? span : undefined,\n );\n }\n\n return span;\n}\n\n/**\n * Adds sentry-trace and baggage headers to the various forms of fetch headers\n */\nexport function addTracingHeadersToFetchRequest(\n request: string | unknown, // unknown is actually type Request but we can't export DOM types from this package,\n client: Client,\n scope: Scope,\n fetchOptionsObj: {\n headers?:\n | {\n [key: string]: string[] | string | undefined;\n }\n | PolymorphicRequestHeaders;\n },\n span?: Span,\n): PolymorphicRequestHeaders | undefined {\n const isolationScope = getIsolationScope();\n\n const { traceId, spanId, sampled, dsc } = {\n ...isolationScope.getPropagationContext(),\n ...scope.getPropagationContext(),\n };\n\n const sentryTraceHeader = span ? spanToTraceHeader(span) : generateSentryTraceHeader(traceId, spanId, sampled);\n\n const sentryBaggageHeader = dynamicSamplingContextToSentryBaggageHeader(\n dsc || (span ? getDynamicSamplingContextFromSpan(span) : getDynamicSamplingContextFromClient(traceId, client)),\n );\n\n const headers =\n fetchOptionsObj.headers ||\n (typeof Request !== 'undefined' && isInstanceOf(request, Request) ? (request as Request).headers : undefined);\n\n if (!headers) {\n return { 'sentry-trace': sentryTraceHeader, baggage: sentryBaggageHeader };\n } else if (typeof Headers !== 'undefined' && isInstanceOf(headers, Headers)) {\n const newHeaders = new Headers(headers as Headers);\n\n newHeaders.set('sentry-trace', sentryTraceHeader);\n\n if (sentryBaggageHeader) {\n const prevBaggageHeader = newHeaders.get(BAGGAGE_HEADER_NAME);\n if (prevBaggageHeader) {\n const prevHeaderStrippedFromSentryBaggage = stripBaggageHeaderOfSentryBaggageValues(prevBaggageHeader);\n newHeaders.set(\n BAGGAGE_HEADER_NAME,\n // If there are non-sentry entries (i.e. if the stripped string is non-empty/truthy) combine the stripped header and sentry baggage header\n // otherwise just set the sentry baggage header\n prevHeaderStrippedFromSentryBaggage\n ? `${prevHeaderStrippedFromSentryBaggage},${sentryBaggageHeader}`\n : sentryBaggageHeader,\n );\n } else {\n newHeaders.set(BAGGAGE_HEADER_NAME, sentryBaggageHeader);\n }\n }\n\n return newHeaders as PolymorphicRequestHeaders;\n } else if (Array.isArray(headers)) {\n const newHeaders = [\n ...headers\n // Remove any existing sentry-trace headers\n .filter(header => {\n return !(Array.isArray(header) && header[0] === 'sentry-trace');\n })\n // Get rid of previous sentry baggage values in baggage header\n .map(header => {\n if (Array.isArray(header) && header[0] === BAGGAGE_HEADER_NAME && typeof header[1] === 'string') {\n const [headerName, headerValue, ...rest] = header;\n return [headerName, stripBaggageHeaderOfSentryBaggageValues(headerValue), ...rest];\n } else {\n return header;\n }\n }),\n // Attach the new sentry-trace header\n ['sentry-trace', sentryTraceHeader],\n ];\n\n if (sentryBaggageHeader) {\n // If there are multiple entries with the same key, the browser will merge the values into a single request header.\n // Its therefore safe to simply push a \"baggage\" entry, even though there might already be another baggage header.\n newHeaders.push([BAGGAGE_HEADER_NAME, sentryBaggageHeader]);\n }\n\n return newHeaders as PolymorphicRequestHeaders;\n } else {\n const existingBaggageHeader = 'baggage' in headers ? headers.baggage : undefined;\n let newBaggageHeaders: string[] = [];\n\n if (Array.isArray(existingBaggageHeader)) {\n newBaggageHeaders = existingBaggageHeader\n .map(headerItem =>\n typeof headerItem === 'string' ? stripBaggageHeaderOfSentryBaggageValues(headerItem) : headerItem,\n )\n .filter(headerItem => headerItem === '');\n } else if (existingBaggageHeader) {\n newBaggageHeaders.push(stripBaggageHeaderOfSentryBaggageValues(existingBaggageHeader));\n }\n\n if (sentryBaggageHeader) {\n newBaggageHeaders.push(sentryBaggageHeader);\n }\n\n return {\n ...(headers as Exclude),\n 'sentry-trace': sentryTraceHeader,\n baggage: newBaggageHeaders.length > 0 ? newBaggageHeaders.join(',') : undefined,\n };\n }\n}\n\nfunction getFullURL(url: string): string | undefined {\n try {\n const parsed = new URL(url);\n return parsed.href;\n } catch {\n return undefined;\n }\n}\n\nfunction endSpan(span: Span, handlerData: HandlerDataFetch): void {\n if (handlerData.response) {\n setHttpStatus(span, handlerData.response.status);\n\n const contentLength =\n handlerData.response && handlerData.response.headers && handlerData.response.headers.get('content-length');\n\n if (contentLength) {\n const contentLengthNum = parseInt(contentLength);\n if (contentLengthNum > 0) {\n span.setAttribute('http.response_content_length', contentLengthNum);\n }\n }\n } else if (handlerData.error) {\n span.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n }\n span.end();\n}\n\nfunction stripBaggageHeaderOfSentryBaggageValues(baggageHeader: string): string {\n return (\n baggageHeader\n .split(',')\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n .filter(baggageEntry => !baggageEntry.split('=')[0]!.startsWith(SENTRY_BAGGAGE_KEY_PREFIX))\n .join(',')\n );\n}\n"],"names":["hasTracingEnabled","getCurrentScope","getClient","parseUrl","getActiveSpan","startInactiveSpan","SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN","SEMANTIC_ATTRIBUTE_SENTRY_OP","SentryNonRecordingSpan","getIsolationScope","spanToTraceHeader","generateSentryTraceHeader","dynamicSamplingContextToSentryBaggageHeader","getDynamicSamplingContextFromSpan","getDynamicSamplingContextFromClient","isInstanceOf","BAGGAGE_HEADER_NAME","setHttpStatus","SPAN_STATUS_ERROR","SENTRY_BAGGAGE_KEY_PREFIX"],"mappings":"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"}