@sentry/browser
Advanced tools
@@ -5,2 +5,3 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); | ||
| const browserUtils = require('@sentry/browser-utils'); | ||
| const attributes = require('@sentry/conventions/attributes'); | ||
@@ -39,4 +40,4 @@ const INTEGRATION_NAME = "GraphQLClient"; | ||
| span.updateName(`${httpMethod} ${httpUrl} (${operationInfo})`); | ||
| if (isStandardRequest(graphqlBody)) { | ||
| span.setAttribute("graphql.document", graphqlBody.query); | ||
| if (isStandardRequest(graphqlBody) && client.getDataCollectionOptions().graphQL.document === true) { | ||
| span.setAttribute(attributes.GRAPHQL_DOCUMENT, graphqlBody.query); | ||
| } | ||
@@ -67,4 +68,4 @@ if (isPersistedRequest(graphqlBody)) { | ||
| data["graphql.operation"] = operationInfo; | ||
| if (isStandardRequest(graphqlBody)) { | ||
| data["graphql.document"] = graphqlBody.query; | ||
| if (isStandardRequest(graphqlBody) && client.getDataCollectionOptions().graphQL.document === true) { | ||
| data[attributes.GRAPHQL_DOCUMENT] = graphqlBody.query; | ||
| } | ||
@@ -71,0 +72,0 @@ if (isPersistedRequest(graphqlBody)) { |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"graphqlClient.js","sources":["../../../../../src/integrations/graphqlClient.ts"],"sourcesContent":["import type { Client, IntegrationFn } from '@sentry/core/browser';\nimport {\n defineIntegration,\n isObjectLike,\n isString,\n SEMANTIC_ATTRIBUTE_HTTP_REQUEST_METHOD,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n SEMANTIC_ATTRIBUTE_URL_FULL,\n spanToJSON,\n stringMatchesSomePattern,\n} from '@sentry/core/browser';\nimport type { FetchHint, XhrHint } from '@sentry/browser-utils';\nimport { getBodyString, getFetchRequestArgBody, SENTRY_XHR_DATA_KEY } from '@sentry/browser-utils';\n\ninterface GraphQLClientOptions {\n endpoints: Array<string | RegExp>;\n}\n\n/** Standard graphql request shape: https://graphql.org/learn/serving-over-http/#post-request-and-body */\ninterface GraphQLStandardRequest {\n query: string;\n operationName?: string;\n variables?: Record<string, unknown>;\n extensions?: Record<string, unknown>;\n}\n\n/** Persisted operation request */\ninterface GraphQLPersistedRequest {\n operationName: string;\n variables?: Record<string, unknown>;\n extensions: {\n persistedQuery: {\n version: number;\n sha256Hash: string;\n };\n } & Record<string, unknown>;\n}\n\ntype GraphQLRequestPayload = GraphQLStandardRequest | GraphQLPersistedRequest;\n\ninterface GraphQLOperation {\n operationType?: string;\n operationName?: string;\n}\n\nconst INTEGRATION_NAME = 'GraphQLClient' as const;\n\nconst _graphqlClientIntegration = ((options: GraphQLClientOptions) => {\n return {\n name: INTEGRATION_NAME,\n setup(client: Client) {\n _updateSpanWithGraphQLData(client, options);\n _updateBreadcrumbWithGraphQLData(client, options);\n },\n };\n}) satisfies IntegrationFn;\n\nfunction _updateSpanWithGraphQLData(client: Client, options: GraphQLClientOptions): void {\n client.on('beforeOutgoingRequestSpan', (span, hint) => {\n const spanJSON = spanToJSON(span);\n\n const spanAttributes = spanJSON.data || {};\n const spanOp = spanAttributes[SEMANTIC_ATTRIBUTE_SENTRY_OP];\n\n const isHttpClientSpan = spanOp === 'http.client';\n\n if (!isHttpClientSpan) {\n return;\n }\n\n // Fall back to `url` because fetch instrumentation only sets `http.url` for absolute URLs;\n // relative URLs end up only in `url` (see `getFetchSpanAttributes` in packages/core/src/fetch.ts).\n const httpUrl = spanAttributes[SEMANTIC_ATTRIBUTE_URL_FULL] || spanAttributes['http.url'] || spanAttributes['url'];\n const httpMethod = spanAttributes[SEMANTIC_ATTRIBUTE_HTTP_REQUEST_METHOD] || spanAttributes['http.method'];\n\n if (!isString(httpUrl) || !isString(httpMethod)) {\n return;\n }\n\n const { endpoints } = options;\n const isTracedGraphqlEndpoint = stringMatchesSomePattern(httpUrl, endpoints);\n const payload = getRequestPayloadXhrOrFetch(hint as XhrHint | FetchHint);\n\n if (isTracedGraphqlEndpoint && payload) {\n const graphqlBody = getGraphQLRequestPayload(payload);\n\n if (graphqlBody) {\n const operationInfo = _getGraphQLOperation(graphqlBody);\n span.updateName(`${httpMethod} ${httpUrl} (${operationInfo})`);\n\n // Handle standard requests - always capture the query document\n if (isStandardRequest(graphqlBody)) {\n span.setAttribute('graphql.document', graphqlBody.query);\n }\n\n // Handle persisted operations - capture hash for debugging\n if (isPersistedRequest(graphqlBody)) {\n span.setAttribute('graphql.persisted_query.hash.sha256', graphqlBody.extensions.persistedQuery.sha256Hash);\n span.setAttribute('graphql.persisted_query.version', graphqlBody.extensions.persistedQuery.version);\n }\n }\n }\n });\n}\n\nfunction _updateBreadcrumbWithGraphQLData(client: Client, options: GraphQLClientOptions): void {\n client.on('beforeOutgoingRequestBreadcrumb', (breadcrumb, handlerData) => {\n const { category, type, data } = breadcrumb;\n\n const isFetch = category === 'fetch';\n const isXhr = category === 'xhr';\n const isHttpBreadcrumb = type === 'http';\n\n if (isHttpBreadcrumb && (isFetch || isXhr)) {\n const httpUrl = data?.url;\n const { endpoints } = options;\n\n const isTracedGraphqlEndpoint = stringMatchesSomePattern(httpUrl, endpoints);\n const payload = getRequestPayloadXhrOrFetch(handlerData as XhrHint | FetchHint);\n\n if (isTracedGraphqlEndpoint && data && payload) {\n const graphqlBody = getGraphQLRequestPayload(payload);\n\n if (!data.graphql && graphqlBody) {\n const operationInfo = _getGraphQLOperation(graphqlBody);\n\n data['graphql.operation'] = operationInfo;\n\n if (isStandardRequest(graphqlBody)) {\n data['graphql.document'] = graphqlBody.query;\n }\n\n if (isPersistedRequest(graphqlBody)) {\n data['graphql.persisted_query.hash.sha256'] = graphqlBody.extensions.persistedQuery.sha256Hash;\n data['graphql.persisted_query.version'] = graphqlBody.extensions.persistedQuery.version;\n }\n }\n }\n }\n });\n}\n\n/**\n * @param requestBody - GraphQL request\n * @returns A formatted version of the request: 'TYPE NAME' or 'TYPE' or 'persisted NAME'\n */\nexport function _getGraphQLOperation(requestBody: GraphQLRequestPayload): string {\n // Handle persisted operations\n if (isPersistedRequest(requestBody)) {\n return `persisted ${requestBody.operationName}`;\n }\n\n // Handle standard GraphQL requests\n if (isStandardRequest(requestBody)) {\n const { query: graphqlQuery, operationName: graphqlOperationName } = requestBody;\n const { operationName = graphqlOperationName, operationType } = parseGraphQLQuery(graphqlQuery);\n const operationInfo = operationName ? `${operationType} ${operationName}` : `${operationType}`;\n return operationInfo;\n }\n\n // Fallback for unknown request types\n return 'unknown';\n}\n\n/**\n * Get the request body/payload based on the shape of the hint.\n *\n * Exported for tests only.\n */\nexport function getRequestPayloadXhrOrFetch(hint: XhrHint | FetchHint): string | undefined {\n const isXhr = 'xhr' in hint;\n\n let body: string | undefined;\n\n if (isXhr) {\n const sentryXhrData = hint.xhr[SENTRY_XHR_DATA_KEY];\n body = sentryXhrData && getBodyString(sentryXhrData.body)[0];\n } else {\n const sentryFetchData = getFetchRequestArgBody(hint.input);\n body = getBodyString(sentryFetchData)[0];\n }\n\n return body;\n}\n\n/**\n * Extract the name and type of the operation from the GraphQL query.\n *\n * Exported for tests only.\n */\nexport function parseGraphQLQuery(query: string): GraphQLOperation {\n const namedQueryRe = /^(?:\\s*)(query|mutation|subscription)(?:\\s*)(\\w+)(?:\\s*)[{(]/;\n const unnamedQueryRe = /^(?:\\s*)(query|mutation|subscription)(?:\\s*)[{(]/;\n\n const namedMatch = query.match(namedQueryRe);\n if (namedMatch) {\n return {\n operationType: namedMatch[1],\n operationName: namedMatch[2],\n };\n }\n\n const unnamedMatch = query.match(unnamedQueryRe);\n if (unnamedMatch) {\n return {\n operationType: unnamedMatch[1],\n operationName: undefined,\n };\n }\n return {\n operationType: undefined,\n operationName: undefined,\n };\n}\n\n/**\n * Helper to safely check if a value is a non-null object\n */\n\n/**\n * Type guard to check if a request is a standard GraphQL request\n */\nfunction isStandardRequest(payload: unknown): payload is GraphQLStandardRequest {\n return isObjectLike(payload) && typeof payload.query === 'string';\n}\n\n/**\n * Type guard to check if a request is a persisted operation request\n */\nfunction isPersistedRequest(payload: unknown): payload is GraphQLPersistedRequest {\n return (\n isObjectLike(payload) &&\n typeof payload.operationName === 'string' &&\n isObjectLike(payload.extensions) &&\n isObjectLike(payload.extensions.persistedQuery) &&\n typeof payload.extensions.persistedQuery.sha256Hash === 'string' &&\n typeof payload.extensions.persistedQuery.version === 'number'\n );\n}\n\n/**\n * Extract the payload of a request if it's GraphQL.\n * Exported for tests only.\n * @param payload - A valid JSON string\n * @returns A POJO or undefined\n */\nexport function getGraphQLRequestPayload(payload: string): GraphQLRequestPayload | undefined {\n try {\n const requestBody = JSON.parse(payload);\n\n // Return any valid GraphQL request (standard, persisted, or APQ retry with both)\n if (isStandardRequest(requestBody) || isPersistedRequest(requestBody)) {\n return requestBody;\n }\n\n // Not a GraphQL request\n return undefined;\n } catch {\n // Invalid JSON\n return undefined;\n }\n}\n\n/**\n * This integration ensures that GraphQL requests made in the browser\n * have their GraphQL-specific data captured and attached to spans and breadcrumbs.\n */\nexport const graphqlClientIntegration = defineIntegration(_graphqlClientIntegration);\n"],"names":["spanToJSON","SEMANTIC_ATTRIBUTE_SENTRY_OP","SEMANTIC_ATTRIBUTE_URL_FULL","SEMANTIC_ATTRIBUTE_HTTP_REQUEST_METHOD","isString","stringMatchesSomePattern","SENTRY_XHR_DATA_KEY","getBodyString","getFetchRequestArgBody","isObjectLike","defineIntegration"],"mappings":"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"} | ||
| {"version":3,"file":"graphqlClient.js","sources":["../../../../../src/integrations/graphqlClient.ts"],"sourcesContent":["import type { Client, IntegrationFn } from '@sentry/core/browser';\nimport {\n defineIntegration,\n isObjectLike,\n isString,\n SEMANTIC_ATTRIBUTE_HTTP_REQUEST_METHOD,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n SEMANTIC_ATTRIBUTE_URL_FULL,\n spanToJSON,\n stringMatchesSomePattern,\n} from '@sentry/core/browser';\nimport type { FetchHint, XhrHint } from '@sentry/browser-utils';\nimport { getBodyString, getFetchRequestArgBody, SENTRY_XHR_DATA_KEY } from '@sentry/browser-utils';\nimport { GRAPHQL_DOCUMENT } from '@sentry/conventions/attributes';\n\ninterface GraphQLClientOptions {\n endpoints: Array<string | RegExp>;\n}\n\n/** Standard graphql request shape: https://graphql.org/learn/serving-over-http/#post-request-and-body */\ninterface GraphQLStandardRequest {\n query: string;\n operationName?: string;\n variables?: Record<string, unknown>;\n extensions?: Record<string, unknown>;\n}\n\n/** Persisted operation request */\ninterface GraphQLPersistedRequest {\n operationName: string;\n variables?: Record<string, unknown>;\n extensions: {\n persistedQuery: {\n version: number;\n sha256Hash: string;\n };\n } & Record<string, unknown>;\n}\n\ntype GraphQLRequestPayload = GraphQLStandardRequest | GraphQLPersistedRequest;\n\ninterface GraphQLOperation {\n operationType?: string;\n operationName?: string;\n}\n\nconst INTEGRATION_NAME = 'GraphQLClient' as const;\n\nconst _graphqlClientIntegration = ((options: GraphQLClientOptions) => {\n return {\n name: INTEGRATION_NAME,\n setup(client: Client) {\n _updateSpanWithGraphQLData(client, options);\n _updateBreadcrumbWithGraphQLData(client, options);\n },\n };\n}) satisfies IntegrationFn;\n\nfunction _updateSpanWithGraphQLData(client: Client, options: GraphQLClientOptions): void {\n client.on('beforeOutgoingRequestSpan', (span, hint) => {\n const spanJSON = spanToJSON(span);\n\n const spanAttributes = spanJSON.data || {};\n const spanOp = spanAttributes[SEMANTIC_ATTRIBUTE_SENTRY_OP];\n\n const isHttpClientSpan = spanOp === 'http.client';\n\n if (!isHttpClientSpan) {\n return;\n }\n\n // Fall back to `url` because fetch instrumentation only sets `http.url` for absolute URLs;\n // relative URLs end up only in `url` (see `getFetchSpanAttributes` in packages/core/src/fetch.ts).\n const httpUrl = spanAttributes[SEMANTIC_ATTRIBUTE_URL_FULL] || spanAttributes['http.url'] || spanAttributes['url'];\n const httpMethod = spanAttributes[SEMANTIC_ATTRIBUTE_HTTP_REQUEST_METHOD] || spanAttributes['http.method'];\n\n if (!isString(httpUrl) || !isString(httpMethod)) {\n return;\n }\n\n const { endpoints } = options;\n const isTracedGraphqlEndpoint = stringMatchesSomePattern(httpUrl, endpoints);\n const payload = getRequestPayloadXhrOrFetch(hint as XhrHint | FetchHint);\n\n if (isTracedGraphqlEndpoint && payload) {\n const graphqlBody = getGraphQLRequestPayload(payload);\n\n if (graphqlBody) {\n const operationInfo = _getGraphQLOperation(graphqlBody);\n span.updateName(`${httpMethod} ${httpUrl} (${operationInfo})`);\n\n // Handle standard requests - capture the query document when enabled via dataCollection (default true)\n if (isStandardRequest(graphqlBody) && client.getDataCollectionOptions().graphQL.document === true) {\n span.setAttribute(GRAPHQL_DOCUMENT, graphqlBody.query);\n }\n\n // Handle persisted operations - capture hash for debugging\n if (isPersistedRequest(graphqlBody)) {\n span.setAttribute('graphql.persisted_query.hash.sha256', graphqlBody.extensions.persistedQuery.sha256Hash);\n span.setAttribute('graphql.persisted_query.version', graphqlBody.extensions.persistedQuery.version);\n }\n }\n }\n });\n}\n\nfunction _updateBreadcrumbWithGraphQLData(client: Client, options: GraphQLClientOptions): void {\n client.on('beforeOutgoingRequestBreadcrumb', (breadcrumb, handlerData) => {\n const { category, type, data } = breadcrumb;\n\n const isFetch = category === 'fetch';\n const isXhr = category === 'xhr';\n const isHttpBreadcrumb = type === 'http';\n\n if (isHttpBreadcrumb && (isFetch || isXhr)) {\n const httpUrl = data?.url;\n const { endpoints } = options;\n\n const isTracedGraphqlEndpoint = stringMatchesSomePattern(httpUrl, endpoints);\n const payload = getRequestPayloadXhrOrFetch(handlerData as XhrHint | FetchHint);\n\n if (isTracedGraphqlEndpoint && data && payload) {\n const graphqlBody = getGraphQLRequestPayload(payload);\n\n if (!data.graphql && graphqlBody) {\n const operationInfo = _getGraphQLOperation(graphqlBody);\n\n data['graphql.operation'] = operationInfo;\n\n if (isStandardRequest(graphqlBody) && client.getDataCollectionOptions().graphQL.document === true) {\n data[GRAPHQL_DOCUMENT] = graphqlBody.query;\n }\n\n if (isPersistedRequest(graphqlBody)) {\n data['graphql.persisted_query.hash.sha256'] = graphqlBody.extensions.persistedQuery.sha256Hash;\n data['graphql.persisted_query.version'] = graphqlBody.extensions.persistedQuery.version;\n }\n }\n }\n }\n });\n}\n\n/**\n * @param requestBody - GraphQL request\n * @returns A formatted version of the request: 'TYPE NAME' or 'TYPE' or 'persisted NAME'\n */\nexport function _getGraphQLOperation(requestBody: GraphQLRequestPayload): string {\n // Handle persisted operations\n if (isPersistedRequest(requestBody)) {\n return `persisted ${requestBody.operationName}`;\n }\n\n // Handle standard GraphQL requests\n if (isStandardRequest(requestBody)) {\n const { query: graphqlQuery, operationName: graphqlOperationName } = requestBody;\n const { operationName = graphqlOperationName, operationType } = parseGraphQLQuery(graphqlQuery);\n const operationInfo = operationName ? `${operationType} ${operationName}` : `${operationType}`;\n return operationInfo;\n }\n\n // Fallback for unknown request types\n return 'unknown';\n}\n\n/**\n * Get the request body/payload based on the shape of the hint.\n *\n * Exported for tests only.\n */\nexport function getRequestPayloadXhrOrFetch(hint: XhrHint | FetchHint): string | undefined {\n const isXhr = 'xhr' in hint;\n\n let body: string | undefined;\n\n if (isXhr) {\n const sentryXhrData = hint.xhr[SENTRY_XHR_DATA_KEY];\n body = sentryXhrData && getBodyString(sentryXhrData.body)[0];\n } else {\n const sentryFetchData = getFetchRequestArgBody(hint.input);\n body = getBodyString(sentryFetchData)[0];\n }\n\n return body;\n}\n\n/**\n * Extract the name and type of the operation from the GraphQL query.\n *\n * Exported for tests only.\n */\nexport function parseGraphQLQuery(query: string): GraphQLOperation {\n const namedQueryRe = /^(?:\\s*)(query|mutation|subscription)(?:\\s*)(\\w+)(?:\\s*)[{(]/;\n const unnamedQueryRe = /^(?:\\s*)(query|mutation|subscription)(?:\\s*)[{(]/;\n\n const namedMatch = query.match(namedQueryRe);\n if (namedMatch) {\n return {\n operationType: namedMatch[1],\n operationName: namedMatch[2],\n };\n }\n\n const unnamedMatch = query.match(unnamedQueryRe);\n if (unnamedMatch) {\n return {\n operationType: unnamedMatch[1],\n operationName: undefined,\n };\n }\n return {\n operationType: undefined,\n operationName: undefined,\n };\n}\n\n/**\n * Helper to safely check if a value is a non-null object\n */\n\n/**\n * Type guard to check if a request is a standard GraphQL request\n */\nfunction isStandardRequest(payload: unknown): payload is GraphQLStandardRequest {\n return isObjectLike(payload) && typeof payload.query === 'string';\n}\n\n/**\n * Type guard to check if a request is a persisted operation request\n */\nfunction isPersistedRequest(payload: unknown): payload is GraphQLPersistedRequest {\n return (\n isObjectLike(payload) &&\n typeof payload.operationName === 'string' &&\n isObjectLike(payload.extensions) &&\n isObjectLike(payload.extensions.persistedQuery) &&\n typeof payload.extensions.persistedQuery.sha256Hash === 'string' &&\n typeof payload.extensions.persistedQuery.version === 'number'\n );\n}\n\n/**\n * Extract the payload of a request if it's GraphQL.\n * Exported for tests only.\n * @param payload - A valid JSON string\n * @returns A POJO or undefined\n */\nexport function getGraphQLRequestPayload(payload: string): GraphQLRequestPayload | undefined {\n try {\n const requestBody = JSON.parse(payload);\n\n // Return any valid GraphQL request (standard, persisted, or APQ retry with both)\n if (isStandardRequest(requestBody) || isPersistedRequest(requestBody)) {\n return requestBody;\n }\n\n // Not a GraphQL request\n return undefined;\n } catch {\n // Invalid JSON\n return undefined;\n }\n}\n\n/**\n * This integration ensures that GraphQL requests made in the browser\n * have their GraphQL-specific data captured and attached to spans and breadcrumbs.\n */\nexport const graphqlClientIntegration = defineIntegration(_graphqlClientIntegration);\n"],"names":["spanToJSON","SEMANTIC_ATTRIBUTE_SENTRY_OP","SEMANTIC_ATTRIBUTE_URL_FULL","SEMANTIC_ATTRIBUTE_HTTP_REQUEST_METHOD","isString","stringMatchesSomePattern","GRAPHQL_DOCUMENT","SENTRY_XHR_DATA_KEY","getBodyString","getFetchRequestArgBody","isObjectLike","defineIntegration"],"mappings":"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"} |
@@ -184,2 +184,3 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); | ||
| }) : new browser.SentryNonRecordingSpan(); | ||
| const spanForTraceHeaders = browser.spanIsIgnored(span) && hasParent ? void 0 : span; | ||
| if (shouldCreateSpanResult && !shouldEmitSpan) { | ||
@@ -196,3 +197,3 @@ client?.recordDroppedEvent("no_parent_span", "span"); | ||
| // which means that the headers will be generated from the scope and the sampling decision is deferred | ||
| browser.hasSpansEnabled() && shouldEmitSpan ? span : void 0, | ||
| browser.hasSpansEnabled() && shouldEmitSpan ? spanForTraceHeaders : void 0, | ||
| propagateTraceparent | ||
@@ -199,0 +200,0 @@ ); |
@@ -1,1 +0,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/browser';\nimport {\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/browser';\nimport type { XhrHint } from '@sentry/browser-utils';\nimport {\n addPerformanceInstrumentationHandler,\n addXhrInstrumentationHandler,\n parseXhrResponseHeaders,\n resourceTimingToSpanAttributes,\n SENTRY_XHR_DATA_KEY,\n} from '@sentry/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 * @deprecated Use `fetchStreamPerformanceIntegration()` instead. Add it to your `integrations` array\n * to track the duration of streamed fetch response bodies.\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\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 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 addFetchInstrumentationHandler(handlerData => {\n const createdSpan = instrumentFetchRequest(handlerData, shouldCreateSpan, shouldAttachHeadersWithTargets, spans, {\n propagateTraceparent,\n onRequestSpanEnd,\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 const sanitizedFullUrl = fullUrl ? stripDataUrlContent(fullUrl) : undefined;\n createdSpan.setAttributes({\n 'http.url': sanitizedFullUrl,\n // `url.full` must match `http.url`. Setting it here ensures parentless `http.client`\n // segment spans don't get `url.full` backfilled with the host page URL (see httpContextIntegration).\n 'url.full': sanitizedFullUrl,\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 const sanitizedFullUrl = fullUrl ? stripDataUrlContent(fullUrl) : undefined;\n\n const urlForSpanName = stripDataUrlContent(stripUrlQueryAndFragment(url));\n\n const client = getClient();\n const hasParent = !!getActiveSpan();\n // With span streaming, we always emit http.client spans, even without a parent span\n const shouldEmitSpan = hasParent || (!!client && hasSpanStreamingEnabled(client));\n\n const span =\n shouldCreateSpanResult && shouldEmitSpan\n ? startInactiveSpan({\n name: `${method} ${urlForSpanName}`,\n attributes: {\n url: stripDataUrlContent(url),\n type: 'xhr',\n 'http.method': method,\n 'http.url': sanitizedFullUrl,\n // `url.full` must match `http.url`. Setting it here ensures parentless `http.client`\n // segment spans don't get `url.full` backfilled with the host page URL (see httpContextIntegration).\n 'url.full': sanitizedFullUrl,\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 if (shouldCreateSpanResult && !shouldEmitSpan) {\n client?.recordDroppedEvent('no_parent_span', 'span');\n }\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() && shouldEmitSpan ? span : undefined,\n propagateTraceparent,\n );\n }\n\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":["addFetchInstrumentationHandler","instrumentFetchRequest","getFullURL","parseUrl","stripDataUrlContent","addXhrInstrumentationHandler","createHeadersSafely","spanToJSON","hasSpanStreamingEnabled","timestampInSeconds","addPerformanceInstrumentationHandler","isPerformanceResourceTiming","resourceTimingToSpanAttributes","getLocationHref","stringMatchesSomePattern","shouldAttachHeaders","SENTRY_XHR_DATA_KEY","hasSpansEnabled","span","setHttpStatus","parseXhrResponseHeaders","stripUrlQueryAndFragment","getClient","getActiveSpan","startInactiveSpan","SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN","SEMANTIC_ATTRIBUTE_SENTRY_OP","SentryNonRecordingSpan","getTraceData","baggageHeaderHasSentryValues"],"mappings":"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"} | ||
| {"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/browser';\nimport {\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 spanIsIgnored,\n spanToJSON,\n startInactiveSpan,\n stringMatchesSomePattern,\n stripDataUrlContent,\n stripUrlQueryAndFragment,\n timestampInSeconds,\n} from '@sentry/core/browser';\nimport type { XhrHint } from '@sentry/browser-utils';\nimport {\n addPerformanceInstrumentationHandler,\n addXhrInstrumentationHandler,\n parseXhrResponseHeaders,\n resourceTimingToSpanAttributes,\n SENTRY_XHR_DATA_KEY,\n} from '@sentry/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 * @deprecated Use `fetchStreamPerformanceIntegration()` instead. Add it to your `integrations` array\n * to track the duration of streamed fetch response bodies.\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\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 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 addFetchInstrumentationHandler(handlerData => {\n const createdSpan = instrumentFetchRequest(handlerData, shouldCreateSpan, shouldAttachHeadersWithTargets, spans, {\n propagateTraceparent,\n onRequestSpanEnd,\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 const sanitizedFullUrl = fullUrl ? stripDataUrlContent(fullUrl) : undefined;\n createdSpan.setAttributes({\n 'http.url': sanitizedFullUrl,\n // `url.full` must match `http.url`. Setting it here ensures parentless `http.client`\n // segment spans don't get `url.full` backfilled with the host page URL (see httpContextIntegration).\n 'url.full': sanitizedFullUrl,\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 */\n// oxlint-disable-next-line complexity\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 const sanitizedFullUrl = fullUrl ? stripDataUrlContent(fullUrl) : undefined;\n\n const urlForSpanName = stripDataUrlContent(stripUrlQueryAndFragment(url));\n\n const client = getClient();\n const hasParent = !!getActiveSpan();\n // With span streaming, we always emit http.client spans, even without a parent span\n const shouldEmitSpan = hasParent || (!!client && hasSpanStreamingEnabled(client));\n\n const span =\n shouldCreateSpanResult && shouldEmitSpan\n ? startInactiveSpan({\n name: `${method} ${urlForSpanName}`,\n attributes: {\n url: stripDataUrlContent(url),\n type: 'xhr',\n 'http.method': method,\n 'http.url': sanitizedFullUrl,\n // `url.full` must match `http.url`. Setting it here ensures parentless `http.client`\n // segment spans don't get `url.full` backfilled with the host page URL (see httpContextIntegration).\n 'url.full': sanitizedFullUrl,\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 // If the span is ignored, we don't want to continue the trace from it (NonRecordingSpan) but rather\n // from the active span. Passing `undefined` here will make `getTraceData` use the active span instead.\n const spanForTraceHeaders = spanIsIgnored(span) && hasParent ? undefined : span;\n\n if (shouldCreateSpanResult && !shouldEmitSpan) {\n client?.recordDroppedEvent('no_parent_span', 'span');\n }\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() && shouldEmitSpan ? spanForTraceHeaders : undefined,\n propagateTraceparent,\n );\n }\n\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":["addFetchInstrumentationHandler","instrumentFetchRequest","getFullURL","parseUrl","stripDataUrlContent","addXhrInstrumentationHandler","createHeadersSafely","spanToJSON","hasSpanStreamingEnabled","timestampInSeconds","addPerformanceInstrumentationHandler","isPerformanceResourceTiming","resourceTimingToSpanAttributes","getLocationHref","stringMatchesSomePattern","shouldAttachHeaders","SENTRY_XHR_DATA_KEY","hasSpansEnabled","span","setHttpStatus","parseXhrResponseHeaders","stripUrlQueryAndFragment","getClient","getActiveSpan","startInactiveSpan","SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN","SEMANTIC_ATTRIBUTE_SENTRY_OP","SentryNonRecordingSpan","spanIsIgnored","getTraceData","baggageHeaderHasSentryValues"],"mappings":"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"} |
@@ -5,2 +5,3 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); | ||
| const browserUtils = require('@sentry/browser-utils'); | ||
| const attributes = require('@sentry/conventions/attributes'); | ||
@@ -39,4 +40,4 @@ const INTEGRATION_NAME = "GraphQLClient"; | ||
| span.updateName(`${httpMethod} ${httpUrl} (${operationInfo})`); | ||
| if (isStandardRequest(graphqlBody)) { | ||
| span.setAttribute("graphql.document", graphqlBody.query); | ||
| if (isStandardRequest(graphqlBody) && client.getDataCollectionOptions().graphQL.document === true) { | ||
| span.setAttribute(attributes.GRAPHQL_DOCUMENT, graphqlBody.query); | ||
| } | ||
@@ -67,4 +68,4 @@ if (isPersistedRequest(graphqlBody)) { | ||
| data["graphql.operation"] = operationInfo; | ||
| if (isStandardRequest(graphqlBody)) { | ||
| data["graphql.document"] = graphqlBody.query; | ||
| if (isStandardRequest(graphqlBody) && client.getDataCollectionOptions().graphQL.document === true) { | ||
| data[attributes.GRAPHQL_DOCUMENT] = graphqlBody.query; | ||
| } | ||
@@ -71,0 +72,0 @@ if (isPersistedRequest(graphqlBody)) { |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"graphqlClient.js","sources":["../../../../../src/integrations/graphqlClient.ts"],"sourcesContent":["import type { Client, IntegrationFn } from '@sentry/core/browser';\nimport {\n defineIntegration,\n isObjectLike,\n isString,\n SEMANTIC_ATTRIBUTE_HTTP_REQUEST_METHOD,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n SEMANTIC_ATTRIBUTE_URL_FULL,\n spanToJSON,\n stringMatchesSomePattern,\n} from '@sentry/core/browser';\nimport type { FetchHint, XhrHint } from '@sentry/browser-utils';\nimport { getBodyString, getFetchRequestArgBody, SENTRY_XHR_DATA_KEY } from '@sentry/browser-utils';\n\ninterface GraphQLClientOptions {\n endpoints: Array<string | RegExp>;\n}\n\n/** Standard graphql request shape: https://graphql.org/learn/serving-over-http/#post-request-and-body */\ninterface GraphQLStandardRequest {\n query: string;\n operationName?: string;\n variables?: Record<string, unknown>;\n extensions?: Record<string, unknown>;\n}\n\n/** Persisted operation request */\ninterface GraphQLPersistedRequest {\n operationName: string;\n variables?: Record<string, unknown>;\n extensions: {\n persistedQuery: {\n version: number;\n sha256Hash: string;\n };\n } & Record<string, unknown>;\n}\n\ntype GraphQLRequestPayload = GraphQLStandardRequest | GraphQLPersistedRequest;\n\ninterface GraphQLOperation {\n operationType?: string;\n operationName?: string;\n}\n\nconst INTEGRATION_NAME = 'GraphQLClient' as const;\n\nconst _graphqlClientIntegration = ((options: GraphQLClientOptions) => {\n return {\n name: INTEGRATION_NAME,\n setup(client: Client) {\n _updateSpanWithGraphQLData(client, options);\n _updateBreadcrumbWithGraphQLData(client, options);\n },\n };\n}) satisfies IntegrationFn;\n\nfunction _updateSpanWithGraphQLData(client: Client, options: GraphQLClientOptions): void {\n client.on('beforeOutgoingRequestSpan', (span, hint) => {\n const spanJSON = spanToJSON(span);\n\n const spanAttributes = spanJSON.data || {};\n const spanOp = spanAttributes[SEMANTIC_ATTRIBUTE_SENTRY_OP];\n\n const isHttpClientSpan = spanOp === 'http.client';\n\n if (!isHttpClientSpan) {\n return;\n }\n\n // Fall back to `url` because fetch instrumentation only sets `http.url` for absolute URLs;\n // relative URLs end up only in `url` (see `getFetchSpanAttributes` in packages/core/src/fetch.ts).\n const httpUrl = spanAttributes[SEMANTIC_ATTRIBUTE_URL_FULL] || spanAttributes['http.url'] || spanAttributes['url'];\n const httpMethod = spanAttributes[SEMANTIC_ATTRIBUTE_HTTP_REQUEST_METHOD] || spanAttributes['http.method'];\n\n if (!isString(httpUrl) || !isString(httpMethod)) {\n return;\n }\n\n const { endpoints } = options;\n const isTracedGraphqlEndpoint = stringMatchesSomePattern(httpUrl, endpoints);\n const payload = getRequestPayloadXhrOrFetch(hint as XhrHint | FetchHint);\n\n if (isTracedGraphqlEndpoint && payload) {\n const graphqlBody = getGraphQLRequestPayload(payload);\n\n if (graphqlBody) {\n const operationInfo = _getGraphQLOperation(graphqlBody);\n span.updateName(`${httpMethod} ${httpUrl} (${operationInfo})`);\n\n // Handle standard requests - always capture the query document\n if (isStandardRequest(graphqlBody)) {\n span.setAttribute('graphql.document', graphqlBody.query);\n }\n\n // Handle persisted operations - capture hash for debugging\n if (isPersistedRequest(graphqlBody)) {\n span.setAttribute('graphql.persisted_query.hash.sha256', graphqlBody.extensions.persistedQuery.sha256Hash);\n span.setAttribute('graphql.persisted_query.version', graphqlBody.extensions.persistedQuery.version);\n }\n }\n }\n });\n}\n\nfunction _updateBreadcrumbWithGraphQLData(client: Client, options: GraphQLClientOptions): void {\n client.on('beforeOutgoingRequestBreadcrumb', (breadcrumb, handlerData) => {\n const { category, type, data } = breadcrumb;\n\n const isFetch = category === 'fetch';\n const isXhr = category === 'xhr';\n const isHttpBreadcrumb = type === 'http';\n\n if (isHttpBreadcrumb && (isFetch || isXhr)) {\n const httpUrl = data?.url;\n const { endpoints } = options;\n\n const isTracedGraphqlEndpoint = stringMatchesSomePattern(httpUrl, endpoints);\n const payload = getRequestPayloadXhrOrFetch(handlerData as XhrHint | FetchHint);\n\n if (isTracedGraphqlEndpoint && data && payload) {\n const graphqlBody = getGraphQLRequestPayload(payload);\n\n if (!data.graphql && graphqlBody) {\n const operationInfo = _getGraphQLOperation(graphqlBody);\n\n data['graphql.operation'] = operationInfo;\n\n if (isStandardRequest(graphqlBody)) {\n data['graphql.document'] = graphqlBody.query;\n }\n\n if (isPersistedRequest(graphqlBody)) {\n data['graphql.persisted_query.hash.sha256'] = graphqlBody.extensions.persistedQuery.sha256Hash;\n data['graphql.persisted_query.version'] = graphqlBody.extensions.persistedQuery.version;\n }\n }\n }\n }\n });\n}\n\n/**\n * @param requestBody - GraphQL request\n * @returns A formatted version of the request: 'TYPE NAME' or 'TYPE' or 'persisted NAME'\n */\nexport function _getGraphQLOperation(requestBody: GraphQLRequestPayload): string {\n // Handle persisted operations\n if (isPersistedRequest(requestBody)) {\n return `persisted ${requestBody.operationName}`;\n }\n\n // Handle standard GraphQL requests\n if (isStandardRequest(requestBody)) {\n const { query: graphqlQuery, operationName: graphqlOperationName } = requestBody;\n const { operationName = graphqlOperationName, operationType } = parseGraphQLQuery(graphqlQuery);\n const operationInfo = operationName ? `${operationType} ${operationName}` : `${operationType}`;\n return operationInfo;\n }\n\n // Fallback for unknown request types\n return 'unknown';\n}\n\n/**\n * Get the request body/payload based on the shape of the hint.\n *\n * Exported for tests only.\n */\nexport function getRequestPayloadXhrOrFetch(hint: XhrHint | FetchHint): string | undefined {\n const isXhr = 'xhr' in hint;\n\n let body: string | undefined;\n\n if (isXhr) {\n const sentryXhrData = hint.xhr[SENTRY_XHR_DATA_KEY];\n body = sentryXhrData && getBodyString(sentryXhrData.body)[0];\n } else {\n const sentryFetchData = getFetchRequestArgBody(hint.input);\n body = getBodyString(sentryFetchData)[0];\n }\n\n return body;\n}\n\n/**\n * Extract the name and type of the operation from the GraphQL query.\n *\n * Exported for tests only.\n */\nexport function parseGraphQLQuery(query: string): GraphQLOperation {\n const namedQueryRe = /^(?:\\s*)(query|mutation|subscription)(?:\\s*)(\\w+)(?:\\s*)[{(]/;\n const unnamedQueryRe = /^(?:\\s*)(query|mutation|subscription)(?:\\s*)[{(]/;\n\n const namedMatch = query.match(namedQueryRe);\n if (namedMatch) {\n return {\n operationType: namedMatch[1],\n operationName: namedMatch[2],\n };\n }\n\n const unnamedMatch = query.match(unnamedQueryRe);\n if (unnamedMatch) {\n return {\n operationType: unnamedMatch[1],\n operationName: undefined,\n };\n }\n return {\n operationType: undefined,\n operationName: undefined,\n };\n}\n\n/**\n * Helper to safely check if a value is a non-null object\n */\n\n/**\n * Type guard to check if a request is a standard GraphQL request\n */\nfunction isStandardRequest(payload: unknown): payload is GraphQLStandardRequest {\n return isObjectLike(payload) && typeof payload.query === 'string';\n}\n\n/**\n * Type guard to check if a request is a persisted operation request\n */\nfunction isPersistedRequest(payload: unknown): payload is GraphQLPersistedRequest {\n return (\n isObjectLike(payload) &&\n typeof payload.operationName === 'string' &&\n isObjectLike(payload.extensions) &&\n isObjectLike(payload.extensions.persistedQuery) &&\n typeof payload.extensions.persistedQuery.sha256Hash === 'string' &&\n typeof payload.extensions.persistedQuery.version === 'number'\n );\n}\n\n/**\n * Extract the payload of a request if it's GraphQL.\n * Exported for tests only.\n * @param payload - A valid JSON string\n * @returns A POJO or undefined\n */\nexport function getGraphQLRequestPayload(payload: string): GraphQLRequestPayload | undefined {\n try {\n const requestBody = JSON.parse(payload);\n\n // Return any valid GraphQL request (standard, persisted, or APQ retry with both)\n if (isStandardRequest(requestBody) || isPersistedRequest(requestBody)) {\n return requestBody;\n }\n\n // Not a GraphQL request\n return undefined;\n } catch {\n // Invalid JSON\n return undefined;\n }\n}\n\n/**\n * This integration ensures that GraphQL requests made in the browser\n * have their GraphQL-specific data captured and attached to spans and breadcrumbs.\n */\nexport const graphqlClientIntegration = defineIntegration(_graphqlClientIntegration);\n"],"names":["spanToJSON","SEMANTIC_ATTRIBUTE_SENTRY_OP","SEMANTIC_ATTRIBUTE_URL_FULL","SEMANTIC_ATTRIBUTE_HTTP_REQUEST_METHOD","isString","stringMatchesSomePattern","SENTRY_XHR_DATA_KEY","getBodyString","getFetchRequestArgBody","isObjectLike","defineIntegration"],"mappings":"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"} | ||
| {"version":3,"file":"graphqlClient.js","sources":["../../../../../src/integrations/graphqlClient.ts"],"sourcesContent":["import type { Client, IntegrationFn } from '@sentry/core/browser';\nimport {\n defineIntegration,\n isObjectLike,\n isString,\n SEMANTIC_ATTRIBUTE_HTTP_REQUEST_METHOD,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n SEMANTIC_ATTRIBUTE_URL_FULL,\n spanToJSON,\n stringMatchesSomePattern,\n} from '@sentry/core/browser';\nimport type { FetchHint, XhrHint } from '@sentry/browser-utils';\nimport { getBodyString, getFetchRequestArgBody, SENTRY_XHR_DATA_KEY } from '@sentry/browser-utils';\nimport { GRAPHQL_DOCUMENT } from '@sentry/conventions/attributes';\n\ninterface GraphQLClientOptions {\n endpoints: Array<string | RegExp>;\n}\n\n/** Standard graphql request shape: https://graphql.org/learn/serving-over-http/#post-request-and-body */\ninterface GraphQLStandardRequest {\n query: string;\n operationName?: string;\n variables?: Record<string, unknown>;\n extensions?: Record<string, unknown>;\n}\n\n/** Persisted operation request */\ninterface GraphQLPersistedRequest {\n operationName: string;\n variables?: Record<string, unknown>;\n extensions: {\n persistedQuery: {\n version: number;\n sha256Hash: string;\n };\n } & Record<string, unknown>;\n}\n\ntype GraphQLRequestPayload = GraphQLStandardRequest | GraphQLPersistedRequest;\n\ninterface GraphQLOperation {\n operationType?: string;\n operationName?: string;\n}\n\nconst INTEGRATION_NAME = 'GraphQLClient' as const;\n\nconst _graphqlClientIntegration = ((options: GraphQLClientOptions) => {\n return {\n name: INTEGRATION_NAME,\n setup(client: Client) {\n _updateSpanWithGraphQLData(client, options);\n _updateBreadcrumbWithGraphQLData(client, options);\n },\n };\n}) satisfies IntegrationFn;\n\nfunction _updateSpanWithGraphQLData(client: Client, options: GraphQLClientOptions): void {\n client.on('beforeOutgoingRequestSpan', (span, hint) => {\n const spanJSON = spanToJSON(span);\n\n const spanAttributes = spanJSON.data || {};\n const spanOp = spanAttributes[SEMANTIC_ATTRIBUTE_SENTRY_OP];\n\n const isHttpClientSpan = spanOp === 'http.client';\n\n if (!isHttpClientSpan) {\n return;\n }\n\n // Fall back to `url` because fetch instrumentation only sets `http.url` for absolute URLs;\n // relative URLs end up only in `url` (see `getFetchSpanAttributes` in packages/core/src/fetch.ts).\n const httpUrl = spanAttributes[SEMANTIC_ATTRIBUTE_URL_FULL] || spanAttributes['http.url'] || spanAttributes['url'];\n const httpMethod = spanAttributes[SEMANTIC_ATTRIBUTE_HTTP_REQUEST_METHOD] || spanAttributes['http.method'];\n\n if (!isString(httpUrl) || !isString(httpMethod)) {\n return;\n }\n\n const { endpoints } = options;\n const isTracedGraphqlEndpoint = stringMatchesSomePattern(httpUrl, endpoints);\n const payload = getRequestPayloadXhrOrFetch(hint as XhrHint | FetchHint);\n\n if (isTracedGraphqlEndpoint && payload) {\n const graphqlBody = getGraphQLRequestPayload(payload);\n\n if (graphqlBody) {\n const operationInfo = _getGraphQLOperation(graphqlBody);\n span.updateName(`${httpMethod} ${httpUrl} (${operationInfo})`);\n\n // Handle standard requests - capture the query document when enabled via dataCollection (default true)\n if (isStandardRequest(graphqlBody) && client.getDataCollectionOptions().graphQL.document === true) {\n span.setAttribute(GRAPHQL_DOCUMENT, graphqlBody.query);\n }\n\n // Handle persisted operations - capture hash for debugging\n if (isPersistedRequest(graphqlBody)) {\n span.setAttribute('graphql.persisted_query.hash.sha256', graphqlBody.extensions.persistedQuery.sha256Hash);\n span.setAttribute('graphql.persisted_query.version', graphqlBody.extensions.persistedQuery.version);\n }\n }\n }\n });\n}\n\nfunction _updateBreadcrumbWithGraphQLData(client: Client, options: GraphQLClientOptions): void {\n client.on('beforeOutgoingRequestBreadcrumb', (breadcrumb, handlerData) => {\n const { category, type, data } = breadcrumb;\n\n const isFetch = category === 'fetch';\n const isXhr = category === 'xhr';\n const isHttpBreadcrumb = type === 'http';\n\n if (isHttpBreadcrumb && (isFetch || isXhr)) {\n const httpUrl = data?.url;\n const { endpoints } = options;\n\n const isTracedGraphqlEndpoint = stringMatchesSomePattern(httpUrl, endpoints);\n const payload = getRequestPayloadXhrOrFetch(handlerData as XhrHint | FetchHint);\n\n if (isTracedGraphqlEndpoint && data && payload) {\n const graphqlBody = getGraphQLRequestPayload(payload);\n\n if (!data.graphql && graphqlBody) {\n const operationInfo = _getGraphQLOperation(graphqlBody);\n\n data['graphql.operation'] = operationInfo;\n\n if (isStandardRequest(graphqlBody) && client.getDataCollectionOptions().graphQL.document === true) {\n data[GRAPHQL_DOCUMENT] = graphqlBody.query;\n }\n\n if (isPersistedRequest(graphqlBody)) {\n data['graphql.persisted_query.hash.sha256'] = graphqlBody.extensions.persistedQuery.sha256Hash;\n data['graphql.persisted_query.version'] = graphqlBody.extensions.persistedQuery.version;\n }\n }\n }\n }\n });\n}\n\n/**\n * @param requestBody - GraphQL request\n * @returns A formatted version of the request: 'TYPE NAME' or 'TYPE' or 'persisted NAME'\n */\nexport function _getGraphQLOperation(requestBody: GraphQLRequestPayload): string {\n // Handle persisted operations\n if (isPersistedRequest(requestBody)) {\n return `persisted ${requestBody.operationName}`;\n }\n\n // Handle standard GraphQL requests\n if (isStandardRequest(requestBody)) {\n const { query: graphqlQuery, operationName: graphqlOperationName } = requestBody;\n const { operationName = graphqlOperationName, operationType } = parseGraphQLQuery(graphqlQuery);\n const operationInfo = operationName ? `${operationType} ${operationName}` : `${operationType}`;\n return operationInfo;\n }\n\n // Fallback for unknown request types\n return 'unknown';\n}\n\n/**\n * Get the request body/payload based on the shape of the hint.\n *\n * Exported for tests only.\n */\nexport function getRequestPayloadXhrOrFetch(hint: XhrHint | FetchHint): string | undefined {\n const isXhr = 'xhr' in hint;\n\n let body: string | undefined;\n\n if (isXhr) {\n const sentryXhrData = hint.xhr[SENTRY_XHR_DATA_KEY];\n body = sentryXhrData && getBodyString(sentryXhrData.body)[0];\n } else {\n const sentryFetchData = getFetchRequestArgBody(hint.input);\n body = getBodyString(sentryFetchData)[0];\n }\n\n return body;\n}\n\n/**\n * Extract the name and type of the operation from the GraphQL query.\n *\n * Exported for tests only.\n */\nexport function parseGraphQLQuery(query: string): GraphQLOperation {\n const namedQueryRe = /^(?:\\s*)(query|mutation|subscription)(?:\\s*)(\\w+)(?:\\s*)[{(]/;\n const unnamedQueryRe = /^(?:\\s*)(query|mutation|subscription)(?:\\s*)[{(]/;\n\n const namedMatch = query.match(namedQueryRe);\n if (namedMatch) {\n return {\n operationType: namedMatch[1],\n operationName: namedMatch[2],\n };\n }\n\n const unnamedMatch = query.match(unnamedQueryRe);\n if (unnamedMatch) {\n return {\n operationType: unnamedMatch[1],\n operationName: undefined,\n };\n }\n return {\n operationType: undefined,\n operationName: undefined,\n };\n}\n\n/**\n * Helper to safely check if a value is a non-null object\n */\n\n/**\n * Type guard to check if a request is a standard GraphQL request\n */\nfunction isStandardRequest(payload: unknown): payload is GraphQLStandardRequest {\n return isObjectLike(payload) && typeof payload.query === 'string';\n}\n\n/**\n * Type guard to check if a request is a persisted operation request\n */\nfunction isPersistedRequest(payload: unknown): payload is GraphQLPersistedRequest {\n return (\n isObjectLike(payload) &&\n typeof payload.operationName === 'string' &&\n isObjectLike(payload.extensions) &&\n isObjectLike(payload.extensions.persistedQuery) &&\n typeof payload.extensions.persistedQuery.sha256Hash === 'string' &&\n typeof payload.extensions.persistedQuery.version === 'number'\n );\n}\n\n/**\n * Extract the payload of a request if it's GraphQL.\n * Exported for tests only.\n * @param payload - A valid JSON string\n * @returns A POJO or undefined\n */\nexport function getGraphQLRequestPayload(payload: string): GraphQLRequestPayload | undefined {\n try {\n const requestBody = JSON.parse(payload);\n\n // Return any valid GraphQL request (standard, persisted, or APQ retry with both)\n if (isStandardRequest(requestBody) || isPersistedRequest(requestBody)) {\n return requestBody;\n }\n\n // Not a GraphQL request\n return undefined;\n } catch {\n // Invalid JSON\n return undefined;\n }\n}\n\n/**\n * This integration ensures that GraphQL requests made in the browser\n * have their GraphQL-specific data captured and attached to spans and breadcrumbs.\n */\nexport const graphqlClientIntegration = defineIntegration(_graphqlClientIntegration);\n"],"names":["spanToJSON","SEMANTIC_ATTRIBUTE_SENTRY_OP","SEMANTIC_ATTRIBUTE_URL_FULL","SEMANTIC_ATTRIBUTE_HTTP_REQUEST_METHOD","isString","stringMatchesSomePattern","GRAPHQL_DOCUMENT","SENTRY_XHR_DATA_KEY","getBodyString","getFetchRequestArgBody","isObjectLike","defineIntegration"],"mappings":"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"} |
@@ -184,2 +184,3 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); | ||
| }) : new browser.SentryNonRecordingSpan(); | ||
| const spanForTraceHeaders = browser.spanIsIgnored(span) && hasParent ? void 0 : span; | ||
| if (shouldCreateSpanResult && !shouldEmitSpan) { | ||
@@ -196,3 +197,3 @@ client?.recordDroppedEvent("no_parent_span", "span"); | ||
| // which means that the headers will be generated from the scope and the sampling decision is deferred | ||
| browser.hasSpansEnabled() && shouldEmitSpan ? span : void 0, | ||
| browser.hasSpansEnabled() && shouldEmitSpan ? spanForTraceHeaders : void 0, | ||
| propagateTraceparent | ||
@@ -199,0 +200,0 @@ ); |
@@ -1,1 +0,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/browser';\nimport {\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/browser';\nimport type { XhrHint } from '@sentry/browser-utils';\nimport {\n addPerformanceInstrumentationHandler,\n addXhrInstrumentationHandler,\n parseXhrResponseHeaders,\n resourceTimingToSpanAttributes,\n SENTRY_XHR_DATA_KEY,\n} from '@sentry/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 * @deprecated Use `fetchStreamPerformanceIntegration()` instead. Add it to your `integrations` array\n * to track the duration of streamed fetch response bodies.\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\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 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 addFetchInstrumentationHandler(handlerData => {\n const createdSpan = instrumentFetchRequest(handlerData, shouldCreateSpan, shouldAttachHeadersWithTargets, spans, {\n propagateTraceparent,\n onRequestSpanEnd,\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 const sanitizedFullUrl = fullUrl ? stripDataUrlContent(fullUrl) : undefined;\n createdSpan.setAttributes({\n 'http.url': sanitizedFullUrl,\n // `url.full` must match `http.url`. Setting it here ensures parentless `http.client`\n // segment spans don't get `url.full` backfilled with the host page URL (see httpContextIntegration).\n 'url.full': sanitizedFullUrl,\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 const sanitizedFullUrl = fullUrl ? stripDataUrlContent(fullUrl) : undefined;\n\n const urlForSpanName = stripDataUrlContent(stripUrlQueryAndFragment(url));\n\n const client = getClient();\n const hasParent = !!getActiveSpan();\n // With span streaming, we always emit http.client spans, even without a parent span\n const shouldEmitSpan = hasParent || (!!client && hasSpanStreamingEnabled(client));\n\n const span =\n shouldCreateSpanResult && shouldEmitSpan\n ? startInactiveSpan({\n name: `${method} ${urlForSpanName}`,\n attributes: {\n url: stripDataUrlContent(url),\n type: 'xhr',\n 'http.method': method,\n 'http.url': sanitizedFullUrl,\n // `url.full` must match `http.url`. Setting it here ensures parentless `http.client`\n // segment spans don't get `url.full` backfilled with the host page URL (see httpContextIntegration).\n 'url.full': sanitizedFullUrl,\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 if (shouldCreateSpanResult && !shouldEmitSpan) {\n client?.recordDroppedEvent('no_parent_span', 'span');\n }\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() && shouldEmitSpan ? span : undefined,\n propagateTraceparent,\n );\n }\n\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":["addFetchInstrumentationHandler","instrumentFetchRequest","getFullURL","parseUrl","stripDataUrlContent","addXhrInstrumentationHandler","createHeadersSafely","spanToJSON","hasSpanStreamingEnabled","timestampInSeconds","addPerformanceInstrumentationHandler","isPerformanceResourceTiming","resourceTimingToSpanAttributes","getLocationHref","stringMatchesSomePattern","shouldAttachHeaders","SENTRY_XHR_DATA_KEY","hasSpansEnabled","span","setHttpStatus","parseXhrResponseHeaders","stripUrlQueryAndFragment","getClient","getActiveSpan","startInactiveSpan","SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN","SEMANTIC_ATTRIBUTE_SENTRY_OP","SentryNonRecordingSpan","getTraceData","baggageHeaderHasSentryValues"],"mappings":"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"} | ||
| {"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/browser';\nimport {\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 spanIsIgnored,\n spanToJSON,\n startInactiveSpan,\n stringMatchesSomePattern,\n stripDataUrlContent,\n stripUrlQueryAndFragment,\n timestampInSeconds,\n} from '@sentry/core/browser';\nimport type { XhrHint } from '@sentry/browser-utils';\nimport {\n addPerformanceInstrumentationHandler,\n addXhrInstrumentationHandler,\n parseXhrResponseHeaders,\n resourceTimingToSpanAttributes,\n SENTRY_XHR_DATA_KEY,\n} from '@sentry/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 * @deprecated Use `fetchStreamPerformanceIntegration()` instead. Add it to your `integrations` array\n * to track the duration of streamed fetch response bodies.\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\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 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 addFetchInstrumentationHandler(handlerData => {\n const createdSpan = instrumentFetchRequest(handlerData, shouldCreateSpan, shouldAttachHeadersWithTargets, spans, {\n propagateTraceparent,\n onRequestSpanEnd,\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 const sanitizedFullUrl = fullUrl ? stripDataUrlContent(fullUrl) : undefined;\n createdSpan.setAttributes({\n 'http.url': sanitizedFullUrl,\n // `url.full` must match `http.url`. Setting it here ensures parentless `http.client`\n // segment spans don't get `url.full` backfilled with the host page URL (see httpContextIntegration).\n 'url.full': sanitizedFullUrl,\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 */\n// oxlint-disable-next-line complexity\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 const sanitizedFullUrl = fullUrl ? stripDataUrlContent(fullUrl) : undefined;\n\n const urlForSpanName = stripDataUrlContent(stripUrlQueryAndFragment(url));\n\n const client = getClient();\n const hasParent = !!getActiveSpan();\n // With span streaming, we always emit http.client spans, even without a parent span\n const shouldEmitSpan = hasParent || (!!client && hasSpanStreamingEnabled(client));\n\n const span =\n shouldCreateSpanResult && shouldEmitSpan\n ? startInactiveSpan({\n name: `${method} ${urlForSpanName}`,\n attributes: {\n url: stripDataUrlContent(url),\n type: 'xhr',\n 'http.method': method,\n 'http.url': sanitizedFullUrl,\n // `url.full` must match `http.url`. Setting it here ensures parentless `http.client`\n // segment spans don't get `url.full` backfilled with the host page URL (see httpContextIntegration).\n 'url.full': sanitizedFullUrl,\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 // If the span is ignored, we don't want to continue the trace from it (NonRecordingSpan) but rather\n // from the active span. Passing `undefined` here will make `getTraceData` use the active span instead.\n const spanForTraceHeaders = spanIsIgnored(span) && hasParent ? undefined : span;\n\n if (shouldCreateSpanResult && !shouldEmitSpan) {\n client?.recordDroppedEvent('no_parent_span', 'span');\n }\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() && shouldEmitSpan ? spanForTraceHeaders : undefined,\n propagateTraceparent,\n );\n }\n\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":["addFetchInstrumentationHandler","instrumentFetchRequest","getFullURL","parseUrl","stripDataUrlContent","addXhrInstrumentationHandler","createHeadersSafely","spanToJSON","hasSpanStreamingEnabled","timestampInSeconds","addPerformanceInstrumentationHandler","isPerformanceResourceTiming","resourceTimingToSpanAttributes","getLocationHref","stringMatchesSomePattern","shouldAttachHeaders","SENTRY_XHR_DATA_KEY","hasSpansEnabled","span","setHttpStatus","parseXhrResponseHeaders","stripUrlQueryAndFragment","getClient","getActiveSpan","startInactiveSpan","SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN","SEMANTIC_ATTRIBUTE_SENTRY_OP","SentryNonRecordingSpan","spanIsIgnored","getTraceData","baggageHeaderHasSentryValues"],"mappings":"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"} |
| import { defineIntegration, spanToJSON, SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_URL_FULL, SEMANTIC_ATTRIBUTE_HTTP_REQUEST_METHOD, isString, stringMatchesSomePattern, isObjectLike } from '@sentry/core/browser'; | ||
| import { SENTRY_XHR_DATA_KEY, getBodyString, getFetchRequestArgBody } from '@sentry/browser-utils'; | ||
| import { GRAPHQL_DOCUMENT } from '@sentry/conventions/attributes'; | ||
@@ -36,4 +37,4 @@ const INTEGRATION_NAME = "GraphQLClient"; | ||
| span.updateName(`${httpMethod} ${httpUrl} (${operationInfo})`); | ||
| if (isStandardRequest(graphqlBody)) { | ||
| span.setAttribute("graphql.document", graphqlBody.query); | ||
| if (isStandardRequest(graphqlBody) && client.getDataCollectionOptions().graphQL.document === true) { | ||
| span.setAttribute(GRAPHQL_DOCUMENT, graphqlBody.query); | ||
| } | ||
@@ -64,4 +65,4 @@ if (isPersistedRequest(graphqlBody)) { | ||
| data["graphql.operation"] = operationInfo; | ||
| if (isStandardRequest(graphqlBody)) { | ||
| data["graphql.document"] = graphqlBody.query; | ||
| if (isStandardRequest(graphqlBody) && client.getDataCollectionOptions().graphQL.document === true) { | ||
| data[GRAPHQL_DOCUMENT] = graphqlBody.query; | ||
| } | ||
@@ -68,0 +69,0 @@ if (isPersistedRequest(graphqlBody)) { |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"graphqlClient.js","sources":["../../../../../src/integrations/graphqlClient.ts"],"sourcesContent":["import type { Client, IntegrationFn } from '@sentry/core/browser';\nimport {\n defineIntegration,\n isObjectLike,\n isString,\n SEMANTIC_ATTRIBUTE_HTTP_REQUEST_METHOD,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n SEMANTIC_ATTRIBUTE_URL_FULL,\n spanToJSON,\n stringMatchesSomePattern,\n} from '@sentry/core/browser';\nimport type { FetchHint, XhrHint } from '@sentry/browser-utils';\nimport { getBodyString, getFetchRequestArgBody, SENTRY_XHR_DATA_KEY } from '@sentry/browser-utils';\n\ninterface GraphQLClientOptions {\n endpoints: Array<string | RegExp>;\n}\n\n/** Standard graphql request shape: https://graphql.org/learn/serving-over-http/#post-request-and-body */\ninterface GraphQLStandardRequest {\n query: string;\n operationName?: string;\n variables?: Record<string, unknown>;\n extensions?: Record<string, unknown>;\n}\n\n/** Persisted operation request */\ninterface GraphQLPersistedRequest {\n operationName: string;\n variables?: Record<string, unknown>;\n extensions: {\n persistedQuery: {\n version: number;\n sha256Hash: string;\n };\n } & Record<string, unknown>;\n}\n\ntype GraphQLRequestPayload = GraphQLStandardRequest | GraphQLPersistedRequest;\n\ninterface GraphQLOperation {\n operationType?: string;\n operationName?: string;\n}\n\nconst INTEGRATION_NAME = 'GraphQLClient' as const;\n\nconst _graphqlClientIntegration = ((options: GraphQLClientOptions) => {\n return {\n name: INTEGRATION_NAME,\n setup(client: Client) {\n _updateSpanWithGraphQLData(client, options);\n _updateBreadcrumbWithGraphQLData(client, options);\n },\n };\n}) satisfies IntegrationFn;\n\nfunction _updateSpanWithGraphQLData(client: Client, options: GraphQLClientOptions): void {\n client.on('beforeOutgoingRequestSpan', (span, hint) => {\n const spanJSON = spanToJSON(span);\n\n const spanAttributes = spanJSON.data || {};\n const spanOp = spanAttributes[SEMANTIC_ATTRIBUTE_SENTRY_OP];\n\n const isHttpClientSpan = spanOp === 'http.client';\n\n if (!isHttpClientSpan) {\n return;\n }\n\n // Fall back to `url` because fetch instrumentation only sets `http.url` for absolute URLs;\n // relative URLs end up only in `url` (see `getFetchSpanAttributes` in packages/core/src/fetch.ts).\n const httpUrl = spanAttributes[SEMANTIC_ATTRIBUTE_URL_FULL] || spanAttributes['http.url'] || spanAttributes['url'];\n const httpMethod = spanAttributes[SEMANTIC_ATTRIBUTE_HTTP_REQUEST_METHOD] || spanAttributes['http.method'];\n\n if (!isString(httpUrl) || !isString(httpMethod)) {\n return;\n }\n\n const { endpoints } = options;\n const isTracedGraphqlEndpoint = stringMatchesSomePattern(httpUrl, endpoints);\n const payload = getRequestPayloadXhrOrFetch(hint as XhrHint | FetchHint);\n\n if (isTracedGraphqlEndpoint && payload) {\n const graphqlBody = getGraphQLRequestPayload(payload);\n\n if (graphqlBody) {\n const operationInfo = _getGraphQLOperation(graphqlBody);\n span.updateName(`${httpMethod} ${httpUrl} (${operationInfo})`);\n\n // Handle standard requests - always capture the query document\n if (isStandardRequest(graphqlBody)) {\n span.setAttribute('graphql.document', graphqlBody.query);\n }\n\n // Handle persisted operations - capture hash for debugging\n if (isPersistedRequest(graphqlBody)) {\n span.setAttribute('graphql.persisted_query.hash.sha256', graphqlBody.extensions.persistedQuery.sha256Hash);\n span.setAttribute('graphql.persisted_query.version', graphqlBody.extensions.persistedQuery.version);\n }\n }\n }\n });\n}\n\nfunction _updateBreadcrumbWithGraphQLData(client: Client, options: GraphQLClientOptions): void {\n client.on('beforeOutgoingRequestBreadcrumb', (breadcrumb, handlerData) => {\n const { category, type, data } = breadcrumb;\n\n const isFetch = category === 'fetch';\n const isXhr = category === 'xhr';\n const isHttpBreadcrumb = type === 'http';\n\n if (isHttpBreadcrumb && (isFetch || isXhr)) {\n const httpUrl = data?.url;\n const { endpoints } = options;\n\n const isTracedGraphqlEndpoint = stringMatchesSomePattern(httpUrl, endpoints);\n const payload = getRequestPayloadXhrOrFetch(handlerData as XhrHint | FetchHint);\n\n if (isTracedGraphqlEndpoint && data && payload) {\n const graphqlBody = getGraphQLRequestPayload(payload);\n\n if (!data.graphql && graphqlBody) {\n const operationInfo = _getGraphQLOperation(graphqlBody);\n\n data['graphql.operation'] = operationInfo;\n\n if (isStandardRequest(graphqlBody)) {\n data['graphql.document'] = graphqlBody.query;\n }\n\n if (isPersistedRequest(graphqlBody)) {\n data['graphql.persisted_query.hash.sha256'] = graphqlBody.extensions.persistedQuery.sha256Hash;\n data['graphql.persisted_query.version'] = graphqlBody.extensions.persistedQuery.version;\n }\n }\n }\n }\n });\n}\n\n/**\n * @param requestBody - GraphQL request\n * @returns A formatted version of the request: 'TYPE NAME' or 'TYPE' or 'persisted NAME'\n */\nexport function _getGraphQLOperation(requestBody: GraphQLRequestPayload): string {\n // Handle persisted operations\n if (isPersistedRequest(requestBody)) {\n return `persisted ${requestBody.operationName}`;\n }\n\n // Handle standard GraphQL requests\n if (isStandardRequest(requestBody)) {\n const { query: graphqlQuery, operationName: graphqlOperationName } = requestBody;\n const { operationName = graphqlOperationName, operationType } = parseGraphQLQuery(graphqlQuery);\n const operationInfo = operationName ? `${operationType} ${operationName}` : `${operationType}`;\n return operationInfo;\n }\n\n // Fallback for unknown request types\n return 'unknown';\n}\n\n/**\n * Get the request body/payload based on the shape of the hint.\n *\n * Exported for tests only.\n */\nexport function getRequestPayloadXhrOrFetch(hint: XhrHint | FetchHint): string | undefined {\n const isXhr = 'xhr' in hint;\n\n let body: string | undefined;\n\n if (isXhr) {\n const sentryXhrData = hint.xhr[SENTRY_XHR_DATA_KEY];\n body = sentryXhrData && getBodyString(sentryXhrData.body)[0];\n } else {\n const sentryFetchData = getFetchRequestArgBody(hint.input);\n body = getBodyString(sentryFetchData)[0];\n }\n\n return body;\n}\n\n/**\n * Extract the name and type of the operation from the GraphQL query.\n *\n * Exported for tests only.\n */\nexport function parseGraphQLQuery(query: string): GraphQLOperation {\n const namedQueryRe = /^(?:\\s*)(query|mutation|subscription)(?:\\s*)(\\w+)(?:\\s*)[{(]/;\n const unnamedQueryRe = /^(?:\\s*)(query|mutation|subscription)(?:\\s*)[{(]/;\n\n const namedMatch = query.match(namedQueryRe);\n if (namedMatch) {\n return {\n operationType: namedMatch[1],\n operationName: namedMatch[2],\n };\n }\n\n const unnamedMatch = query.match(unnamedQueryRe);\n if (unnamedMatch) {\n return {\n operationType: unnamedMatch[1],\n operationName: undefined,\n };\n }\n return {\n operationType: undefined,\n operationName: undefined,\n };\n}\n\n/**\n * Helper to safely check if a value is a non-null object\n */\n\n/**\n * Type guard to check if a request is a standard GraphQL request\n */\nfunction isStandardRequest(payload: unknown): payload is GraphQLStandardRequest {\n return isObjectLike(payload) && typeof payload.query === 'string';\n}\n\n/**\n * Type guard to check if a request is a persisted operation request\n */\nfunction isPersistedRequest(payload: unknown): payload is GraphQLPersistedRequest {\n return (\n isObjectLike(payload) &&\n typeof payload.operationName === 'string' &&\n isObjectLike(payload.extensions) &&\n isObjectLike(payload.extensions.persistedQuery) &&\n typeof payload.extensions.persistedQuery.sha256Hash === 'string' &&\n typeof payload.extensions.persistedQuery.version === 'number'\n );\n}\n\n/**\n * Extract the payload of a request if it's GraphQL.\n * Exported for tests only.\n * @param payload - A valid JSON string\n * @returns A POJO or undefined\n */\nexport function getGraphQLRequestPayload(payload: string): GraphQLRequestPayload | undefined {\n try {\n const requestBody = JSON.parse(payload);\n\n // Return any valid GraphQL request (standard, persisted, or APQ retry with both)\n if (isStandardRequest(requestBody) || isPersistedRequest(requestBody)) {\n return requestBody;\n }\n\n // Not a GraphQL request\n return undefined;\n } catch {\n // Invalid JSON\n return undefined;\n }\n}\n\n/**\n * This integration ensures that GraphQL requests made in the browser\n * have their GraphQL-specific data captured and attached to spans and breadcrumbs.\n */\nexport const graphqlClientIntegration = defineIntegration(_graphqlClientIntegration);\n"],"names":[],"mappings":"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"} | ||
| {"version":3,"file":"graphqlClient.js","sources":["../../../../../src/integrations/graphqlClient.ts"],"sourcesContent":["import type { Client, IntegrationFn } from '@sentry/core/browser';\nimport {\n defineIntegration,\n isObjectLike,\n isString,\n SEMANTIC_ATTRIBUTE_HTTP_REQUEST_METHOD,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n SEMANTIC_ATTRIBUTE_URL_FULL,\n spanToJSON,\n stringMatchesSomePattern,\n} from '@sentry/core/browser';\nimport type { FetchHint, XhrHint } from '@sentry/browser-utils';\nimport { getBodyString, getFetchRequestArgBody, SENTRY_XHR_DATA_KEY } from '@sentry/browser-utils';\nimport { GRAPHQL_DOCUMENT } from '@sentry/conventions/attributes';\n\ninterface GraphQLClientOptions {\n endpoints: Array<string | RegExp>;\n}\n\n/** Standard graphql request shape: https://graphql.org/learn/serving-over-http/#post-request-and-body */\ninterface GraphQLStandardRequest {\n query: string;\n operationName?: string;\n variables?: Record<string, unknown>;\n extensions?: Record<string, unknown>;\n}\n\n/** Persisted operation request */\ninterface GraphQLPersistedRequest {\n operationName: string;\n variables?: Record<string, unknown>;\n extensions: {\n persistedQuery: {\n version: number;\n sha256Hash: string;\n };\n } & Record<string, unknown>;\n}\n\ntype GraphQLRequestPayload = GraphQLStandardRequest | GraphQLPersistedRequest;\n\ninterface GraphQLOperation {\n operationType?: string;\n operationName?: string;\n}\n\nconst INTEGRATION_NAME = 'GraphQLClient' as const;\n\nconst _graphqlClientIntegration = ((options: GraphQLClientOptions) => {\n return {\n name: INTEGRATION_NAME,\n setup(client: Client) {\n _updateSpanWithGraphQLData(client, options);\n _updateBreadcrumbWithGraphQLData(client, options);\n },\n };\n}) satisfies IntegrationFn;\n\nfunction _updateSpanWithGraphQLData(client: Client, options: GraphQLClientOptions): void {\n client.on('beforeOutgoingRequestSpan', (span, hint) => {\n const spanJSON = spanToJSON(span);\n\n const spanAttributes = spanJSON.data || {};\n const spanOp = spanAttributes[SEMANTIC_ATTRIBUTE_SENTRY_OP];\n\n const isHttpClientSpan = spanOp === 'http.client';\n\n if (!isHttpClientSpan) {\n return;\n }\n\n // Fall back to `url` because fetch instrumentation only sets `http.url` for absolute URLs;\n // relative URLs end up only in `url` (see `getFetchSpanAttributes` in packages/core/src/fetch.ts).\n const httpUrl = spanAttributes[SEMANTIC_ATTRIBUTE_URL_FULL] || spanAttributes['http.url'] || spanAttributes['url'];\n const httpMethod = spanAttributes[SEMANTIC_ATTRIBUTE_HTTP_REQUEST_METHOD] || spanAttributes['http.method'];\n\n if (!isString(httpUrl) || !isString(httpMethod)) {\n return;\n }\n\n const { endpoints } = options;\n const isTracedGraphqlEndpoint = stringMatchesSomePattern(httpUrl, endpoints);\n const payload = getRequestPayloadXhrOrFetch(hint as XhrHint | FetchHint);\n\n if (isTracedGraphqlEndpoint && payload) {\n const graphqlBody = getGraphQLRequestPayload(payload);\n\n if (graphqlBody) {\n const operationInfo = _getGraphQLOperation(graphqlBody);\n span.updateName(`${httpMethod} ${httpUrl} (${operationInfo})`);\n\n // Handle standard requests - capture the query document when enabled via dataCollection (default true)\n if (isStandardRequest(graphqlBody) && client.getDataCollectionOptions().graphQL.document === true) {\n span.setAttribute(GRAPHQL_DOCUMENT, graphqlBody.query);\n }\n\n // Handle persisted operations - capture hash for debugging\n if (isPersistedRequest(graphqlBody)) {\n span.setAttribute('graphql.persisted_query.hash.sha256', graphqlBody.extensions.persistedQuery.sha256Hash);\n span.setAttribute('graphql.persisted_query.version', graphqlBody.extensions.persistedQuery.version);\n }\n }\n }\n });\n}\n\nfunction _updateBreadcrumbWithGraphQLData(client: Client, options: GraphQLClientOptions): void {\n client.on('beforeOutgoingRequestBreadcrumb', (breadcrumb, handlerData) => {\n const { category, type, data } = breadcrumb;\n\n const isFetch = category === 'fetch';\n const isXhr = category === 'xhr';\n const isHttpBreadcrumb = type === 'http';\n\n if (isHttpBreadcrumb && (isFetch || isXhr)) {\n const httpUrl = data?.url;\n const { endpoints } = options;\n\n const isTracedGraphqlEndpoint = stringMatchesSomePattern(httpUrl, endpoints);\n const payload = getRequestPayloadXhrOrFetch(handlerData as XhrHint | FetchHint);\n\n if (isTracedGraphqlEndpoint && data && payload) {\n const graphqlBody = getGraphQLRequestPayload(payload);\n\n if (!data.graphql && graphqlBody) {\n const operationInfo = _getGraphQLOperation(graphqlBody);\n\n data['graphql.operation'] = operationInfo;\n\n if (isStandardRequest(graphqlBody) && client.getDataCollectionOptions().graphQL.document === true) {\n data[GRAPHQL_DOCUMENT] = graphqlBody.query;\n }\n\n if (isPersistedRequest(graphqlBody)) {\n data['graphql.persisted_query.hash.sha256'] = graphqlBody.extensions.persistedQuery.sha256Hash;\n data['graphql.persisted_query.version'] = graphqlBody.extensions.persistedQuery.version;\n }\n }\n }\n }\n });\n}\n\n/**\n * @param requestBody - GraphQL request\n * @returns A formatted version of the request: 'TYPE NAME' or 'TYPE' or 'persisted NAME'\n */\nexport function _getGraphQLOperation(requestBody: GraphQLRequestPayload): string {\n // Handle persisted operations\n if (isPersistedRequest(requestBody)) {\n return `persisted ${requestBody.operationName}`;\n }\n\n // Handle standard GraphQL requests\n if (isStandardRequest(requestBody)) {\n const { query: graphqlQuery, operationName: graphqlOperationName } = requestBody;\n const { operationName = graphqlOperationName, operationType } = parseGraphQLQuery(graphqlQuery);\n const operationInfo = operationName ? `${operationType} ${operationName}` : `${operationType}`;\n return operationInfo;\n }\n\n // Fallback for unknown request types\n return 'unknown';\n}\n\n/**\n * Get the request body/payload based on the shape of the hint.\n *\n * Exported for tests only.\n */\nexport function getRequestPayloadXhrOrFetch(hint: XhrHint | FetchHint): string | undefined {\n const isXhr = 'xhr' in hint;\n\n let body: string | undefined;\n\n if (isXhr) {\n const sentryXhrData = hint.xhr[SENTRY_XHR_DATA_KEY];\n body = sentryXhrData && getBodyString(sentryXhrData.body)[0];\n } else {\n const sentryFetchData = getFetchRequestArgBody(hint.input);\n body = getBodyString(sentryFetchData)[0];\n }\n\n return body;\n}\n\n/**\n * Extract the name and type of the operation from the GraphQL query.\n *\n * Exported for tests only.\n */\nexport function parseGraphQLQuery(query: string): GraphQLOperation {\n const namedQueryRe = /^(?:\\s*)(query|mutation|subscription)(?:\\s*)(\\w+)(?:\\s*)[{(]/;\n const unnamedQueryRe = /^(?:\\s*)(query|mutation|subscription)(?:\\s*)[{(]/;\n\n const namedMatch = query.match(namedQueryRe);\n if (namedMatch) {\n return {\n operationType: namedMatch[1],\n operationName: namedMatch[2],\n };\n }\n\n const unnamedMatch = query.match(unnamedQueryRe);\n if (unnamedMatch) {\n return {\n operationType: unnamedMatch[1],\n operationName: undefined,\n };\n }\n return {\n operationType: undefined,\n operationName: undefined,\n };\n}\n\n/**\n * Helper to safely check if a value is a non-null object\n */\n\n/**\n * Type guard to check if a request is a standard GraphQL request\n */\nfunction isStandardRequest(payload: unknown): payload is GraphQLStandardRequest {\n return isObjectLike(payload) && typeof payload.query === 'string';\n}\n\n/**\n * Type guard to check if a request is a persisted operation request\n */\nfunction isPersistedRequest(payload: unknown): payload is GraphQLPersistedRequest {\n return (\n isObjectLike(payload) &&\n typeof payload.operationName === 'string' &&\n isObjectLike(payload.extensions) &&\n isObjectLike(payload.extensions.persistedQuery) &&\n typeof payload.extensions.persistedQuery.sha256Hash === 'string' &&\n typeof payload.extensions.persistedQuery.version === 'number'\n );\n}\n\n/**\n * Extract the payload of a request if it's GraphQL.\n * Exported for tests only.\n * @param payload - A valid JSON string\n * @returns A POJO or undefined\n */\nexport function getGraphQLRequestPayload(payload: string): GraphQLRequestPayload | undefined {\n try {\n const requestBody = JSON.parse(payload);\n\n // Return any valid GraphQL request (standard, persisted, or APQ retry with both)\n if (isStandardRequest(requestBody) || isPersistedRequest(requestBody)) {\n return requestBody;\n }\n\n // Not a GraphQL request\n return undefined;\n } catch {\n // Invalid JSON\n return undefined;\n }\n}\n\n/**\n * This integration ensures that GraphQL requests made in the browser\n * have their GraphQL-specific data captured and attached to spans and breadcrumbs.\n */\nexport const graphqlClientIntegration = defineIntegration(_graphqlClientIntegration);\n"],"names":[],"mappings":"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"} |
@@ -1,1 +0,1 @@ | ||
| {"type":"module","version":"10.65.0","sideEffects":false} | ||
| {"type":"module","version":"10.66.0","sideEffects":false} |
@@ -1,2 +0,2 @@ | ||
| import { addFetchInstrumentationHandler, instrumentFetchRequest, parseUrl, stripDataUrlContent, spanToJSON, hasSpanStreamingEnabled, timestampInSeconds, hasSpansEnabled, setHttpStatus, stripUrlQueryAndFragment, getClient, getActiveSpan, startInactiveSpan, SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, SentryNonRecordingSpan, getLocationHref, stringMatchesSomePattern, getTraceData } from '@sentry/core/browser'; | ||
| import { addFetchInstrumentationHandler, instrumentFetchRequest, parseUrl, stripDataUrlContent, spanToJSON, hasSpanStreamingEnabled, timestampInSeconds, hasSpansEnabled, setHttpStatus, stripUrlQueryAndFragment, getClient, getActiveSpan, startInactiveSpan, SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, SentryNonRecordingSpan, spanIsIgnored, getLocationHref, stringMatchesSomePattern, getTraceData } from '@sentry/core/browser'; | ||
| import { addXhrInstrumentationHandler, addPerformanceInstrumentationHandler, resourceTimingToSpanAttributes, SENTRY_XHR_DATA_KEY, parseXhrResponseHeaders } from '@sentry/browser-utils'; | ||
@@ -182,2 +182,3 @@ import { getFullURL, createHeadersSafely, isPerformanceResourceTiming, baggageHeaderHasSentryValues } from './utils.js'; | ||
| }) : new SentryNonRecordingSpan(); | ||
| const spanForTraceHeaders = spanIsIgnored(span) && hasParent ? void 0 : span; | ||
| if (shouldCreateSpanResult && !shouldEmitSpan) { | ||
@@ -194,3 +195,3 @@ client?.recordDroppedEvent("no_parent_span", "span"); | ||
| // which means that the headers will be generated from the scope and the sampling decision is deferred | ||
| hasSpansEnabled() && shouldEmitSpan ? span : void 0, | ||
| hasSpansEnabled() && shouldEmitSpan ? spanForTraceHeaders : void 0, | ||
| propagateTraceparent | ||
@@ -197,0 +198,0 @@ ); |
@@ -1,1 +0,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/browser';\nimport {\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/browser';\nimport type { XhrHint } from '@sentry/browser-utils';\nimport {\n addPerformanceInstrumentationHandler,\n addXhrInstrumentationHandler,\n parseXhrResponseHeaders,\n resourceTimingToSpanAttributes,\n SENTRY_XHR_DATA_KEY,\n} from '@sentry/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 * @deprecated Use `fetchStreamPerformanceIntegration()` instead. Add it to your `integrations` array\n * to track the duration of streamed fetch response bodies.\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\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 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 addFetchInstrumentationHandler(handlerData => {\n const createdSpan = instrumentFetchRequest(handlerData, shouldCreateSpan, shouldAttachHeadersWithTargets, spans, {\n propagateTraceparent,\n onRequestSpanEnd,\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 const sanitizedFullUrl = fullUrl ? stripDataUrlContent(fullUrl) : undefined;\n createdSpan.setAttributes({\n 'http.url': sanitizedFullUrl,\n // `url.full` must match `http.url`. Setting it here ensures parentless `http.client`\n // segment spans don't get `url.full` backfilled with the host page URL (see httpContextIntegration).\n 'url.full': sanitizedFullUrl,\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 const sanitizedFullUrl = fullUrl ? stripDataUrlContent(fullUrl) : undefined;\n\n const urlForSpanName = stripDataUrlContent(stripUrlQueryAndFragment(url));\n\n const client = getClient();\n const hasParent = !!getActiveSpan();\n // With span streaming, we always emit http.client spans, even without a parent span\n const shouldEmitSpan = hasParent || (!!client && hasSpanStreamingEnabled(client));\n\n const span =\n shouldCreateSpanResult && shouldEmitSpan\n ? startInactiveSpan({\n name: `${method} ${urlForSpanName}`,\n attributes: {\n url: stripDataUrlContent(url),\n type: 'xhr',\n 'http.method': method,\n 'http.url': sanitizedFullUrl,\n // `url.full` must match `http.url`. Setting it here ensures parentless `http.client`\n // segment spans don't get `url.full` backfilled with the host page URL (see httpContextIntegration).\n 'url.full': sanitizedFullUrl,\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 if (shouldCreateSpanResult && !shouldEmitSpan) {\n client?.recordDroppedEvent('no_parent_span', 'span');\n }\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() && shouldEmitSpan ? span : undefined,\n propagateTraceparent,\n );\n }\n\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":["shouldAttachHeaders","span"],"mappings":"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"} | ||
| {"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/browser';\nimport {\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 spanIsIgnored,\n spanToJSON,\n startInactiveSpan,\n stringMatchesSomePattern,\n stripDataUrlContent,\n stripUrlQueryAndFragment,\n timestampInSeconds,\n} from '@sentry/core/browser';\nimport type { XhrHint } from '@sentry/browser-utils';\nimport {\n addPerformanceInstrumentationHandler,\n addXhrInstrumentationHandler,\n parseXhrResponseHeaders,\n resourceTimingToSpanAttributes,\n SENTRY_XHR_DATA_KEY,\n} from '@sentry/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 * @deprecated Use `fetchStreamPerformanceIntegration()` instead. Add it to your `integrations` array\n * to track the duration of streamed fetch response bodies.\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\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 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 addFetchInstrumentationHandler(handlerData => {\n const createdSpan = instrumentFetchRequest(handlerData, shouldCreateSpan, shouldAttachHeadersWithTargets, spans, {\n propagateTraceparent,\n onRequestSpanEnd,\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 const sanitizedFullUrl = fullUrl ? stripDataUrlContent(fullUrl) : undefined;\n createdSpan.setAttributes({\n 'http.url': sanitizedFullUrl,\n // `url.full` must match `http.url`. Setting it here ensures parentless `http.client`\n // segment spans don't get `url.full` backfilled with the host page URL (see httpContextIntegration).\n 'url.full': sanitizedFullUrl,\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 */\n// oxlint-disable-next-line complexity\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 const sanitizedFullUrl = fullUrl ? stripDataUrlContent(fullUrl) : undefined;\n\n const urlForSpanName = stripDataUrlContent(stripUrlQueryAndFragment(url));\n\n const client = getClient();\n const hasParent = !!getActiveSpan();\n // With span streaming, we always emit http.client spans, even without a parent span\n const shouldEmitSpan = hasParent || (!!client && hasSpanStreamingEnabled(client));\n\n const span =\n shouldCreateSpanResult && shouldEmitSpan\n ? startInactiveSpan({\n name: `${method} ${urlForSpanName}`,\n attributes: {\n url: stripDataUrlContent(url),\n type: 'xhr',\n 'http.method': method,\n 'http.url': sanitizedFullUrl,\n // `url.full` must match `http.url`. Setting it here ensures parentless `http.client`\n // segment spans don't get `url.full` backfilled with the host page URL (see httpContextIntegration).\n 'url.full': sanitizedFullUrl,\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 // If the span is ignored, we don't want to continue the trace from it (NonRecordingSpan) but rather\n // from the active span. Passing `undefined` here will make `getTraceData` use the active span instead.\n const spanForTraceHeaders = spanIsIgnored(span) && hasParent ? undefined : span;\n\n if (shouldCreateSpanResult && !shouldEmitSpan) {\n client?.recordDroppedEvent('no_parent_span', 'span');\n }\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() && shouldEmitSpan ? spanForTraceHeaders : undefined,\n propagateTraceparent,\n );\n }\n\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":["shouldAttachHeaders","span"],"mappings":"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"} |
| import { defineIntegration, spanToJSON, SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_URL_FULL, SEMANTIC_ATTRIBUTE_HTTP_REQUEST_METHOD, isString, stringMatchesSomePattern, isObjectLike } from '@sentry/core/browser'; | ||
| import { SENTRY_XHR_DATA_KEY, getBodyString, getFetchRequestArgBody } from '@sentry/browser-utils'; | ||
| import { GRAPHQL_DOCUMENT } from '@sentry/conventions/attributes'; | ||
@@ -36,4 +37,4 @@ const INTEGRATION_NAME = "GraphQLClient"; | ||
| span.updateName(`${httpMethod} ${httpUrl} (${operationInfo})`); | ||
| if (isStandardRequest(graphqlBody)) { | ||
| span.setAttribute("graphql.document", graphqlBody.query); | ||
| if (isStandardRequest(graphqlBody) && client.getDataCollectionOptions().graphQL.document === true) { | ||
| span.setAttribute(GRAPHQL_DOCUMENT, graphqlBody.query); | ||
| } | ||
@@ -64,4 +65,4 @@ if (isPersistedRequest(graphqlBody)) { | ||
| data["graphql.operation"] = operationInfo; | ||
| if (isStandardRequest(graphqlBody)) { | ||
| data["graphql.document"] = graphqlBody.query; | ||
| if (isStandardRequest(graphqlBody) && client.getDataCollectionOptions().graphQL.document === true) { | ||
| data[GRAPHQL_DOCUMENT] = graphqlBody.query; | ||
| } | ||
@@ -68,0 +69,0 @@ if (isPersistedRequest(graphqlBody)) { |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"graphqlClient.js","sources":["../../../../../src/integrations/graphqlClient.ts"],"sourcesContent":["import type { Client, IntegrationFn } from '@sentry/core/browser';\nimport {\n defineIntegration,\n isObjectLike,\n isString,\n SEMANTIC_ATTRIBUTE_HTTP_REQUEST_METHOD,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n SEMANTIC_ATTRIBUTE_URL_FULL,\n spanToJSON,\n stringMatchesSomePattern,\n} from '@sentry/core/browser';\nimport type { FetchHint, XhrHint } from '@sentry/browser-utils';\nimport { getBodyString, getFetchRequestArgBody, SENTRY_XHR_DATA_KEY } from '@sentry/browser-utils';\n\ninterface GraphQLClientOptions {\n endpoints: Array<string | RegExp>;\n}\n\n/** Standard graphql request shape: https://graphql.org/learn/serving-over-http/#post-request-and-body */\ninterface GraphQLStandardRequest {\n query: string;\n operationName?: string;\n variables?: Record<string, unknown>;\n extensions?: Record<string, unknown>;\n}\n\n/** Persisted operation request */\ninterface GraphQLPersistedRequest {\n operationName: string;\n variables?: Record<string, unknown>;\n extensions: {\n persistedQuery: {\n version: number;\n sha256Hash: string;\n };\n } & Record<string, unknown>;\n}\n\ntype GraphQLRequestPayload = GraphQLStandardRequest | GraphQLPersistedRequest;\n\ninterface GraphQLOperation {\n operationType?: string;\n operationName?: string;\n}\n\nconst INTEGRATION_NAME = 'GraphQLClient' as const;\n\nconst _graphqlClientIntegration = ((options: GraphQLClientOptions) => {\n return {\n name: INTEGRATION_NAME,\n setup(client: Client) {\n _updateSpanWithGraphQLData(client, options);\n _updateBreadcrumbWithGraphQLData(client, options);\n },\n };\n}) satisfies IntegrationFn;\n\nfunction _updateSpanWithGraphQLData(client: Client, options: GraphQLClientOptions): void {\n client.on('beforeOutgoingRequestSpan', (span, hint) => {\n const spanJSON = spanToJSON(span);\n\n const spanAttributes = spanJSON.data || {};\n const spanOp = spanAttributes[SEMANTIC_ATTRIBUTE_SENTRY_OP];\n\n const isHttpClientSpan = spanOp === 'http.client';\n\n if (!isHttpClientSpan) {\n return;\n }\n\n // Fall back to `url` because fetch instrumentation only sets `http.url` for absolute URLs;\n // relative URLs end up only in `url` (see `getFetchSpanAttributes` in packages/core/src/fetch.ts).\n const httpUrl = spanAttributes[SEMANTIC_ATTRIBUTE_URL_FULL] || spanAttributes['http.url'] || spanAttributes['url'];\n const httpMethod = spanAttributes[SEMANTIC_ATTRIBUTE_HTTP_REQUEST_METHOD] || spanAttributes['http.method'];\n\n if (!isString(httpUrl) || !isString(httpMethod)) {\n return;\n }\n\n const { endpoints } = options;\n const isTracedGraphqlEndpoint = stringMatchesSomePattern(httpUrl, endpoints);\n const payload = getRequestPayloadXhrOrFetch(hint as XhrHint | FetchHint);\n\n if (isTracedGraphqlEndpoint && payload) {\n const graphqlBody = getGraphQLRequestPayload(payload);\n\n if (graphqlBody) {\n const operationInfo = _getGraphQLOperation(graphqlBody);\n span.updateName(`${httpMethod} ${httpUrl} (${operationInfo})`);\n\n // Handle standard requests - always capture the query document\n if (isStandardRequest(graphqlBody)) {\n span.setAttribute('graphql.document', graphqlBody.query);\n }\n\n // Handle persisted operations - capture hash for debugging\n if (isPersistedRequest(graphqlBody)) {\n span.setAttribute('graphql.persisted_query.hash.sha256', graphqlBody.extensions.persistedQuery.sha256Hash);\n span.setAttribute('graphql.persisted_query.version', graphqlBody.extensions.persistedQuery.version);\n }\n }\n }\n });\n}\n\nfunction _updateBreadcrumbWithGraphQLData(client: Client, options: GraphQLClientOptions): void {\n client.on('beforeOutgoingRequestBreadcrumb', (breadcrumb, handlerData) => {\n const { category, type, data } = breadcrumb;\n\n const isFetch = category === 'fetch';\n const isXhr = category === 'xhr';\n const isHttpBreadcrumb = type === 'http';\n\n if (isHttpBreadcrumb && (isFetch || isXhr)) {\n const httpUrl = data?.url;\n const { endpoints } = options;\n\n const isTracedGraphqlEndpoint = stringMatchesSomePattern(httpUrl, endpoints);\n const payload = getRequestPayloadXhrOrFetch(handlerData as XhrHint | FetchHint);\n\n if (isTracedGraphqlEndpoint && data && payload) {\n const graphqlBody = getGraphQLRequestPayload(payload);\n\n if (!data.graphql && graphqlBody) {\n const operationInfo = _getGraphQLOperation(graphqlBody);\n\n data['graphql.operation'] = operationInfo;\n\n if (isStandardRequest(graphqlBody)) {\n data['graphql.document'] = graphqlBody.query;\n }\n\n if (isPersistedRequest(graphqlBody)) {\n data['graphql.persisted_query.hash.sha256'] = graphqlBody.extensions.persistedQuery.sha256Hash;\n data['graphql.persisted_query.version'] = graphqlBody.extensions.persistedQuery.version;\n }\n }\n }\n }\n });\n}\n\n/**\n * @param requestBody - GraphQL request\n * @returns A formatted version of the request: 'TYPE NAME' or 'TYPE' or 'persisted NAME'\n */\nexport function _getGraphQLOperation(requestBody: GraphQLRequestPayload): string {\n // Handle persisted operations\n if (isPersistedRequest(requestBody)) {\n return `persisted ${requestBody.operationName}`;\n }\n\n // Handle standard GraphQL requests\n if (isStandardRequest(requestBody)) {\n const { query: graphqlQuery, operationName: graphqlOperationName } = requestBody;\n const { operationName = graphqlOperationName, operationType } = parseGraphQLQuery(graphqlQuery);\n const operationInfo = operationName ? `${operationType} ${operationName}` : `${operationType}`;\n return operationInfo;\n }\n\n // Fallback for unknown request types\n return 'unknown';\n}\n\n/**\n * Get the request body/payload based on the shape of the hint.\n *\n * Exported for tests only.\n */\nexport function getRequestPayloadXhrOrFetch(hint: XhrHint | FetchHint): string | undefined {\n const isXhr = 'xhr' in hint;\n\n let body: string | undefined;\n\n if (isXhr) {\n const sentryXhrData = hint.xhr[SENTRY_XHR_DATA_KEY];\n body = sentryXhrData && getBodyString(sentryXhrData.body)[0];\n } else {\n const sentryFetchData = getFetchRequestArgBody(hint.input);\n body = getBodyString(sentryFetchData)[0];\n }\n\n return body;\n}\n\n/**\n * Extract the name and type of the operation from the GraphQL query.\n *\n * Exported for tests only.\n */\nexport function parseGraphQLQuery(query: string): GraphQLOperation {\n const namedQueryRe = /^(?:\\s*)(query|mutation|subscription)(?:\\s*)(\\w+)(?:\\s*)[{(]/;\n const unnamedQueryRe = /^(?:\\s*)(query|mutation|subscription)(?:\\s*)[{(]/;\n\n const namedMatch = query.match(namedQueryRe);\n if (namedMatch) {\n return {\n operationType: namedMatch[1],\n operationName: namedMatch[2],\n };\n }\n\n const unnamedMatch = query.match(unnamedQueryRe);\n if (unnamedMatch) {\n return {\n operationType: unnamedMatch[1],\n operationName: undefined,\n };\n }\n return {\n operationType: undefined,\n operationName: undefined,\n };\n}\n\n/**\n * Helper to safely check if a value is a non-null object\n */\n\n/**\n * Type guard to check if a request is a standard GraphQL request\n */\nfunction isStandardRequest(payload: unknown): payload is GraphQLStandardRequest {\n return isObjectLike(payload) && typeof payload.query === 'string';\n}\n\n/**\n * Type guard to check if a request is a persisted operation request\n */\nfunction isPersistedRequest(payload: unknown): payload is GraphQLPersistedRequest {\n return (\n isObjectLike(payload) &&\n typeof payload.operationName === 'string' &&\n isObjectLike(payload.extensions) &&\n isObjectLike(payload.extensions.persistedQuery) &&\n typeof payload.extensions.persistedQuery.sha256Hash === 'string' &&\n typeof payload.extensions.persistedQuery.version === 'number'\n );\n}\n\n/**\n * Extract the payload of a request if it's GraphQL.\n * Exported for tests only.\n * @param payload - A valid JSON string\n * @returns A POJO or undefined\n */\nexport function getGraphQLRequestPayload(payload: string): GraphQLRequestPayload | undefined {\n try {\n const requestBody = JSON.parse(payload);\n\n // Return any valid GraphQL request (standard, persisted, or APQ retry with both)\n if (isStandardRequest(requestBody) || isPersistedRequest(requestBody)) {\n return requestBody;\n }\n\n // Not a GraphQL request\n return undefined;\n } catch {\n // Invalid JSON\n return undefined;\n }\n}\n\n/**\n * This integration ensures that GraphQL requests made in the browser\n * have their GraphQL-specific data captured and attached to spans and breadcrumbs.\n */\nexport const graphqlClientIntegration = defineIntegration(_graphqlClientIntegration);\n"],"names":[],"mappings":"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"} | ||
| {"version":3,"file":"graphqlClient.js","sources":["../../../../../src/integrations/graphqlClient.ts"],"sourcesContent":["import type { Client, IntegrationFn } from '@sentry/core/browser';\nimport {\n defineIntegration,\n isObjectLike,\n isString,\n SEMANTIC_ATTRIBUTE_HTTP_REQUEST_METHOD,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n SEMANTIC_ATTRIBUTE_URL_FULL,\n spanToJSON,\n stringMatchesSomePattern,\n} from '@sentry/core/browser';\nimport type { FetchHint, XhrHint } from '@sentry/browser-utils';\nimport { getBodyString, getFetchRequestArgBody, SENTRY_XHR_DATA_KEY } from '@sentry/browser-utils';\nimport { GRAPHQL_DOCUMENT } from '@sentry/conventions/attributes';\n\ninterface GraphQLClientOptions {\n endpoints: Array<string | RegExp>;\n}\n\n/** Standard graphql request shape: https://graphql.org/learn/serving-over-http/#post-request-and-body */\ninterface GraphQLStandardRequest {\n query: string;\n operationName?: string;\n variables?: Record<string, unknown>;\n extensions?: Record<string, unknown>;\n}\n\n/** Persisted operation request */\ninterface GraphQLPersistedRequest {\n operationName: string;\n variables?: Record<string, unknown>;\n extensions: {\n persistedQuery: {\n version: number;\n sha256Hash: string;\n };\n } & Record<string, unknown>;\n}\n\ntype GraphQLRequestPayload = GraphQLStandardRequest | GraphQLPersistedRequest;\n\ninterface GraphQLOperation {\n operationType?: string;\n operationName?: string;\n}\n\nconst INTEGRATION_NAME = 'GraphQLClient' as const;\n\nconst _graphqlClientIntegration = ((options: GraphQLClientOptions) => {\n return {\n name: INTEGRATION_NAME,\n setup(client: Client) {\n _updateSpanWithGraphQLData(client, options);\n _updateBreadcrumbWithGraphQLData(client, options);\n },\n };\n}) satisfies IntegrationFn;\n\nfunction _updateSpanWithGraphQLData(client: Client, options: GraphQLClientOptions): void {\n client.on('beforeOutgoingRequestSpan', (span, hint) => {\n const spanJSON = spanToJSON(span);\n\n const spanAttributes = spanJSON.data || {};\n const spanOp = spanAttributes[SEMANTIC_ATTRIBUTE_SENTRY_OP];\n\n const isHttpClientSpan = spanOp === 'http.client';\n\n if (!isHttpClientSpan) {\n return;\n }\n\n // Fall back to `url` because fetch instrumentation only sets `http.url` for absolute URLs;\n // relative URLs end up only in `url` (see `getFetchSpanAttributes` in packages/core/src/fetch.ts).\n const httpUrl = spanAttributes[SEMANTIC_ATTRIBUTE_URL_FULL] || spanAttributes['http.url'] || spanAttributes['url'];\n const httpMethod = spanAttributes[SEMANTIC_ATTRIBUTE_HTTP_REQUEST_METHOD] || spanAttributes['http.method'];\n\n if (!isString(httpUrl) || !isString(httpMethod)) {\n return;\n }\n\n const { endpoints } = options;\n const isTracedGraphqlEndpoint = stringMatchesSomePattern(httpUrl, endpoints);\n const payload = getRequestPayloadXhrOrFetch(hint as XhrHint | FetchHint);\n\n if (isTracedGraphqlEndpoint && payload) {\n const graphqlBody = getGraphQLRequestPayload(payload);\n\n if (graphqlBody) {\n const operationInfo = _getGraphQLOperation(graphqlBody);\n span.updateName(`${httpMethod} ${httpUrl} (${operationInfo})`);\n\n // Handle standard requests - capture the query document when enabled via dataCollection (default true)\n if (isStandardRequest(graphqlBody) && client.getDataCollectionOptions().graphQL.document === true) {\n span.setAttribute(GRAPHQL_DOCUMENT, graphqlBody.query);\n }\n\n // Handle persisted operations - capture hash for debugging\n if (isPersistedRequest(graphqlBody)) {\n span.setAttribute('graphql.persisted_query.hash.sha256', graphqlBody.extensions.persistedQuery.sha256Hash);\n span.setAttribute('graphql.persisted_query.version', graphqlBody.extensions.persistedQuery.version);\n }\n }\n }\n });\n}\n\nfunction _updateBreadcrumbWithGraphQLData(client: Client, options: GraphQLClientOptions): void {\n client.on('beforeOutgoingRequestBreadcrumb', (breadcrumb, handlerData) => {\n const { category, type, data } = breadcrumb;\n\n const isFetch = category === 'fetch';\n const isXhr = category === 'xhr';\n const isHttpBreadcrumb = type === 'http';\n\n if (isHttpBreadcrumb && (isFetch || isXhr)) {\n const httpUrl = data?.url;\n const { endpoints } = options;\n\n const isTracedGraphqlEndpoint = stringMatchesSomePattern(httpUrl, endpoints);\n const payload = getRequestPayloadXhrOrFetch(handlerData as XhrHint | FetchHint);\n\n if (isTracedGraphqlEndpoint && data && payload) {\n const graphqlBody = getGraphQLRequestPayload(payload);\n\n if (!data.graphql && graphqlBody) {\n const operationInfo = _getGraphQLOperation(graphqlBody);\n\n data['graphql.operation'] = operationInfo;\n\n if (isStandardRequest(graphqlBody) && client.getDataCollectionOptions().graphQL.document === true) {\n data[GRAPHQL_DOCUMENT] = graphqlBody.query;\n }\n\n if (isPersistedRequest(graphqlBody)) {\n data['graphql.persisted_query.hash.sha256'] = graphqlBody.extensions.persistedQuery.sha256Hash;\n data['graphql.persisted_query.version'] = graphqlBody.extensions.persistedQuery.version;\n }\n }\n }\n }\n });\n}\n\n/**\n * @param requestBody - GraphQL request\n * @returns A formatted version of the request: 'TYPE NAME' or 'TYPE' or 'persisted NAME'\n */\nexport function _getGraphQLOperation(requestBody: GraphQLRequestPayload): string {\n // Handle persisted operations\n if (isPersistedRequest(requestBody)) {\n return `persisted ${requestBody.operationName}`;\n }\n\n // Handle standard GraphQL requests\n if (isStandardRequest(requestBody)) {\n const { query: graphqlQuery, operationName: graphqlOperationName } = requestBody;\n const { operationName = graphqlOperationName, operationType } = parseGraphQLQuery(graphqlQuery);\n const operationInfo = operationName ? `${operationType} ${operationName}` : `${operationType}`;\n return operationInfo;\n }\n\n // Fallback for unknown request types\n return 'unknown';\n}\n\n/**\n * Get the request body/payload based on the shape of the hint.\n *\n * Exported for tests only.\n */\nexport function getRequestPayloadXhrOrFetch(hint: XhrHint | FetchHint): string | undefined {\n const isXhr = 'xhr' in hint;\n\n let body: string | undefined;\n\n if (isXhr) {\n const sentryXhrData = hint.xhr[SENTRY_XHR_DATA_KEY];\n body = sentryXhrData && getBodyString(sentryXhrData.body)[0];\n } else {\n const sentryFetchData = getFetchRequestArgBody(hint.input);\n body = getBodyString(sentryFetchData)[0];\n }\n\n return body;\n}\n\n/**\n * Extract the name and type of the operation from the GraphQL query.\n *\n * Exported for tests only.\n */\nexport function parseGraphQLQuery(query: string): GraphQLOperation {\n const namedQueryRe = /^(?:\\s*)(query|mutation|subscription)(?:\\s*)(\\w+)(?:\\s*)[{(]/;\n const unnamedQueryRe = /^(?:\\s*)(query|mutation|subscription)(?:\\s*)[{(]/;\n\n const namedMatch = query.match(namedQueryRe);\n if (namedMatch) {\n return {\n operationType: namedMatch[1],\n operationName: namedMatch[2],\n };\n }\n\n const unnamedMatch = query.match(unnamedQueryRe);\n if (unnamedMatch) {\n return {\n operationType: unnamedMatch[1],\n operationName: undefined,\n };\n }\n return {\n operationType: undefined,\n operationName: undefined,\n };\n}\n\n/**\n * Helper to safely check if a value is a non-null object\n */\n\n/**\n * Type guard to check if a request is a standard GraphQL request\n */\nfunction isStandardRequest(payload: unknown): payload is GraphQLStandardRequest {\n return isObjectLike(payload) && typeof payload.query === 'string';\n}\n\n/**\n * Type guard to check if a request is a persisted operation request\n */\nfunction isPersistedRequest(payload: unknown): payload is GraphQLPersistedRequest {\n return (\n isObjectLike(payload) &&\n typeof payload.operationName === 'string' &&\n isObjectLike(payload.extensions) &&\n isObjectLike(payload.extensions.persistedQuery) &&\n typeof payload.extensions.persistedQuery.sha256Hash === 'string' &&\n typeof payload.extensions.persistedQuery.version === 'number'\n );\n}\n\n/**\n * Extract the payload of a request if it's GraphQL.\n * Exported for tests only.\n * @param payload - A valid JSON string\n * @returns A POJO or undefined\n */\nexport function getGraphQLRequestPayload(payload: string): GraphQLRequestPayload | undefined {\n try {\n const requestBody = JSON.parse(payload);\n\n // Return any valid GraphQL request (standard, persisted, or APQ retry with both)\n if (isStandardRequest(requestBody) || isPersistedRequest(requestBody)) {\n return requestBody;\n }\n\n // Not a GraphQL request\n return undefined;\n } catch {\n // Invalid JSON\n return undefined;\n }\n}\n\n/**\n * This integration ensures that GraphQL requests made in the browser\n * have their GraphQL-specific data captured and attached to spans and breadcrumbs.\n */\nexport const graphqlClientIntegration = defineIntegration(_graphqlClientIntegration);\n"],"names":[],"mappings":"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"} |
@@ -1,1 +0,1 @@ | ||
| {"type":"module","version":"10.65.0","sideEffects":false} | ||
| {"type":"module","version":"10.66.0","sideEffects":false} |
@@ -1,2 +0,2 @@ | ||
| import { addFetchInstrumentationHandler, instrumentFetchRequest, parseUrl, stripDataUrlContent, spanToJSON, hasSpanStreamingEnabled, timestampInSeconds, hasSpansEnabled, setHttpStatus, stripUrlQueryAndFragment, getClient, getActiveSpan, startInactiveSpan, SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, SentryNonRecordingSpan, getLocationHref, stringMatchesSomePattern, getTraceData } from '@sentry/core/browser'; | ||
| import { addFetchInstrumentationHandler, instrumentFetchRequest, parseUrl, stripDataUrlContent, spanToJSON, hasSpanStreamingEnabled, timestampInSeconds, hasSpansEnabled, setHttpStatus, stripUrlQueryAndFragment, getClient, getActiveSpan, startInactiveSpan, SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, SentryNonRecordingSpan, spanIsIgnored, getLocationHref, stringMatchesSomePattern, getTraceData } from '@sentry/core/browser'; | ||
| import { addXhrInstrumentationHandler, addPerformanceInstrumentationHandler, resourceTimingToSpanAttributes, SENTRY_XHR_DATA_KEY, parseXhrResponseHeaders } from '@sentry/browser-utils'; | ||
@@ -182,2 +182,3 @@ import { getFullURL, createHeadersSafely, isPerformanceResourceTiming, baggageHeaderHasSentryValues } from './utils.js'; | ||
| }) : new SentryNonRecordingSpan(); | ||
| const spanForTraceHeaders = spanIsIgnored(span) && hasParent ? void 0 : span; | ||
| if (shouldCreateSpanResult && !shouldEmitSpan) { | ||
@@ -194,3 +195,3 @@ client?.recordDroppedEvent("no_parent_span", "span"); | ||
| // which means that the headers will be generated from the scope and the sampling decision is deferred | ||
| hasSpansEnabled() && shouldEmitSpan ? span : void 0, | ||
| hasSpansEnabled() && shouldEmitSpan ? spanForTraceHeaders : void 0, | ||
| propagateTraceparent | ||
@@ -197,0 +198,0 @@ ); |
@@ -1,1 +0,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/browser';\nimport {\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/browser';\nimport type { XhrHint } from '@sentry/browser-utils';\nimport {\n addPerformanceInstrumentationHandler,\n addXhrInstrumentationHandler,\n parseXhrResponseHeaders,\n resourceTimingToSpanAttributes,\n SENTRY_XHR_DATA_KEY,\n} from '@sentry/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 * @deprecated Use `fetchStreamPerformanceIntegration()` instead. Add it to your `integrations` array\n * to track the duration of streamed fetch response bodies.\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\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 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 addFetchInstrumentationHandler(handlerData => {\n const createdSpan = instrumentFetchRequest(handlerData, shouldCreateSpan, shouldAttachHeadersWithTargets, spans, {\n propagateTraceparent,\n onRequestSpanEnd,\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 const sanitizedFullUrl = fullUrl ? stripDataUrlContent(fullUrl) : undefined;\n createdSpan.setAttributes({\n 'http.url': sanitizedFullUrl,\n // `url.full` must match `http.url`. Setting it here ensures parentless `http.client`\n // segment spans don't get `url.full` backfilled with the host page URL (see httpContextIntegration).\n 'url.full': sanitizedFullUrl,\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 const sanitizedFullUrl = fullUrl ? stripDataUrlContent(fullUrl) : undefined;\n\n const urlForSpanName = stripDataUrlContent(stripUrlQueryAndFragment(url));\n\n const client = getClient();\n const hasParent = !!getActiveSpan();\n // With span streaming, we always emit http.client spans, even without a parent span\n const shouldEmitSpan = hasParent || (!!client && hasSpanStreamingEnabled(client));\n\n const span =\n shouldCreateSpanResult && shouldEmitSpan\n ? startInactiveSpan({\n name: `${method} ${urlForSpanName}`,\n attributes: {\n url: stripDataUrlContent(url),\n type: 'xhr',\n 'http.method': method,\n 'http.url': sanitizedFullUrl,\n // `url.full` must match `http.url`. Setting it here ensures parentless `http.client`\n // segment spans don't get `url.full` backfilled with the host page URL (see httpContextIntegration).\n 'url.full': sanitizedFullUrl,\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 if (shouldCreateSpanResult && !shouldEmitSpan) {\n client?.recordDroppedEvent('no_parent_span', 'span');\n }\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() && shouldEmitSpan ? span : undefined,\n propagateTraceparent,\n );\n }\n\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":["shouldAttachHeaders","span"],"mappings":"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"} | ||
| {"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/browser';\nimport {\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 spanIsIgnored,\n spanToJSON,\n startInactiveSpan,\n stringMatchesSomePattern,\n stripDataUrlContent,\n stripUrlQueryAndFragment,\n timestampInSeconds,\n} from '@sentry/core/browser';\nimport type { XhrHint } from '@sentry/browser-utils';\nimport {\n addPerformanceInstrumentationHandler,\n addXhrInstrumentationHandler,\n parseXhrResponseHeaders,\n resourceTimingToSpanAttributes,\n SENTRY_XHR_DATA_KEY,\n} from '@sentry/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 * @deprecated Use `fetchStreamPerformanceIntegration()` instead. Add it to your `integrations` array\n * to track the duration of streamed fetch response bodies.\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\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 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 addFetchInstrumentationHandler(handlerData => {\n const createdSpan = instrumentFetchRequest(handlerData, shouldCreateSpan, shouldAttachHeadersWithTargets, spans, {\n propagateTraceparent,\n onRequestSpanEnd,\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 const sanitizedFullUrl = fullUrl ? stripDataUrlContent(fullUrl) : undefined;\n createdSpan.setAttributes({\n 'http.url': sanitizedFullUrl,\n // `url.full` must match `http.url`. Setting it here ensures parentless `http.client`\n // segment spans don't get `url.full` backfilled with the host page URL (see httpContextIntegration).\n 'url.full': sanitizedFullUrl,\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 */\n// oxlint-disable-next-line complexity\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 const sanitizedFullUrl = fullUrl ? stripDataUrlContent(fullUrl) : undefined;\n\n const urlForSpanName = stripDataUrlContent(stripUrlQueryAndFragment(url));\n\n const client = getClient();\n const hasParent = !!getActiveSpan();\n // With span streaming, we always emit http.client spans, even without a parent span\n const shouldEmitSpan = hasParent || (!!client && hasSpanStreamingEnabled(client));\n\n const span =\n shouldCreateSpanResult && shouldEmitSpan\n ? startInactiveSpan({\n name: `${method} ${urlForSpanName}`,\n attributes: {\n url: stripDataUrlContent(url),\n type: 'xhr',\n 'http.method': method,\n 'http.url': sanitizedFullUrl,\n // `url.full` must match `http.url`. Setting it here ensures parentless `http.client`\n // segment spans don't get `url.full` backfilled with the host page URL (see httpContextIntegration).\n 'url.full': sanitizedFullUrl,\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 // If the span is ignored, we don't want to continue the trace from it (NonRecordingSpan) but rather\n // from the active span. Passing `undefined` here will make `getTraceData` use the active span instead.\n const spanForTraceHeaders = spanIsIgnored(span) && hasParent ? undefined : span;\n\n if (shouldCreateSpanResult && !shouldEmitSpan) {\n client?.recordDroppedEvent('no_parent_span', 'span');\n }\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() && shouldEmitSpan ? spanForTraceHeaders : undefined,\n propagateTraceparent,\n );\n }\n\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":["shouldAttachHeaders","span"],"mappings":"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"} |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"graphqlClient.d.ts","sourceRoot":"","sources":["../../../../src/integrations/graphqlClient.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAGhE,UAAU,oBAAoB;IAC5B,SAAS,EAAE,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,CAAC;CACnC;AAED,yGAAyG;AACzG,UAAU,sBAAsB;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACpC,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACtC;AAED,kCAAkC;AAClC,UAAU,uBAAuB;IAC/B,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACpC,UAAU,EAAE;QACV,cAAc,EAAE;YACd,OAAO,EAAE,MAAM,CAAC;YAChB,UAAU,EAAE,MAAM,CAAC;SACpB,CAAC;KACH,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC7B;AAED,KAAK,qBAAqB,GAAG,sBAAsB,GAAG,uBAAuB,CAAC;AAE9E,UAAU,gBAAgB;IACxB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAmGD;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,qBAAqB,GAAG,MAAM,CAgB/E;AAED;;;;GAIG;AACH,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,OAAO,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAczF;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,gBAAgB,CAuBjE;AA2BD;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,MAAM,GAAG,qBAAqB,GAAG,SAAS,CAe3F;AAED;;;GAGG;AACH,eAAO,MAAM,wBAAwB;;CAA+C,CAAC"} | ||
| {"version":3,"file":"graphqlClient.d.ts","sourceRoot":"","sources":["../../../../src/integrations/graphqlClient.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAIhE,UAAU,oBAAoB;IAC5B,SAAS,EAAE,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,CAAC;CACnC;AAED,yGAAyG;AACzG,UAAU,sBAAsB;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACpC,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACtC;AAED,kCAAkC;AAClC,UAAU,uBAAuB;IAC/B,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACpC,UAAU,EAAE;QACV,cAAc,EAAE;YACd,OAAO,EAAE,MAAM,CAAC;YAChB,UAAU,EAAE,MAAM,CAAC;SACpB,CAAC;KACH,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC7B;AAED,KAAK,qBAAqB,GAAG,sBAAsB,GAAG,uBAAuB,CAAC;AAE9E,UAAU,gBAAgB;IACxB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAmGD;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,qBAAqB,GAAG,MAAM,CAgB/E;AAED;;;;GAIG;AACH,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,OAAO,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAczF;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,gBAAgB,CAuBjE;AA2BD;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,MAAM,GAAG,qBAAqB,GAAG,SAAS,CAe3F;AAED;;;GAGG;AACH,eAAO,MAAM,wBAAwB;;CAA+C,CAAC"} |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"request.d.ts","sourceRoot":"","sources":["../../../../src/tracing/request.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,MAAM,EAEN,eAAe,EACf,gBAAgB,EAEhB,IAAI,EAEL,MAAM,sBAAsB,CAAC;AAiC9B,0CAA0C;AAC1C,MAAM,WAAW,6BAA6B;IAC5C;;;;;;;;;;;;;;;;;;;;;;;;;;OA0BG;IACH,uBAAuB,CAAC,EAAE,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,CAAC;IAEjD;;;;OAIG;IACH,UAAU,EAAE,OAAO,CAAC;IAEpB;;;;OAIG;IACH,QAAQ,EAAE,OAAO,CAAC;IAElB;;;;;;;;;;;OAWG;IACH,2BAA2B,EAAE,OAAO,CAAC;IAErC;;;;OAIG;IACH,iBAAiB,EAAE,OAAO,CAAC;IAE3B;;;;;OAKG;IACH,0BAA0B,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;IAE9D;;OAEG;IACH,kBAAkB,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,kBAAkB,EAAE,eAAe,GAAG,IAAI,CAAC;IAE3E;;OAEG;IACH,gBAAgB,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,mBAAmB,EAAE,gBAAgB,GAAG,IAAI,CAAC;CAC5E;AAED,eAAO,MAAM,oCAAoC,EAAE,6BAKlD,CAAC;AAEF,0DAA0D;AAC1D,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,OAAO,CAAC,6BAA6B,CAAC,GAAG,IAAI,CA4ElH;AAiED;;;GAGG;AACH,wBAAgB,mBAAmB,CACjC,SAAS,EAAE,MAAM,EACjB,uBAAuB,EAAE,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,GAAG,SAAS,GACvD,OAAO,CAqCT"} | ||
| {"version":3,"file":"request.d.ts","sourceRoot":"","sources":["../../../../src/tracing/request.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,MAAM,EAEN,eAAe,EACf,gBAAgB,EAEhB,IAAI,EAEL,MAAM,sBAAsB,CAAC;AAkC9B,0CAA0C;AAC1C,MAAM,WAAW,6BAA6B;IAC5C;;;;;;;;;;;;;;;;;;;;;;;;;;OA0BG;IACH,uBAAuB,CAAC,EAAE,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,CAAC;IAEjD;;;;OAIG;IACH,UAAU,EAAE,OAAO,CAAC;IAEpB;;;;OAIG;IACH,QAAQ,EAAE,OAAO,CAAC;IAElB;;;;;;;;;;;OAWG;IACH,2BAA2B,EAAE,OAAO,CAAC;IAErC;;;;OAIG;IACH,iBAAiB,EAAE,OAAO,CAAC;IAE3B;;;;;OAKG;IACH,0BAA0B,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;IAE9D;;OAEG;IACH,kBAAkB,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,kBAAkB,EAAE,eAAe,GAAG,IAAI,CAAC;IAE3E;;OAEG;IACH,gBAAgB,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,mBAAmB,EAAE,gBAAgB,GAAG,IAAI,CAAC;CAC5E;AAED,eAAO,MAAM,oCAAoC,EAAE,6BAKlD,CAAC;AAEF,0DAA0D;AAC1D,wBAAgB,0BAA0B,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,OAAO,CAAC,6BAA6B,CAAC,GAAG,IAAI,CA4ElH;AAiED;;;GAGG;AACH,wBAAgB,mBAAmB,CACjC,SAAS,EAAE,MAAM,EACjB,uBAAuB,EAAE,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,GAAG,SAAS,GACvD,OAAO,CAqCT"} |
+8
-8
| { | ||
| "name": "@sentry/browser", | ||
| "version": "10.65.0", | ||
| "version": "10.66.0", | ||
| "description": "Official Sentry SDK for browsers", | ||
@@ -48,11 +48,11 @@ "repository": "git://github.com/getsentry/sentry-javascript.git", | ||
| "dependencies": { | ||
| "@sentry/browser-utils": "10.65.0", | ||
| "@sentry/conventions": "^0.15.1", | ||
| "@sentry/feedback": "10.65.0", | ||
| "@sentry/replay": "10.65.0", | ||
| "@sentry/replay-canvas": "10.65.0", | ||
| "@sentry/core": "10.65.0" | ||
| "@sentry/browser-utils": "10.66.0", | ||
| "@sentry/conventions": "^0.16.0", | ||
| "@sentry/feedback": "10.66.0", | ||
| "@sentry/replay": "10.66.0", | ||
| "@sentry/replay-canvas": "10.66.0", | ||
| "@sentry/core": "10.66.0" | ||
| }, | ||
| "devDependencies": { | ||
| "@sentry-internal/integration-shims": "10.65.0", | ||
| "@sentry-internal/integration-shims": "10.66.0", | ||
| "fake-indexeddb": "^6.2.4" | ||
@@ -59,0 +59,0 @@ }, |
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
2711617
0.16%23193
0.03%+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
Updated
Updated
Updated
Updated