{"version":3,"file":"outgoingFetchRequest.js","sources":["../../../src/utils/outgoingFetchRequest.ts"],"sourcesContent":["import type { LRUMap, SanitizedRequestData } from '@sentry/core';\nimport {\n addBreadcrumb,\n getBreadcrumbLogLevelFromHttpStatusCode,\n getClient,\n getSanitizedUrlString,\n getTraceData,\n parseUrl,\n shouldPropagateTraceForUrl,\n} from '@sentry/core';\nimport type { UndiciRequest, UndiciResponse } from '../integrations/node-fetch/types';\nimport { mergeBaggageHeaders } from './baggage';\n\nconst SENTRY_TRACE_HEADER = 'sentry-trace';\nconst SENTRY_BAGGAGE_HEADER = 'baggage';\n\n// For baggage, we make sure to merge this into a possibly existing header\nconst BAGGAGE_HEADER_REGEX = /baggage: (.*)\\r\\n/;\n\n/**\n * Add trace propagation headers to an outgoing fetch/undici request.\n *\n * Checks if the request URL matches trace propagation targets,\n * then injects sentry-trace, traceparent, and baggage headers.\n */\n// eslint-disable-next-line complexity\nexport function addTracePropagationHeadersToFetchRequest(\n request: UndiciRequest,\n propagationDecisionMap: LRUMap,\n): void {\n const url = getAbsoluteUrl(request.origin, request.path);\n\n // Manually add the trace headers, if it applies\n // Note: We do not use `propagation.inject()` here, because our propagator relies on an active span\n // Which we do not have in this case\n // The propagator _may_ overwrite this, but this should be fine as it is the same data\n const { tracePropagationTargets, propagateTraceparent } = getClient()?.getOptions() || {};\n const addedHeaders = shouldPropagateTraceForUrl(url, tracePropagationTargets, propagationDecisionMap)\n ? getTraceData({ propagateTraceparent })\n : undefined;\n\n if (!addedHeaders) {\n return;\n }\n\n const { 'sentry-trace': sentryTrace, baggage, traceparent } = addedHeaders;\n\n // We do not want to overwrite existing headers here\n // If the core UndiciInstrumentation is registered, it will already have set the headers\n // We do not want to add any then\n if (Array.isArray(request.headers)) {\n const requestHeaders = request.headers;\n\n // We do not want to overwrite existing header here, if it was already set\n if (sentryTrace && !requestHeaders.includes(SENTRY_TRACE_HEADER)) {\n requestHeaders.push(SENTRY_TRACE_HEADER, sentryTrace);\n }\n\n if (traceparent && !requestHeaders.includes('traceparent')) {\n requestHeaders.push('traceparent', traceparent);\n }\n\n // For baggage, we make sure to merge this into a possibly existing header\n const existingBaggagePos = requestHeaders.findIndex(header => header === SENTRY_BAGGAGE_HEADER);\n if (baggage && existingBaggagePos === -1) {\n requestHeaders.push(SENTRY_BAGGAGE_HEADER, baggage);\n } else if (baggage) {\n const existingBaggage = requestHeaders[existingBaggagePos + 1];\n const merged = mergeBaggageHeaders(existingBaggage, baggage);\n if (merged) {\n requestHeaders[existingBaggagePos + 1] = merged;\n }\n }\n } else {\n const requestHeaders = request.headers;\n // We do not want to overwrite existing header here, if it was already set\n if (sentryTrace && !requestHeaders.includes(`${SENTRY_TRACE_HEADER}:`)) {\n request.headers += `${SENTRY_TRACE_HEADER}: ${sentryTrace}\\r\\n`;\n }\n\n if (traceparent && !requestHeaders.includes('traceparent:')) {\n request.headers += `traceparent: ${traceparent}\\r\\n`;\n }\n\n const existingBaggage = request.headers.match(BAGGAGE_HEADER_REGEX)?.[1];\n if (baggage && !existingBaggage) {\n request.headers += `${SENTRY_BAGGAGE_HEADER}: ${baggage}\\r\\n`;\n } else if (baggage) {\n const merged = mergeBaggageHeaders(existingBaggage, baggage);\n if (merged) {\n request.headers = request.headers.replace(BAGGAGE_HEADER_REGEX, `baggage: ${merged}\\r\\n`);\n }\n }\n }\n}\n\n/** Add a breadcrumb for an outgoing fetch/undici request. */\nexport function addFetchRequestBreadcrumb(request: UndiciRequest, response: UndiciResponse): void {\n const data = getBreadcrumbData(request);\n\n const statusCode = response.statusCode;\n const level = getBreadcrumbLogLevelFromHttpStatusCode(statusCode);\n\n addBreadcrumb(\n {\n category: 'http',\n data: {\n status_code: statusCode,\n ...data,\n },\n type: 'http',\n level,\n },\n {\n event: 'response',\n request,\n response,\n },\n );\n}\n\nfunction getBreadcrumbData(request: UndiciRequest): Partial {\n try {\n const url = getAbsoluteUrl(request.origin, request.path);\n const parsedUrl = parseUrl(url);\n\n const data: Partial = {\n url: getSanitizedUrlString(parsedUrl),\n 'http.method': request.method || 'GET',\n };\n\n if (parsedUrl.search) {\n data['http.query'] = parsedUrl.search;\n }\n if (parsedUrl.hash) {\n data['http.fragment'] = parsedUrl.hash;\n }\n\n return data;\n } catch {\n return {};\n }\n}\n\n/** Get the absolute URL from an origin and path. */\nexport function getAbsoluteUrl(origin: string, path: string = '/'): string {\n try {\n const url = new URL(path, origin);\n return url.toString();\n } catch {\n // fallback: Construct it on our own\n const url = `${origin}`;\n\n if (url.endsWith('/') && path.startsWith('/')) {\n return `${url}${path.slice(1)}`;\n }\n\n if (!url.endsWith('/') && !path.startsWith('/')) {\n return `${url}/${path}`;\n }\n\n return `${url}${path}`;\n }\n}\n"],"names":[],"mappings":"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"}