From 5fe62fa7016108e50582a99545541602c64da863 Mon Sep 17 00:00:00 2001 From: Francesco Novy Date: Fri, 28 Aug 2026 11:00:30 +0200 Subject: [PATCH] ref(core): Move browser-only types out of core Relocate browser-specific types that were exported from `@sentry/core`'s browser entry but never used by core itself. - `HandlerDataXhr`, `HandlerDataDom`, `HandlerDataHistory`, `SentryWrappedXMLHttpRequest` and `SentryXhrData` move to `@sentry/browser-utils`, where the actual instrumentation lives. - `BrowserClientProfilingOptions` moves to `@sentry/browser` (its only consumer, the browser `Client`). Co-Authored-By: Claude Opus 4.8 (1M context) --- packages/browser-utils/src/index.ts | 11 +++- .../browser-utils/src/instrumentation/dom.ts | 2 +- .../src/instrumentation/history.ts | 2 +- .../browser-utils/src/instrumentation/xhr.ts | 2 +- packages/browser-utils/src/types.ts | 54 ++++++++++++++++--- .../test/instrumentation/xhr.test.ts | 2 +- packages/browser/src/client.ts | 24 ++++++++- .../browser/src/integrations/breadcrumbs.ts | 5 +- .../browser/src/integrations/httpclient.ts | 3 +- packages/browser/src/tracing/request.ts | 12 +---- packages/browser/test/tracing/request.test.ts | 8 +-- packages/core/src/browser-exports.ts | 9 +--- packages/core/src/types/browseroptions.ts | 23 -------- packages/core/src/types/instrument.ts | 49 ----------------- .../src/coreHandlers/handleDom.ts | 3 +- .../src/coreHandlers/handleHistory.ts | 2 +- packages/replay-internal/test/types.ts | 2 +- .../test/unit/coreHandlers/handleDom.test.ts | 2 +- .../handleNetworkBreadcrumbs.test.ts | 9 +--- 19 files changed, 102 insertions(+), 122 deletions(-) diff --git a/packages/browser-utils/src/index.ts b/packages/browser-utils/src/index.ts index ca86c78052f0..250714ddd974 100644 --- a/packages/browser-utils/src/index.ts +++ b/packages/browser-utils/src/index.ts @@ -50,4 +50,13 @@ export { isElement } from './is'; export { getAbsoluteUrl } from './instrumentation/location'; -export type { FetchHint, NetworkMetaWarning, XhrHint } from './types'; +export type { + FetchHint, + HandlerDataDom, + HandlerDataHistory, + HandlerDataXhr, + NetworkMetaWarning, + SentryWrappedXMLHttpRequest, + SentryXhrData, + XhrHint, +} from './types'; diff --git a/packages/browser-utils/src/instrumentation/dom.ts b/packages/browser-utils/src/instrumentation/dom.ts index 8b3d8cb8b2b2..d326fd281ef2 100644 --- a/packages/browser-utils/src/instrumentation/dom.ts +++ b/packages/browser-utils/src/instrumentation/dom.ts @@ -1,5 +1,5 @@ -import type { HandlerDataDom } from '@sentry/core'; import { addHandler, addNonEnumerableProperty, fill, maybeInstrument, triggerHandlers, uuid4 } from '@sentry/core'; +import type { HandlerDataDom } from '../types'; import { WINDOW } from '../types'; type SentryWrappedTarget = HTMLElement & { _sentryId?: string }; diff --git a/packages/browser-utils/src/instrumentation/history.ts b/packages/browser-utils/src/instrumentation/history.ts index 76bf43f7b398..0c5d1e6333e6 100644 --- a/packages/browser-utils/src/instrumentation/history.ts +++ b/packages/browser-utils/src/instrumentation/history.ts @@ -1,5 +1,5 @@ -import type { HandlerDataHistory } from '@sentry/core'; import { addHandler, fill, maybeInstrument, supportsHistory, triggerHandlers } from '@sentry/core'; +import type { HandlerDataHistory } from '../types'; import { WINDOW } from '../types'; let lastHref: string | undefined; diff --git a/packages/browser-utils/src/instrumentation/xhr.ts b/packages/browser-utils/src/instrumentation/xhr.ts index 9775a5441da7..6887723ae1d3 100644 --- a/packages/browser-utils/src/instrumentation/xhr.ts +++ b/packages/browser-utils/src/instrumentation/xhr.ts @@ -1,5 +1,5 @@ -import type { HandlerDataXhr, SentryWrappedXMLHttpRequest } from '@sentry/core'; import { addHandler, isString, maybeInstrument, timestampInSeconds, triggerHandlers } from '@sentry/core'; +import type { HandlerDataXhr, SentryWrappedXMLHttpRequest } from '../types'; import { WINDOW } from '../types'; export const SENTRY_XHR_DATA_KEY = '__sentry_xhr_v3__'; diff --git a/packages/browser-utils/src/types.ts b/packages/browser-utils/src/types.ts index f2d19dc2e561..4639a40fedb6 100644 --- a/packages/browser-utils/src/types.ts +++ b/packages/browser-utils/src/types.ts @@ -1,9 +1,4 @@ -import type { - FetchBreadcrumbHint, - HandlerDataFetch, - SentryWrappedXMLHttpRequest, - XhrBreadcrumbHint, -} from '@sentry/core'; +import type { FetchBreadcrumbHint, HandlerDataFetch, XhrBreadcrumbHint } from '@sentry/core'; import { GLOBAL_OBJ } from '@sentry/core'; export const WINDOW = GLOBAL_OBJ as typeof GLOBAL_OBJ & @@ -29,3 +24,50 @@ export type FetchHint = FetchBreadcrumbHint & { input: HandlerDataFetch['args']; response: Response; }; + +// This should be: null | Blob | BufferSource | FormData | URLSearchParams | string +// But since not all of those are available in node, we just use `unknown` here for now +type XHRSendInput = unknown; + +export interface SentryWrappedXMLHttpRequest { + __sentry_xhr_v3__?: SentryXhrData; + __sentry_own_request__?: boolean; + // span id for the xhr request + __sentry_xhr_span_id__?: string; + setRequestHeader?: (key: string, val: string) => void; + getResponseHeader?: (key: string) => string | null; +} + +// WARNING: When the shape of this type is changed bump the version in `SentryWrappedXMLHttpRequest` +export interface SentryXhrData { + method: string; + url: string; + status_code?: number; + body?: XHRSendInput; + request_body_size?: number; + response_body_size?: number; + request_headers: Record; +} + +export interface HandlerDataXhr { + xhr: SentryWrappedXMLHttpRequest; + startTimestamp?: number; + endTimestamp?: number; + error?: unknown; + // This is to be consumed by the HttpClient integration + virtualError?: unknown; +} + +export interface HandlerDataDom { + // TODO: Replace `object` here with a vendored type for browser Events. We can't depend on the `DOM` or `react` TS types package here. + event: object | { target: object }; + name: string; + global?: boolean; +} + +export interface HandlerDataHistory { + /** The full URL of the previous page */ + from: string | undefined; + /** The full URL of the new page */ + to: string; +} diff --git a/packages/browser-utils/test/instrumentation/xhr.test.ts b/packages/browser-utils/test/instrumentation/xhr.test.ts index 81734d3abf89..91991a579439 100644 --- a/packages/browser-utils/test/instrumentation/xhr.test.ts +++ b/packages/browser-utils/test/instrumentation/xhr.test.ts @@ -1,6 +1,6 @@ -import type { HandlerDataXhr } from '@sentry/core'; import { afterEach, describe, expect, it, vi } from 'vitest'; import { addXhrInstrumentationHandler, instrumentXHR } from '../../src/instrumentation/xhr'; +import type { HandlerDataXhr } from '../../src/types'; import { WINDOW } from '../../src/types'; const win = WINDOW as typeof WINDOW & { XMLHttpRequest?: typeof XMLHttpRequest }; diff --git a/packages/browser/src/client.ts b/packages/browser/src/client.ts index 211befa2c933..72cba459b0c1 100644 --- a/packages/browser/src/client.ts +++ b/packages/browser/src/client.ts @@ -1,5 +1,4 @@ import type { - BrowserClientProfilingOptions, BrowserClientReplayOptions, ClientOptions, Event, @@ -19,6 +18,29 @@ import type { BrowserTransportOptions } from './transports/types'; */ declare const __SENTRY_RELEASE__: string | undefined; +export type BrowserClientProfilingOptions = { + /** + * Sets profiling session sample rate for the entire profiling session. + * + * A profiling session corresponds to a user session, meaning it is set once at integration initialization and + * persisted until the next page reload. This rate determines what percentage of user sessions will have profiling enabled. + * @default 0 + */ + profileSessionSampleRate?: number; + + /** + * Set the lifecycle mode of the profiler. + * - **manual**: The profiler will be manually started and stopped via `startProfiler`/`stopProfiler`. + * If a session is sampled, is dependent on the `profileSessionSampleRate`. + * - **trace**: The profiler will be automatically started when a root span exists and stopped when there are no + * more sampled root spans. Whether a session is sampled, is dependent on the `profileSessionSampleRate` and the + * existing sampling configuration for tracing (`tracesSampleRate`/`tracesSampler`). + * + * @default 'manual' + */ + profileLifecycle?: 'manual' | 'trace'; +}; + type BrowserSpecificOptions = BrowserClientReplayOptions & BrowserClientProfilingOptions & { /** If configured, this URL will be used as base URL for lazy loading integration. */ diff --git a/packages/browser/src/integrations/breadcrumbs.ts b/packages/browser/src/integrations/breadcrumbs.ts index 936702ca9c6a..f627ea10d31e 100644 --- a/packages/browser/src/integrations/breadcrumbs.ts +++ b/packages/browser/src/integrations/breadcrumbs.ts @@ -7,10 +7,7 @@ import type { FetchBreadcrumbData, FetchBreadcrumbHint, HandlerDataConsole, - HandlerDataDom, HandlerDataFetch, - HandlerDataHistory, - HandlerDataXhr, IntegrationFn, XhrBreadcrumbData, XhrBreadcrumbHint, @@ -28,7 +25,7 @@ import { safeJoin, severityLevelFromString, } from '@sentry/core/browser'; -import type { FetchHint, XhrHint } from '@sentry/browser-utils'; +import type { FetchHint, HandlerDataDom, HandlerDataHistory, HandlerDataXhr, XhrHint } from '@sentry/browser-utils'; import { addClickKeypressInstrumentationHandler, addHistoryInstrumentationHandler, diff --git a/packages/browser/src/integrations/httpclient.ts b/packages/browser/src/integrations/httpclient.ts index 12cf929d0026..40da32d73674 100644 --- a/packages/browser/src/integrations/httpclient.ts +++ b/packages/browser/src/integrations/httpclient.ts @@ -1,4 +1,4 @@ -import type { Client, Event as SentryEvent, IntegrationFn, SentryWrappedXMLHttpRequest } from '@sentry/core/browser'; +import type { Client, Event as SentryEvent, IntegrationFn } from '@sentry/core/browser'; import { _INTERNAL_filterCookies, _INTERNAL_filterKeyValueData, @@ -12,6 +12,7 @@ import { isSentryRequestUrl, supportsNativeFetch, } from '@sentry/core/browser'; +import type { SentryWrappedXMLHttpRequest } from '@sentry/browser-utils'; import { addXhrInstrumentationHandler, SENTRY_XHR_DATA_KEY } from '@sentry/browser-utils'; import { DEBUG_BUILD } from '../debug-build'; diff --git a/packages/browser/src/tracing/request.ts b/packages/browser/src/tracing/request.ts index 5ab075ca0620..817676fe728a 100644 --- a/packages/browser/src/tracing/request.ts +++ b/packages/browser/src/tracing/request.ts @@ -1,13 +1,5 @@ /* eslint-disable max-lines */ -import type { - Client, - HandlerDataXhr, - RequestHookInfo, - ResponseHookInfo, - SentryWrappedXMLHttpRequest, - Span, - SpanTimeInput, -} from '@sentry/core/browser'; +import type { Client, RequestHookInfo, ResponseHookInfo, Span, SpanTimeInput } from '@sentry/core/browser'; import { addFetchInstrumentationHandler, getActiveSpan, @@ -32,7 +24,7 @@ import { stripUrlQueryAndFragment, timestampInSeconds, } from '@sentry/core/browser'; -import type { XhrHint } from '@sentry/browser-utils'; +import type { HandlerDataXhr, SentryWrappedXMLHttpRequest, XhrHint } from '@sentry/browser-utils'; import { filterCollectedUrl, filterCollectedUrlQuery } from '@sentry/core'; import { addPerformanceInstrumentationHandler, diff --git a/packages/browser/test/tracing/request.test.ts b/packages/browser/test/tracing/request.test.ts index f3cd82b86aea..f73c718ec0a6 100644 --- a/packages/browser/test/tracing/request.test.ts +++ b/packages/browser/test/tracing/request.test.ts @@ -90,7 +90,7 @@ describe('instrumentOutgoingRequests', () => { }); it('creates a QUERY XHR span with the QUERY method attribute', () => { - let xhrHandler: ((data: utils.HandlerDataXhr) => void) | undefined; + let xhrHandler: ((data: browserUtils.HandlerDataXhr) => void) | undefined; let requestSpan: utils.Span | undefined; vi.spyOn(browserUtils, 'addXhrInstrumentationHandler').mockImplementation(handler => { @@ -117,7 +117,7 @@ describe('instrumentOutgoingRequests', () => { setRequestHeader: vi.fn(), }, startTimestamp: Date.now(), - } as utils.HandlerDataXhr); + } as browserUtils.HandlerDataXhr); expect(xhrHandler).toBeDefined(); expect(requestSpan).toBeDefined(); @@ -134,7 +134,7 @@ describe('instrumentOutgoingRequests', () => { it('uses the active propagation context for an ignored child span', () => { const activeSpan = new utils.SentryNonRecordingSpan(); const ignoredSpan = new utils.SentryNonRecordingSpan({ dropReason: 'ignored' }); - let xhrHandler: ((data: utils.HandlerDataXhr) => void) | undefined; + let xhrHandler: ((data: browserUtils.HandlerDataXhr) => void) | undefined; vi.spyOn(browserUtils, 'addXhrInstrumentationHandler').mockImplementation(handler => { xhrHandler = handler; @@ -163,7 +163,7 @@ describe('instrumentOutgoingRequests', () => { setRequestHeader: vi.fn(), }, startTimestamp: Date.now(), - } as utils.HandlerDataXhr); + } as browserUtils.HandlerDataXhr); expect(xhrHandler).toBeDefined(); expect(getTraceDataSpy).toHaveBeenCalledWith({ diff --git a/packages/core/src/browser-exports.ts b/packages/core/src/browser-exports.ts index 639ba3b90b39..e758c03cb5a4 100644 --- a/packages/core/src/browser-exports.ts +++ b/packages/core/src/browser-exports.ts @@ -18,11 +18,4 @@ export { spanStreamingIntegration } from './integrations/browserSpanStreaming'; export { getLocationHref } from './utils/browser'; export { supportsDOMError, supportsHistory, supportsNativeFetch, supportsReportingObserver } from './utils/supports'; export type { XhrBreadcrumbData, XhrBreadcrumbHint } from './types/breadcrumb'; -export type { - HandlerDataXhr, - HandlerDataDom, - HandlerDataHistory, - SentryXhrData, - SentryWrappedXMLHttpRequest, -} from './types/instrument'; -export type { BrowserClientReplayOptions, BrowserClientProfilingOptions } from './types/browseroptions'; +export type { BrowserClientReplayOptions } from './types/browseroptions'; diff --git a/packages/core/src/types/browseroptions.ts b/packages/core/src/types/browseroptions.ts index c9ee66c628b6..3beb3752be99 100644 --- a/packages/core/src/types/browseroptions.ts +++ b/packages/core/src/types/browseroptions.ts @@ -16,26 +16,3 @@ export type BrowserClientReplayOptions = { */ replaysOnErrorSampleRate?: number; }; - -export type BrowserClientProfilingOptions = { - /** - * Sets profiling session sample rate for the entire profiling session. - * - * A profiling session corresponds to a user session, meaning it is set once at integration initialization and - * persisted until the next page reload. This rate determines what percentage of user sessions will have profiling enabled. - * @default 0 - */ - profileSessionSampleRate?: number; - - /** - * Set the lifecycle mode of the profiler. - * - **manual**: The profiler will be manually started and stopped via `startProfiler`/`stopProfiler`. - * If a session is sampled, is dependent on the `profileSessionSampleRate`. - * - **trace**: The profiler will be automatically started when a root span exists and stopped when there are no - * more sampled root spans. Whether a session is sampled, is dependent on the `profileSessionSampleRate` and the - * existing sampling configuration for tracing (`tracesSampleRate`/`tracesSampler`). - * - * @default 'manual' - */ - profileLifecycle?: 'manual' | 'trace'; -}; diff --git a/packages/core/src/types/instrument.ts b/packages/core/src/types/instrument.ts index 7caab9e3dacf..109a7ddfeeba 100644 --- a/packages/core/src/types/instrument.ts +++ b/packages/core/src/types/instrument.ts @@ -1,42 +1,7 @@ -// This should be: null | Blob | BufferSource | FormData | URLSearchParams | string -// But since not all of those are available in node, we just export `unknown` here for now - import type { WebFetchHeaders } from './webfetchapi'; -// Make sure to cast it where needed! -type XHRSendInput = unknown; - export type ConsoleLevel = 'debug' | 'info' | 'warn' | 'error' | 'log' | 'assert' | 'trace'; -export interface SentryWrappedXMLHttpRequest { - __sentry_xhr_v3__?: SentryXhrData; - __sentry_own_request__?: boolean; - // span id for the xhr request - __sentry_xhr_span_id__?: string; - setRequestHeader?: (key: string, val: string) => void; - getResponseHeader?: (key: string) => string | null; -} - -// WARNING: When the shape of this type is changed bump the version in `SentryWrappedXMLHttpRequest` -export interface SentryXhrData { - method: string; - url: string; - status_code?: number; - body?: XHRSendInput; - request_body_size?: number; - response_body_size?: number; - request_headers: Record; -} - -export interface HandlerDataXhr { - xhr: SentryWrappedXMLHttpRequest; - startTimestamp?: number; - endTimestamp?: number; - error?: unknown; - // This is to be consumed by the HttpClient integration - virtualError?: unknown; -} - interface SentryFetchData { method: string; url: string; @@ -66,26 +31,12 @@ export interface HandlerDataFetch { headers?: WebFetchHeaders; } -export interface HandlerDataDom { - // TODO: Replace `object` here with a vendored type for browser Events. We can't depend on the `DOM` or `react` TS types package here. - event: object | { target: object }; - name: string; - global?: boolean; -} - export interface HandlerDataConsole { level: ConsoleLevel; // eslint-disable-next-line @typescript-eslint/no-explicit-any args: any[]; } -export interface HandlerDataHistory { - /** The full URL of the previous page */ - from: string | undefined; - /** The full URL of the new page */ - to: string; -} - export interface HandlerDataError { column?: number; error?: Error; diff --git a/packages/replay-internal/src/coreHandlers/handleDom.ts b/packages/replay-internal/src/coreHandlers/handleDom.ts index 2f8ef16c5671..4c3171aa3276 100644 --- a/packages/replay-internal/src/coreHandlers/handleDom.ts +++ b/packages/replay-internal/src/coreHandlers/handleDom.ts @@ -1,5 +1,6 @@ +import type { HandlerDataDom } from '@sentry/browser-utils'; import { htmlTreeAsString } from '@sentry/browser-utils'; -import type { Breadcrumb, HandlerDataDom } from '@sentry/core'; +import type { Breadcrumb } from '@sentry/core'; import { record } from '@sentry/rrweb'; import type { serializedElementNodeWithId, serializedNodeWithId } from '@sentry/rrweb-snapshot'; import { NodeType } from '@sentry/rrweb-snapshot'; diff --git a/packages/replay-internal/src/coreHandlers/handleHistory.ts b/packages/replay-internal/src/coreHandlers/handleHistory.ts index aa85757e3a3e..41d6009e380b 100644 --- a/packages/replay-internal/src/coreHandlers/handleHistory.ts +++ b/packages/replay-internal/src/coreHandlers/handleHistory.ts @@ -1,4 +1,4 @@ -import type { HandlerDataHistory } from '@sentry/core'; +import type { HandlerDataHistory } from '@sentry/browser-utils'; import type { HistoryData, ReplayContainer, ReplayPerformanceEntry } from '../types'; import { createPerformanceSpans } from '../util/createPerformanceSpans'; diff --git a/packages/replay-internal/test/types.ts b/packages/replay-internal/test/types.ts index ff28aa40a5f7..0bd0fa7e249e 100644 --- a/packages/replay-internal/test/types.ts +++ b/packages/replay-internal/test/types.ts @@ -1,3 +1,3 @@ -import type { HandlerDataDom } from '@sentry/core'; +import type { HandlerDataDom } from '@sentry/browser-utils'; export type DomHandler = (data: HandlerDataDom) => void; diff --git a/packages/replay-internal/test/unit/coreHandlers/handleDom.test.ts b/packages/replay-internal/test/unit/coreHandlers/handleDom.test.ts index 1512f3481de9..88ea52b8c9ac 100644 --- a/packages/replay-internal/test/unit/coreHandlers/handleDom.test.ts +++ b/packages/replay-internal/test/unit/coreHandlers/handleDom.test.ts @@ -2,7 +2,7 @@ * @vitest-environment jsdom */ -import type { HandlerDataDom } from '@sentry/core'; +import type { HandlerDataDom } from '@sentry/browser-utils'; import { describe, expect, test } from 'vitest'; import { handleDom } from '../../../src/coreHandlers/handleDom'; diff --git a/packages/replay-internal/test/unit/coreHandlers/handleNetworkBreadcrumbs.test.ts b/packages/replay-internal/test/unit/coreHandlers/handleNetworkBreadcrumbs.test.ts index 0179724f2a2c..b785435bd312 100644 --- a/packages/replay-internal/test/unit/coreHandlers/handleNetworkBreadcrumbs.test.ts +++ b/packages/replay-internal/test/unit/coreHandlers/handleNetworkBreadcrumbs.test.ts @@ -3,13 +3,8 @@ */ import '../../utils/mock-internal-setTimeout'; -import type { - Breadcrumb, - BreadcrumbHint, - FetchBreadcrumbHint, - SentryWrappedXMLHttpRequest, - XhrBreadcrumbHint, -} from '@sentry/core'; +import type { Breadcrumb, BreadcrumbHint, FetchBreadcrumbHint, XhrBreadcrumbHint } from '@sentry/core'; +import type { SentryWrappedXMLHttpRequest } from '@sentry/browser-utils'; import { SENTRY_XHR_DATA_KEY } from '@sentry/browser-utils'; import { beforeAll, beforeEach, describe, expect, it, vi } from 'vitest'; import { NETWORK_BODY_MAX_SIZE } from '../../../src/constants';