Skip to content

ref(browser): Move utils to @sentry-internal/browser-utils #11451

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Apr 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions packages/browser-utils/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
module.exports = {
extends: ['../../.eslintrc.js'],
env: {
browser: true,
},
overrides: [
{
files: ['src/**'],
Expand Down
2 changes: 1 addition & 1 deletion packages/browser-utils/src/browser/backgroundtab.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { SPAN_STATUS_ERROR, getActiveSpan, getRootSpan } from '@sentry/core';
import { spanToJSON } from '@sentry/core';
import { logger } from '@sentry/utils';

import { DEBUG_BUILD } from '../common/debug-build';
import { DEBUG_BUILD } from '../debug-build';
import { WINDOW } from './types';

/**
Expand Down
13 changes: 4 additions & 9 deletions packages/browser-utils/src/browser/browserTracingIntegration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,10 @@ import {
} from '@sentry/core';
import type { Client, IntegrationFn, StartSpanOptions, TransactionSource } from '@sentry/types';
import type { Span } from '@sentry/types';
import {
addHistoryInstrumentationHandler,
browserPerformanceTimeOrigin,
getDomElement,
logger,
uuid4,
} from '@sentry/utils';

import { DEBUG_BUILD } from '../common/debug-build';
import { browserPerformanceTimeOrigin, getDomElement, logger, uuid4 } from '@sentry/utils';

import { DEBUG_BUILD } from '../debug-build';
import { addHistoryInstrumentationHandler } from '../instrument/history';
import { registerBackgroundTabDetection } from './backgroundtab';
import {
addPerformanceEntries,
Expand Down
2 changes: 1 addition & 1 deletion packages/browser-utils/src/browser/instrument.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { getFunctionName, logger } from '@sentry/utils';

import { DEBUG_BUILD } from '../common/debug-build';
import { DEBUG_BUILD } from '../debug-build';
import { onCLS } from './web-vitals/getCLS';
import { onFID } from './web-vitals/getFID';
import { onLCP } from './web-vitals/getLCP';
Expand Down
2 changes: 1 addition & 1 deletion packages/browser-utils/src/browser/metrics/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import type { Measurements, Span, SpanAttributes, StartSpanOptions } from '@sent
import { browserPerformanceTimeOrigin, getComponentName, htmlTreeAsString, logger, parseUrl } from '@sentry/utils';

import { spanToJSON } from '@sentry/core';
import { DEBUG_BUILD } from '../../common/debug-build';
import { DEBUG_BUILD } from '../../debug-build';
import {
addClsInstrumentationHandler,
addFidInstrumentationHandler,
Expand Down
3 changes: 1 addition & 2 deletions packages/browser-utils/src/browser/request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,13 @@ import {
import type { HandlerDataXhr, SentryWrappedXMLHttpRequest, Span } from '@sentry/types';
import {
BAGGAGE_HEADER_NAME,
SENTRY_XHR_DATA_KEY,
addFetchInstrumentationHandler,
addXhrInstrumentationHandler,
browserPerformanceTimeOrigin,
dynamicSamplingContextToSentryBaggageHeader,
generateSentryTraceHeader,
stringMatchesSomePattern,
} from '@sentry/utils';
import { SENTRY_XHR_DATA_KEY, addXhrInstrumentationHandler } from '../instrument/xhr';

import { addPerformanceInstrumentationHandler } from './instrument';
import { WINDOW } from './types';
Expand Down
9 changes: 9 additions & 0 deletions packages/browser-utils/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,13 @@ export {
addLcpInstrumentationHandler,
} from './browser';

export { addClickKeypressInstrumentationHandler } from './instrument/dom';

export { addHistoryInstrumentationHandler } from './instrument/history';

export {
addXhrInstrumentationHandler,
SENTRY_XHR_DATA_KEY,
} from './instrument/xhr';

export type { RequestInstrumentationOptions } from './browser';
Original file line number Diff line number Diff line change
@@ -1,13 +1,7 @@
// TODO(v8): Move everything in this file into the browser package. Nothing here is generic and we run risk of leaking browser types into non-browser packages.

/* eslint-disable @typescript-eslint/no-explicit-any */
/* eslint-disable @typescript-eslint/ban-types */
import type { HandlerDataDom } from '@sentry/types';

import { uuid4 } from '../misc';
import { addNonEnumerableProperty, fill } from '../object';
import { GLOBAL_OBJ } from '../worldwide';
import { addHandler, maybeInstrument, triggerHandlers } from './_handlers';
import { addHandler, addNonEnumerableProperty, fill, maybeInstrument, triggerHandlers, uuid4 } from '@sentry/utils';
import { WINDOW } from '../browser/types';

type SentryWrappedTarget = HTMLElement & { _sentryId?: string };

Expand All @@ -25,14 +19,13 @@ type RemoveEventListener = (
type InstrumentedElement = Element & {
__sentry_instrumentation_handlers__?: {
[key in 'click' | 'keypress']?: {
handler?: Function;
handler?: unknown;
/** The number of custom listeners attached to this element */
refCount: number;
};
};
};

const WINDOW = GLOBAL_OBJ as unknown as Window;
const DEBOUNCE_DURATION = 1000;

let debounceTimerID: number | undefined;
Expand Down Expand Up @@ -71,7 +64,7 @@ export function instrumentDOM(): void {
// could potentially prevent the event from bubbling up to our global listeners. This way, our handler are still
// guaranteed to fire at least once.)
['EventTarget', 'Node'].forEach((target: string) => {
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any
const proto = (WINDOW as any)[target] && (WINDOW as any)[target].prototype;
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, no-prototype-builtins
if (!proto || !proto.hasOwnProperty || !proto.hasOwnProperty('addEventListener')) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,6 @@
// TODO(v8): Move everything in this file into the browser package. Nothing here is generic and we run risk of leaking browser types into non-browser packages.

/* eslint-disable @typescript-eslint/no-explicit-any */
/* eslint-disable @typescript-eslint/ban-types */
import type { HandlerDataHistory } from '@sentry/types';

import { fill } from '../object';
import { supportsHistory } from '../supports';
import { GLOBAL_OBJ } from '../worldwide';
import { addHandler, maybeInstrument, triggerHandlers } from './_handlers';

const WINDOW = GLOBAL_OBJ as unknown as Window;
import { addHandler, fill, maybeInstrument, supportsHistory, triggerHandlers } from '@sentry/utils';
import { WINDOW } from '../browser/types';

let lastHref: string | undefined;

Expand All @@ -33,7 +24,7 @@ function instrumentHistory(): void {
}

const oldOnPopState = WINDOW.onpopstate;
WINDOW.onpopstate = function (this: WindowEventHandlers, ...args: any[]): any {
WINDOW.onpopstate = function (this: WindowEventHandlers, ...args: unknown[]) {
const to = WINDOW.location.href;
// keep track of the current URL state, as we always receive only the updated state
const from = lastHref;
Expand All @@ -53,7 +44,7 @@ function instrumentHistory(): void {
};

function historyReplacementFunction(originalHistoryFunction: () => void): () => void {
return function (this: History, ...args: any[]): void {
return function (this: History, ...args: unknown[]): void {
const url = args.length > 2 ? args[2] : undefined;
if (url) {
// coerce to string (this is what pushState does)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,12 @@
// TODO(v8): Move everything in this file into the browser package. Nothing here is generic and we run risk of leaking browser types into non-browser packages.

/* eslint-disable @typescript-eslint/no-explicit-any */
/* eslint-disable @typescript-eslint/ban-types */
import type { HandlerDataXhr, SentryWrappedXMLHttpRequest, WrappedFunction } from '@sentry/types';

import { isString } from '../is';
import { fill } from '../object';
import { GLOBAL_OBJ } from '../worldwide';
import { addHandler, maybeInstrument, triggerHandlers } from './_handlers';

const WINDOW = GLOBAL_OBJ as unknown as Window;
import { addHandler, fill, isString, maybeInstrument, triggerHandlers } from '@sentry/utils';
import { WINDOW } from '../browser/types';

export const SENTRY_XHR_DATA_KEY = '__sentry_xhr_v3__';

type WindowWithXhr = Window & { XMLHttpRequest?: typeof XMLHttpRequest };

/**
* Add an instrumentation handler for when an XHR request happens.
* The handler function is called once when the request starts and once when it ends,
Expand All @@ -29,15 +23,14 @@ export function addXhrInstrumentationHandler(handler: (data: HandlerDataXhr) =>

/** Exported only for tests. */
export function instrumentXHR(): void {
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
if (!(WINDOW as any).XMLHttpRequest) {
if (!(WINDOW as WindowWithXhr).XMLHttpRequest) {
return;
}

const xhrproto = XMLHttpRequest.prototype;

fill(xhrproto, 'open', function (originalOpen: () => void): () => void {
return function (this: XMLHttpRequest & SentryWrappedXMLHttpRequest, ...args: any[]): void {
return function (this: XMLHttpRequest & SentryWrappedXMLHttpRequest, ...args: unknown[]): void {
const startTimestamp = Date.now();

// open() should always be called with two or more arguments
Expand Down Expand Up @@ -87,8 +80,8 @@ export function instrumentXHR(): void {
};

if ('onreadystatechange' in this && typeof this.onreadystatechange === 'function') {
fill(this, 'onreadystatechange', function (original: WrappedFunction): Function {
return function (this: SentryWrappedXMLHttpRequest, ...readyStateArgs: any[]): void {
fill(this, 'onreadystatechange', function (original: WrappedFunction) {
return function (this: SentryWrappedXMLHttpRequest, ...readyStateArgs: unknown[]): void {
onreadystatechangeHandler();
return original.apply(this, readyStateArgs);
};
Expand All @@ -100,7 +93,7 @@ export function instrumentXHR(): void {
// Intercepting `setRequestHeader` to access the request headers of XHR instance.
// This will only work for user/library defined headers, not for the default/browser-assigned headers.
// Request cookies are also unavailable for XHR, as `Cookie` header can't be defined by `setRequestHeader`.
fill(this, 'setRequestHeader', function (original: WrappedFunction): Function {
fill(this, 'setRequestHeader', function (original: WrappedFunction) {
return function (this: SentryWrappedXMLHttpRequest, ...setRequestHeaderArgs: unknown[]): void {
const [header, value] = setRequestHeaderArgs;

Expand All @@ -119,7 +112,7 @@ export function instrumentXHR(): void {
});

fill(xhrproto, 'send', function (originalSend: () => void): () => void {
return function (this: XMLHttpRequest & SentryWrappedXMLHttpRequest, ...args: any[]): void {
return function (this: XMLHttpRequest & SentryWrappedXMLHttpRequest, ...args: unknown[]): void {
const sentryXhrData = this[SENTRY_XHR_DATA_KEY];

if (!sentryXhrData) {
Expand Down
7 changes: 4 additions & 3 deletions packages/browser-utils/test/browser/request.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/* eslint-disable deprecation/deprecation */
import * as utils from '@sentry/utils';

import * as xhrInstrumentation from '../../src/instrument/xhr';

import { extractNetworkProtocol, instrumentOutgoingRequests, shouldAttachHeaders } from '../../src/browser/request';
import { WINDOW } from '../../src/browser/types';

Expand All @@ -17,7 +18,7 @@ describe('instrumentOutgoingRequests', () => {

it('instruments fetch and xhr requests', () => {
const addFetchSpy = jest.spyOn(utils, 'addFetchInstrumentationHandler');
const addXhrSpy = jest.spyOn(utils, 'addXhrInstrumentationHandler');
const addXhrSpy = jest.spyOn(xhrInstrumentation, 'addXhrInstrumentationHandler');

instrumentOutgoingRequests();

Expand All @@ -34,7 +35,7 @@ describe('instrumentOutgoingRequests', () => {
});

it('does not instrument xhr requests if traceXHR is false', () => {
const addXhrSpy = jest.spyOn(utils, 'addXhrInstrumentationHandler');
const addXhrSpy = jest.spyOn(xhrInstrumentation, 'addXhrInstrumentationHandler');

instrumentOutgoingRequests({ traceXHR: false });

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { instrumentDOM } from '../../src/instrument/dom';

jest.mock('../../src/worldwide', () => {
const original = jest.requireActual('../../src/worldwide');
jest.mock('@sentry/utils', () => {
const original = jest.requireActual('@sentry/utils');

return {
...original,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { instrumentXHR } from '../../src/instrument/xhr';

jest.mock('../../src/worldwide', () => {
const original = jest.requireActual('../../src/worldwide');

jest.mock('@sentry/utils', () => {
const original = jest.requireActual('@sentry/utils');
return {
...original,
GLOBAL_OBJ: {
Expand Down
20 changes: 10 additions & 10 deletions packages/browser/src/integrations/breadcrumbs.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,28 @@
import {
SENTRY_XHR_DATA_KEY,
addClickKeypressInstrumentationHandler,
addHistoryInstrumentationHandler,
addXhrInstrumentationHandler,
} from '@sentry-internal/browser-utils';
import { addBreadcrumb, defineIntegration, getClient } from '@sentry/core';
import type {
Breadcrumb,
Client,
Event as SentryEvent,
FetchBreadcrumbData,
FetchBreadcrumbHint,
HandlerDataConsole,
HandlerDataDom,
HandlerDataFetch,
HandlerDataHistory,
HandlerDataXhr,
IntegrationFn,
} from '@sentry/types';
import type {
Breadcrumb,
FetchBreadcrumbData,
FetchBreadcrumbHint,
XhrBreadcrumbData,
XhrBreadcrumbHint,
} from '@sentry/types/build/types/breadcrumb';
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While working on this I noticed we were incorrectly importing from @sentry/types at times. I fixed this wherever possible.

} from '@sentry/types';
import {
SENTRY_XHR_DATA_KEY,
addClickKeypressInstrumentationHandler,
addConsoleInstrumentationHandler,
addFetchInstrumentationHandler,
addHistoryInstrumentationHandler,
addXhrInstrumentationHandler,
getComponentName,
getEventDescription,
htmlTreeAsString,
Expand Down
3 changes: 1 addition & 2 deletions packages/browser/src/integrations/httpclient.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import { SENTRY_XHR_DATA_KEY, addXhrInstrumentationHandler } from '@sentry-internal/browser-utils';
import { captureEvent, defineIntegration, getClient, isSentryRequestUrl } from '@sentry/core';
import type { Client, Event as SentryEvent, IntegrationFn, SentryWrappedXMLHttpRequest } from '@sentry/types';
import {
GLOBAL_OBJ,
SENTRY_XHR_DATA_KEY,
addExceptionMechanism,
addFetchInstrumentationHandler,
addXhrInstrumentationHandler,
logger,
supportsNativeFetch,
} from '@sentry/utils';
Expand Down
3 changes: 1 addition & 2 deletions packages/browser/src/profiling/integration.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { defineIntegration, getActiveSpan, getRootSpan } from '@sentry/core';
import type { EventEnvelope, IntegrationFn, Span } from '@sentry/types';
import type { Profile } from '@sentry/types/src/profiling';
import type { EventEnvelope, IntegrationFn, Profile, Span } from '@sentry/types';
import { logger } from '@sentry/utils';

import { DEBUG_BUILD } from '../debug-build';
Expand Down
13 changes: 11 additions & 2 deletions packages/browser/src/profiling/utils.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,17 @@
/* eslint-disable max-lines */

import { DEFAULT_ENVIRONMENT, getClient, spanToJSON } from '@sentry/core';
import type { DebugImage, Envelope, Event, EventEnvelope, Span, StackFrame, StackParser } from '@sentry/types';
import type { Profile, ThreadCpuProfile } from '@sentry/types/src/profiling';
import type {
DebugImage,
Envelope,
Event,
EventEnvelope,
Profile,
Span,
StackFrame,
StackParser,
ThreadCpuProfile,
} from '@sentry/types';
import { GLOBAL_OBJ, browserPerformanceTimeOrigin, forEachEnvelopeItem, logger, uuid4 } from '@sentry/utils';

import { DEBUG_BUILD } from '../debug-build';
Expand Down
9 changes: 2 additions & 7 deletions packages/browser/src/sdk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,9 @@ import {
startSession,
} from '@sentry/core';
import type { DsnLike, Integration, Options, UserFeedback } from '@sentry/types';
import {
addHistoryInstrumentationHandler,
consoleSandbox,
logger,
stackParserFromStackParserOptions,
supportsFetch,
} from '@sentry/utils';
import { consoleSandbox, logger, stackParserFromStackParserOptions, supportsFetch } from '@sentry/utils';

import { addHistoryInstrumentationHandler } from '@sentry-internal/browser-utils';
import { dedupeIntegration } from '@sentry/core';
import type { BrowserClientOptions, BrowserOptions } from './client';
import { BrowserClient } from './client';
Expand Down
11 changes: 9 additions & 2 deletions packages/deno/src/integrations/breadcrumbs.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
import { addBreadcrumb, defineIntegration, getClient } from '@sentry/core';
import type { Client, Event as SentryEvent, HandlerDataConsole, HandlerDataFetch, IntegrationFn } from '@sentry/types';
import type { FetchBreadcrumbData, FetchBreadcrumbHint } from '@sentry/types/build/types/breadcrumb';
import type {
Client,
Event as SentryEvent,
FetchBreadcrumbData,
FetchBreadcrumbHint,
HandlerDataConsole,
HandlerDataFetch,
IntegrationFn,
} from '@sentry/types';
import {
addConsoleInstrumentationHandler,
addFetchInstrumentationHandler,
Expand Down
Loading