diff --git a/packages/astro/src/index.server.ts b/packages/astro/src/index.server.ts index dabd32fce530..e788549c0a78 100644 --- a/packages/astro/src/index.server.ts +++ b/packages/astro/src/index.server.ts @@ -31,7 +31,6 @@ export { cron, dataloaderIntegration, dedupeIntegration, - DEFAULT_USER_INCLUDES, defaultStackParser, endSession, expressErrorHandler, diff --git a/packages/aws-serverless/src/index.ts b/packages/aws-serverless/src/index.ts index 1041f89243e4..e2e405768b3b 100644 --- a/packages/aws-serverless/src/index.ts +++ b/packages/aws-serverless/src/index.ts @@ -42,7 +42,6 @@ export { flush, close, getSentryRelease, - DEFAULT_USER_INCLUDES, createGetModuleFromFilename, anrIntegration, disableAnrDetectionForCallback, diff --git a/packages/bun/src/index.ts b/packages/bun/src/index.ts index 0adee621edac..a9ea0801e6f2 100644 --- a/packages/bun/src/index.ts +++ b/packages/bun/src/index.ts @@ -18,7 +18,6 @@ export type { Thread, User, } from '@sentry/core'; -export type { AddRequestDataToEventOptions } from '@sentry/core'; export { addEventProcessor, @@ -64,7 +63,6 @@ export { flush, close, getSentryRelease, - DEFAULT_USER_INCLUDES, createGetModuleFromFilename, anrIntegration, disableAnrDetectionForCallback, diff --git a/packages/cloudflare/src/index.ts b/packages/cloudflare/src/index.ts index 8dd5ba50a623..b13eea386427 100644 --- a/packages/cloudflare/src/index.ts +++ b/packages/cloudflare/src/index.ts @@ -18,7 +18,6 @@ export type { Thread, User, } from '@sentry/core'; -export type { AddRequestDataToEventOptions } from '@sentry/core'; export type { CloudflareOptions } from './client'; diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 036c31e9b1d2..031aefb4287e 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -3,7 +3,6 @@ export type { AsyncContextStrategy } from './asyncContext/types'; export type { Carrier } from './carrier'; export type { OfflineStore, OfflineTransportOptions } from './transports/offline'; export type { ServerRuntimeClientOptions } from './server-runtime-client'; -export type { RequestDataIntegrationOptions } from './integrations/requestdata'; export type { IntegrationIndex } from './integration'; export * from './tracing'; diff --git a/packages/core/src/integrations/requestdata.ts b/packages/core/src/integrations/requestdata.ts index 1ce1799cac59..df670bb81013 100644 --- a/packages/core/src/integrations/requestdata.ts +++ b/packages/core/src/integrations/requestdata.ts @@ -1,88 +1,49 @@ import { defineIntegration } from '../integration'; -import type { IntegrationFn } from '../types-hoist'; -import { type AddRequestDataToEventOptions, addNormalizedRequestDataToEvent } from '../utils-hoist/requestdata'; +import type { Event, IntegrationFn, RequestEventData } from '../types-hoist'; +import { parseCookie } from '../utils-hoist/cookie'; +import { getClientIPAddress, ipHeaderNames } from '../utils-hoist/vendor/getIpAddress'; -export type RequestDataIntegrationOptions = { - /** - * Controls what data is pulled from the request and added to the event - */ - include?: { - cookies?: boolean; - data?: boolean; - headers?: boolean; - ip?: boolean; - query_string?: boolean; - url?: boolean; - user?: - | boolean - | { - id?: boolean; - username?: boolean; - email?: boolean; - }; - }; +interface RequestDataIncludeOptions { + cookies?: boolean; + data?: boolean; + headers?: boolean; + ip?: boolean; + query_string?: boolean; + url?: boolean; +} +type RequestDataIntegrationOptions = { /** - * Whether to identify transactions by parameterized path, parameterized path with method, or handler name. - * @deprecated This option does not do anything anymore, and will be removed in v9. + * Controls what data is pulled from the request and added to the event. */ - transactionNamingScheme?: 'path' | 'methodPath' | 'handler'; + include?: RequestDataIncludeOptions; }; -const DEFAULT_OPTIONS = { - include: { - cookies: true, - data: true, - headers: true, - ip: false, - query_string: true, - url: true, - user: { - id: true, - username: true, - email: true, - }, - }, - transactionNamingScheme: 'methodPath' as const, -}; +const DEFAULT_INCLUDE = { + cookies: true, + data: true, + headers: true, + ip: false, + query_string: true, + url: true, +} satisfies RequestDataIncludeOptions; const INTEGRATION_NAME = 'RequestData'; const _requestDataIntegration = ((options: RequestDataIntegrationOptions = {}) => { - const _options: Required = { - ...DEFAULT_OPTIONS, - ...options, - include: { - ...DEFAULT_OPTIONS.include, - ...options.include, - user: - options.include && typeof options.include.user === 'boolean' - ? options.include.user - : { - ...DEFAULT_OPTIONS.include.user, - // Unclear why TS still thinks `options.include.user` could be a boolean at this point - ...((options.include || {}).user as Record), - }, - }, + const include = { + ...DEFAULT_INCLUDE, + ...options.include, }; return { name: INTEGRATION_NAME, processEvent(event) { - // Note: In the long run, most of the logic here should probably move into the request data utility functions. For - // the moment it lives here, though, until https://github.com/getsentry/sentry-javascript/issues/5718 is addressed. - // (TL;DR: Those functions touch many parts of the repo in many different ways, and need to be cleaned up. Once - // that's happened, it will be easier to add this logic in without worrying about unexpected side effects.) - const { sdkProcessingMetadata = {} } = event; const { normalizedRequest, ipAddress } = sdkProcessingMetadata; - const addRequestDataOptions = convertReqDataIntegrationOptsToAddReqDataOpts(_options); - - // If this is set, it takes precedence over the plain request object if (normalizedRequest) { - // TODO: user??? - addNormalizedRequestDataToEvent(event, normalizedRequest, { ipAddress }, addRequestDataOptions); + addNormalizedRequestDataToEvent(event, normalizedRequest, { ipAddress }, include); return event; } @@ -97,42 +58,75 @@ const _requestDataIntegration = ((options: RequestDataIntegrationOptions = {}) = */ export const requestDataIntegration = defineIntegration(_requestDataIntegration); -/** Convert this integration's options to match what `addRequestDataToEvent` expects */ -/** TODO: Can possibly be deleted once https://github.com/getsentry/sentry-javascript/issues/5718 is fixed */ -function convertReqDataIntegrationOptsToAddReqDataOpts( - integrationOptions: Required, -): AddRequestDataToEventOptions { - const { - include: { ip, user, ...requestOptions }, - } = integrationOptions; - - const requestIncludeKeys: string[] = ['method']; - for (const [key, value] of Object.entries(requestOptions)) { - if (value) { - requestIncludeKeys.push(key); +/** + * Add already normalized request data to an event. + * This mutates the passed in event. + */ +function addNormalizedRequestDataToEvent( + event: Event, + req: RequestEventData, + // Data that should not go into `event.request` but is somehow related to requests + additionalData: { ipAddress?: string }, + include: RequestDataIncludeOptions, +): void { + event.request = { + ...event.request, + ...extractNormalizedRequestData(req, include), + }; + + if (include.ip) { + const ip = (req.headers && getClientIPAddress(req.headers)) || additionalData.ipAddress; + if (ip) { + event.user = { + ...event.user, + ip_address: ip, + }; } } +} - let addReqDataUserOpt; - if (user === undefined) { - addReqDataUserOpt = true; - } else if (typeof user === 'boolean') { - addReqDataUserOpt = user; - } else { - const userIncludeKeys: string[] = []; - for (const [key, value] of Object.entries(user)) { - if (value) { - userIncludeKeys.push(key); - } +function extractNormalizedRequestData( + normalizedRequest: RequestEventData, + include: RequestDataIncludeOptions, +): RequestEventData { + const requestData: RequestEventData = {}; + const headers = { ...normalizedRequest.headers }; + + if (include.headers) { + requestData.headers = headers; + + // Remove the Cookie header in case cookie data should not be included in the event + if (!include.cookies) { + delete (headers as { cookie?: string }).cookie; + } + + // Remove IP headers in case IP data should not be included in the event + if (!include.ip) { + ipHeaderNames.forEach(ipHeaderName => { + // eslint-disable-next-line @typescript-eslint/no-dynamic-delete + delete (headers as Record)[ipHeaderName]; + }); } - addReqDataUserOpt = userIncludeKeys; } - return { - include: { - ip, - user: addReqDataUserOpt, - request: requestIncludeKeys.length !== 0 ? requestIncludeKeys : undefined, - }, - }; + requestData.method = normalizedRequest.method; + + if (include.url) { + requestData.url = normalizedRequest.url; + } + + if (include.cookies) { + const cookies = normalizedRequest.cookies || (headers && headers.cookie ? parseCookie(headers.cookie) : undefined); + requestData.cookies = cookies || {}; + } + + if (include.query_string) { + requestData.query_string = normalizedRequest.query_string; + } + + if (include.data) { + requestData.data = normalizedRequest.data; + } + + return requestData; } diff --git a/packages/core/src/utils-hoist/index.ts b/packages/core/src/utils-hoist/index.ts index bf90762e2209..04e5dd6560b4 100644 --- a/packages/core/src/utils-hoist/index.ts +++ b/packages/core/src/utils-hoist/index.ts @@ -66,17 +66,13 @@ export { basename, dirname, isAbsolute, join, normalizePath, relative, resolve } export { makePromiseBuffer } from './promisebuffer'; export type { PromiseBuffer } from './promisebuffer'; -// TODO: Remove requestdata export once equivalent integration is used everywhere export { - DEFAULT_USER_INCLUDES, - addNormalizedRequestDataToEvent, winterCGHeadersToDict, winterCGRequestToRequestData, httpRequestToRequestData, extractQueryParamsFromUrl, headersToDict, } from './requestdata'; -export type { AddRequestDataToEventOptions } from './requestdata'; export { severityLevelFromString } from './severity'; export { diff --git a/packages/core/src/utils-hoist/requestdata.ts b/packages/core/src/utils-hoist/requestdata.ts index bc72b9cb2a2f..4f348f3870ed 100644 --- a/packages/core/src/utils-hoist/requestdata.ts +++ b/packages/core/src/utils-hoist/requestdata.ts @@ -1,115 +1,7 @@ -import type { Event, PolymorphicRequest, RequestEventData, WebFetchHeaders, WebFetchRequest } from '../types-hoist'; -import { parseCookie } from './cookie'; +import type { PolymorphicRequest, RequestEventData, WebFetchHeaders, WebFetchRequest } from '../types-hoist'; import { DEBUG_BUILD } from './debug-build'; -import { isPlainObject } from './is'; import { logger } from './logger'; import { dropUndefinedKeys } from './object'; -import { getClientIPAddress, ipHeaderNames } from './vendor/getIpAddress'; - -const DEFAULT_INCLUDES = { - ip: false, - request: true, - user: true, -}; -const DEFAULT_REQUEST_INCLUDES = ['cookies', 'data', 'headers', 'method', 'query_string', 'url']; -export const DEFAULT_USER_INCLUDES = ['id', 'username', 'email']; - -/** - * Options deciding what parts of the request to use when enhancing an event - */ -export type AddRequestDataToEventOptions = { - /** Flags controlling whether each type of data should be added to the event */ - include?: { - ip?: boolean; - request?: boolean | Array<(typeof DEFAULT_REQUEST_INCLUDES)[number]>; - user?: boolean | Array<(typeof DEFAULT_USER_INCLUDES)[number]>; - }; - - /** Injected platform-specific dependencies */ - deps?: { - cookie: { - parse: (cookieStr: string) => Record; - }; - url: { - parse: (urlStr: string) => { - query: string | null; - }; - }; - }; -}; - -function extractUserData( - user: { - [key: string]: unknown; - }, - keys: boolean | string[], -): { [key: string]: unknown } { - const extractedUser: { [key: string]: unknown } = {}; - const attributes = Array.isArray(keys) ? keys : DEFAULT_USER_INCLUDES; - - attributes.forEach(key => { - if (user && key in user) { - extractedUser[key] = user[key]; - } - }); - - return extractedUser; -} - -/** - * Add already normalized request data to an event. - * This mutates the passed in event. - */ -export function addNormalizedRequestDataToEvent( - event: Event, - req: RequestEventData, - // This is non-standard data that is not part of the regular HTTP request - additionalData: { ipAddress?: string; user?: Record }, - options: AddRequestDataToEventOptions, -): void { - const include = { - ...DEFAULT_INCLUDES, - ...(options && options.include), - }; - - if (include.request) { - const includeRequest = Array.isArray(include.request) ? [...include.request] : [...DEFAULT_REQUEST_INCLUDES]; - if (include.ip) { - includeRequest.push('ip'); - } - - const extractedRequestData = extractNormalizedRequestData(req, { include: includeRequest }); - - event.request = { - ...event.request, - ...extractedRequestData, - }; - } - - if (include.user) { - const extractedUser = - additionalData.user && isPlainObject(additionalData.user) - ? extractUserData(additionalData.user, include.user) - : {}; - - if (Object.keys(extractedUser).length) { - event.user = { - ...event.user, - ...extractedUser, - }; - } - } - - if (include.ip) { - const ip = (req.headers && getClientIPAddress(req.headers)) || additionalData.ipAddress; - if (ip) { - event.user = { - ...event.user, - ip_address: ip, - }; - } - } -} /** * Transforms a `Headers` object that implements the `Web Fetch API` (https://developer.mozilla.org/en-US/docs/Web/API/Headers) into a simple key-value dict. @@ -224,53 +116,3 @@ export function extractQueryParamsFromUrl(url: string): string | undefined { return undefined; } } - -function extractNormalizedRequestData( - normalizedRequest: RequestEventData, - { include }: { include: string[] }, -): RequestEventData { - const includeKeys = include ? (Array.isArray(include) ? include : DEFAULT_REQUEST_INCLUDES) : []; - - const requestData: RequestEventData = {}; - const headers = { ...normalizedRequest.headers }; - - if (includeKeys.includes('headers')) { - requestData.headers = headers; - - // Remove the Cookie header in case cookie data should not be included in the event - if (!include.includes('cookies')) { - delete (headers as { cookie?: string }).cookie; - } - - // Remove IP headers in case IP data should not be included in the event - if (!include.includes('ip')) { - ipHeaderNames.forEach(ipHeaderName => { - // eslint-disable-next-line @typescript-eslint/no-dynamic-delete - delete (headers as Record)[ipHeaderName]; - }); - } - } - - if (includeKeys.includes('method')) { - requestData.method = normalizedRequest.method; - } - - if (includeKeys.includes('url')) { - requestData.url = normalizedRequest.url; - } - - if (includeKeys.includes('cookies')) { - const cookies = normalizedRequest.cookies || (headers && headers.cookie ? parseCookie(headers.cookie) : undefined); - requestData.cookies = cookies || {}; - } - - if (includeKeys.includes('query_string')) { - requestData.query_string = normalizedRequest.query_string; - } - - if (includeKeys.includes('data')) { - requestData.data = normalizedRequest.data; - } - - return requestData; -} diff --git a/packages/deno/src/index.ts b/packages/deno/src/index.ts index 40f43bb0d5c2..acbacc02dfd3 100644 --- a/packages/deno/src/index.ts +++ b/packages/deno/src/index.ts @@ -18,7 +18,6 @@ export type { Thread, User, } from '@sentry/core'; -export type { AddRequestDataToEventOptions } from '@sentry/core'; export type { DenoOptions } from './types'; diff --git a/packages/google-cloud-serverless/src/index.ts b/packages/google-cloud-serverless/src/index.ts index b9a367a09a18..e7c1e4296dde 100644 --- a/packages/google-cloud-serverless/src/index.ts +++ b/packages/google-cloud-serverless/src/index.ts @@ -42,7 +42,6 @@ export { flush, close, getSentryRelease, - DEFAULT_USER_INCLUDES, createGetModuleFromFilename, anrIntegration, disableAnrDetectionForCallback, diff --git a/packages/node/src/index.ts b/packages/node/src/index.ts index 4c5adac95d88..a1f5e3119ea9 100644 --- a/packages/node/src/index.ts +++ b/packages/node/src/index.ts @@ -54,8 +54,6 @@ export { cron } from './cron'; export type { NodeOptions } from './types'; -export { DEFAULT_USER_INCLUDES } from '@sentry/core'; - export { // These are custom variants that need to be used instead of the core one // As they have slightly different implementations diff --git a/packages/remix/src/index.server.ts b/packages/remix/src/index.server.ts index 41c74a4a870d..04b9a3859351 100644 --- a/packages/remix/src/index.server.ts +++ b/packages/remix/src/index.server.ts @@ -34,7 +34,6 @@ export { createTransport, cron, dedupeIntegration, - DEFAULT_USER_INCLUDES, defaultStackParser, endSession, expressErrorHandler, diff --git a/packages/solidstart/src/server/index.ts b/packages/solidstart/src/server/index.ts index d09e5c86b8c2..599739c07084 100644 --- a/packages/solidstart/src/server/index.ts +++ b/packages/solidstart/src/server/index.ts @@ -26,7 +26,6 @@ export { createTransport, cron, dedupeIntegration, - DEFAULT_USER_INCLUDES, defaultStackParser, endSession, expressErrorHandler, diff --git a/packages/sveltekit/src/server/index.ts b/packages/sveltekit/src/server/index.ts index 7df24ce61384..690869593a7b 100644 --- a/packages/sveltekit/src/server/index.ts +++ b/packages/sveltekit/src/server/index.ts @@ -26,7 +26,6 @@ export { createTransport, cron, dedupeIntegration, - DEFAULT_USER_INCLUDES, defaultStackParser, endSession, expressErrorHandler, diff --git a/packages/utils/src/index.ts b/packages/utils/src/index.ts index c0eab65004dd..c50b5c18c2f0 100644 --- a/packages/utils/src/index.ts +++ b/packages/utils/src/index.ts @@ -2,7 +2,6 @@ import { CONSOLE_LEVELS as CONSOLE_LEVELS_imported, DEFAULT_RETRY_AFTER as DEFAULT_RETRY_AFTER_imported, - DEFAULT_USER_INCLUDES as DEFAULT_USER_INCLUDES_imported, GLOBAL_OBJ as GLOBAL_OBJ_imported, LRUMap as LRUMap_imported, MAX_BAGGAGE_STRING_LENGTH as MAX_BAGGAGE_STRING_LENGTH_imported, @@ -25,7 +24,6 @@ import { addHandler as addHandler_imported, addItemToEnvelope as addItemToEnvelope_imported, addNonEnumerableProperty as addNonEnumerableProperty_imported, - addNormalizedRequestDataToEvent as addNormalizedRequestDataToEvent_imported, applyAggregateErrorsToEvent as applyAggregateErrorsToEvent_imported, baggageHeaderToDynamicSamplingContext as baggageHeaderToDynamicSamplingContext_imported, basename as basename_imported, @@ -318,9 +316,6 @@ export const objectify = objectify_imported; /** @deprecated Import from `@sentry/core` instead. */ export const makePromiseBuffer = makePromiseBuffer_imported; -/** @deprecated Import from `@sentry/core` instead. */ -export const addNormalizedRequestDataToEvent = addNormalizedRequestDataToEvent_imported; - /** @deprecated Import from `@sentry/core` instead. */ export const winterCGHeadersToDict = winterCGHeadersToDict_imported; @@ -595,9 +590,6 @@ export const memoBuilder = memoBuilder_imported; /** @deprecated Import from `@sentry/core` instead. */ export const normalizeUrlToBase = normalizeUrlToBase_imported; -/** @deprecated Import from `@sentry/core` instead. */ -export const DEFAULT_USER_INCLUDES = DEFAULT_USER_INCLUDES_imported; - /** @deprecated Import from `@sentry/core` instead. */ export const getSanitizedUrlString = getSanitizedUrlString_imported; @@ -608,7 +600,6 @@ export const parseUrl = parseUrl_imported; export const stripUrlQueryAndFragment = stripUrlQueryAndFragment_imported; import type { - AddRequestDataToEventOptions as AddRequestDataToEventOptions_imported, InternalGlobal as InternalGlobal_imported, PromiseBuffer as PromiseBuffer_imported, RateLimits as RateLimits_imported, @@ -624,8 +615,5 @@ export type SdkSource = SdkSource_imported; /** @deprecated Import from `@sentry/core` instead. */ export type RateLimits = RateLimits_imported; -/** @deprecated Import from `@sentry/core` instead. */ -export type AddRequestDataToEventOptions = AddRequestDataToEventOptions_imported; - /** @deprecated Import from `@sentry/core` instead. */ export type PromiseBuffer = PromiseBuffer_imported; diff --git a/packages/vercel-edge/src/index.ts b/packages/vercel-edge/src/index.ts index 0820a4590c70..b4f961c21dad 100644 --- a/packages/vercel-edge/src/index.ts +++ b/packages/vercel-edge/src/index.ts @@ -18,7 +18,6 @@ export type { Thread, User, } from '@sentry/core'; -export type { AddRequestDataToEventOptions } from '@sentry/core'; export type { VercelEdgeOptions } from './types';