From a23b8de929fdec3d7834f18b43325d71d9396eba Mon Sep 17 00:00:00 2001 From: Francesco Novy Date: Fri, 28 Aug 2026 09:57:35 +0200 Subject: [PATCH 1/2] ref(core)!: Remove `getLocationHref` export from core --- packages/browser/src/helpers.ts | 14 +++++++++++++- .../browser/src/integrations/globalhandlers.ts | 3 +-- .../src/tracing/browserTracingIntegration.ts | 3 +-- packages/browser/src/tracing/request.ts | 2 +- .../browser/src/utils/detectBrowserExtension.ts | 4 ++-- packages/browser/test/sdk.test.ts | 3 ++- packages/browser/test/tracing/request.test.ts | 7 ++++--- packages/core/src/browser-exports.ts | 1 - packages/feedback/src/core/sendFeedback.ts | 17 ++++++++++++++--- 9 files changed, 38 insertions(+), 16 deletions(-) diff --git a/packages/browser/src/helpers.ts b/packages/browser/src/helpers.ts index 5e31528b6dea..e266a10ccd3c 100644 --- a/packages/browser/src/helpers.ts +++ b/packages/browser/src/helpers.ts @@ -4,7 +4,6 @@ import { addExceptionTypeValue, addNonEnumerableProperty, captureException, - getLocationHref, getOriginalFunction, GLOBAL_OBJ, markFunctionWrapped, @@ -205,3 +204,16 @@ export function getHttpRequestData(): { url: string; headers: Record { const consoleErrorSpy = vi.spyOn(console, 'error').mockImplementation(() => {}); const locationHrefSpy = vi - .spyOn(SentryCore, 'getLocationHref') + .spyOn(helpers, 'getLocationHref') .mockImplementation(() => `${extensionProtocol}://mock-extension-id/dedicated-page.html`); Object.defineProperty(WINDOW, 'browser', { value: { runtime: { id: 'mock-extension-id' } }, writable: true }); diff --git a/packages/browser/test/tracing/request.test.ts b/packages/browser/test/tracing/request.test.ts index f3cd82b86aea..7aa049391de9 100644 --- a/packages/browser/test/tracing/request.test.ts +++ b/packages/browser/test/tracing/request.test.ts @@ -1,5 +1,6 @@ import type { Client } from '@sentry/core/browser'; import * as utils from '@sentry/core/browser'; +import * as helpers from '../../src/helpers'; import * as browserUtils from '@sentry/browser-utils'; import { HTTP_REQUEST_METHOD } from '@sentry/conventions/attributes'; import type { MockInstance } from 'vitest'; @@ -193,7 +194,7 @@ describe('shouldAttachHeaders', () => { let locationHrefSpy: MockInstance; beforeEach(() => { - locationHrefSpy = vi.spyOn(utils, 'getLocationHref').mockImplementation(() => 'https://my-origin.com'); + locationHrefSpy = vi.spyOn(helpers, 'getLocationHref').mockImplementation(() => 'https://my-origin.com'); }); afterEach(() => { @@ -232,7 +233,7 @@ describe('shouldAttachHeaders', () => { beforeEach(() => { locationHrefSpy = vi - .spyOn(utils, 'getLocationHref') + .spyOn(helpers, 'getLocationHref') .mockImplementation(() => 'https://my-origin.com/api/my-route'); }); @@ -364,7 +365,7 @@ describe('shouldAttachHeaders', () => { let locationHrefSpy: MockInstance; beforeEach(() => { - locationHrefSpy = vi.spyOn(utils, 'getLocationHref').mockImplementation(() => ''); + locationHrefSpy = vi.spyOn(helpers, 'getLocationHref').mockImplementation(() => ''); }); afterEach(() => { diff --git a/packages/core/src/browser-exports.ts b/packages/core/src/browser-exports.ts index 639ba3b90b39..a5722843187d 100644 --- a/packages/core/src/browser-exports.ts +++ b/packages/core/src/browser-exports.ts @@ -15,7 +15,6 @@ export { startIdleSpan } from './tracing/idleSpan'; 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 { diff --git a/packages/feedback/src/core/sendFeedback.ts b/packages/feedback/src/core/sendFeedback.ts index 35c829ab0869..3c1d2c97c9fc 100644 --- a/packages/feedback/src/core/sendFeedback.ts +++ b/packages/feedback/src/core/sendFeedback.ts @@ -6,8 +6,8 @@ import type { SendFeedbackParams, TransportMakeRequestResponse, } from '@sentry/core'; -import { captureFeedback, getClient, getCurrentScope, getLocationHref } from '@sentry/core'; -import { FEEDBACK_API_SOURCE } from '../constants'; +import { captureFeedback, getClient, getCurrentScope } from '@sentry/core'; +import { FEEDBACK_API_SOURCE, WINDOW } from '../constants'; import { createFeedbackError } from '../util/createFeedbackError'; /** @@ -36,7 +36,7 @@ export const sendFeedback: SendFeedback = ( const eventId = captureFeedback( { source: FEEDBACK_API_SOURCE, - url: getLocationHref(), + url: _getLocationHref(), ...params, }, hint, @@ -113,3 +113,14 @@ export const sendFeedback: SendFeedback = ( * }, * } */ + +/** + * A safe form of location.href. + */ +function _getLocationHref(): string { + try { + return WINDOW.document.location.href; + } catch { + return ''; + } +} From 6dfc9f57658e314799832be10bbab78964ae6606 Mon Sep 17 00:00:00 2001 From: Francesco Novy Date: Fri, 28 Aug 2026 10:06:38 +0200 Subject: [PATCH 2/2] ref(browser-utils): Move getLocationHref to browser-utils Move the browser `getLocationHref` helper out of `@sentry/browser` into `@sentry/browser-utils` so it can be shared. Update browser consumers and `replay-internal` to import it from there. Co-Authored-By: Claude Opus 4.8 (1M context) --- packages/browser-utils/src/getLocationHref.ts | 12 ++++++++++++ packages/browser-utils/src/index.ts | 2 ++ packages/browser/src/helpers.ts | 14 +------------- .../browser/src/integrations/globalhandlers.ts | 3 ++- .../src/tracing/browserTracingIntegration.ts | 3 ++- packages/browser/src/tracing/request.ts | 2 +- .../browser/src/utils/detectBrowserExtension.ts | 3 ++- packages/browser/test/sdk.test.ts | 4 ++-- packages/browser/test/tracing/request.test.ts | 7 +++---- .../src/coreHandlers/handleBeforeSendEvent.ts | 2 +- 10 files changed, 28 insertions(+), 24 deletions(-) create mode 100644 packages/browser-utils/src/getLocationHref.ts diff --git a/packages/browser-utils/src/getLocationHref.ts b/packages/browser-utils/src/getLocationHref.ts new file mode 100644 index 000000000000..75675a727e25 --- /dev/null +++ b/packages/browser-utils/src/getLocationHref.ts @@ -0,0 +1,12 @@ +import { WINDOW } from './types'; + +/** + * A safe form of location.href. + */ +export function getLocationHref(): string { + try { + return WINDOW.document?.location.href ?? ''; + } catch { + return ''; + } +} diff --git a/packages/browser-utils/src/index.ts b/packages/browser-utils/src/index.ts index ca86c78052f0..327d78aca1a1 100644 --- a/packages/browser-utils/src/index.ts +++ b/packages/browser-utils/src/index.ts @@ -22,6 +22,8 @@ export { interactionsIntegration } from './performance/interactions'; export { isBotUserAgent } from './isBotUserAgent'; +export { getLocationHref } from './getLocationHref'; + export { userTimingIntegration } from './performance/userTiming'; export { extractNetworkProtocol } from './performance/utils'; diff --git a/packages/browser/src/helpers.ts b/packages/browser/src/helpers.ts index e266a10ccd3c..32007ad33954 100644 --- a/packages/browser/src/helpers.ts +++ b/packages/browser/src/helpers.ts @@ -9,6 +9,7 @@ import { markFunctionWrapped, withScope, } from '@sentry/core/browser'; +import { getLocationHref } from '@sentry/browser-utils'; export const WINDOW = GLOBAL_OBJ as typeof GLOBAL_OBJ & Window; @@ -204,16 +205,3 @@ export function getHttpRequestData(): { url: string; headers: Record { const consoleErrorSpy = vi.spyOn(console, 'error').mockImplementation(() => {}); const locationHrefSpy = vi - .spyOn(helpers, 'getLocationHref') + .spyOn(browserUtils, 'getLocationHref') .mockImplementation(() => `${extensionProtocol}://mock-extension-id/dedicated-page.html`); Object.defineProperty(WINDOW, 'browser', { value: { runtime: { id: 'mock-extension-id' } }, writable: true }); diff --git a/packages/browser/test/tracing/request.test.ts b/packages/browser/test/tracing/request.test.ts index 7aa049391de9..c75fccebb6a1 100644 --- a/packages/browser/test/tracing/request.test.ts +++ b/packages/browser/test/tracing/request.test.ts @@ -1,6 +1,5 @@ import type { Client } from '@sentry/core/browser'; import * as utils from '@sentry/core/browser'; -import * as helpers from '../../src/helpers'; import * as browserUtils from '@sentry/browser-utils'; import { HTTP_REQUEST_METHOD } from '@sentry/conventions/attributes'; import type { MockInstance } from 'vitest'; @@ -194,7 +193,7 @@ describe('shouldAttachHeaders', () => { let locationHrefSpy: MockInstance; beforeEach(() => { - locationHrefSpy = vi.spyOn(helpers, 'getLocationHref').mockImplementation(() => 'https://my-origin.com'); + locationHrefSpy = vi.spyOn(browserUtils, 'getLocationHref').mockImplementation(() => 'https://my-origin.com'); }); afterEach(() => { @@ -233,7 +232,7 @@ describe('shouldAttachHeaders', () => { beforeEach(() => { locationHrefSpy = vi - .spyOn(helpers, 'getLocationHref') + .spyOn(browserUtils, 'getLocationHref') .mockImplementation(() => 'https://my-origin.com/api/my-route'); }); @@ -365,7 +364,7 @@ describe('shouldAttachHeaders', () => { let locationHrefSpy: MockInstance; beforeEach(() => { - locationHrefSpy = vi.spyOn(helpers, 'getLocationHref').mockImplementation(() => ''); + locationHrefSpy = vi.spyOn(browserUtils, 'getLocationHref').mockImplementation(() => ''); }); afterEach(() => { diff --git a/packages/replay-internal/src/coreHandlers/handleBeforeSendEvent.ts b/packages/replay-internal/src/coreHandlers/handleBeforeSendEvent.ts index d529bf425ce7..02dbecb755d2 100644 --- a/packages/replay-internal/src/coreHandlers/handleBeforeSendEvent.ts +++ b/packages/replay-internal/src/coreHandlers/handleBeforeSendEvent.ts @@ -1,5 +1,5 @@ +import { getLocationHref } from '@sentry/browser-utils'; import type { ErrorEvent, Event } from '@sentry/core'; -import { getLocationHref } from '@sentry/core'; import type { ReplayContainer } from '../types'; import { createBreadcrumb } from '../util/createBreadcrumb'; import { isErrorEvent } from '../util/eventUtils';