Skip to content

Commit 56206f5

Browse files
authored
fix: Ensure all integration classes have correct types (#10183)
This ensures that all integration classes have both the correct constructor options, as well as the correct instance methods. This is pretty dirty, but since we're going to remove the classes very soon in v8, IMHO that's the easiest approach to make this work properly for our users. Somehow TS complains when using the option types directly, so we inline them for now everywhere, which seems to make it happy. 🤷 soon we'll remove these anyhow! Extracted out of #10143
1 parent 139a29a commit 56206f5

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+391
-153
lines changed

packages/browser/src/integrations/breadcrumbs.ts

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import type {
88
HandlerDataFetch,
99
HandlerDataHistory,
1010
HandlerDataXhr,
11+
Integration,
12+
IntegrationClass,
1113
IntegrationFn,
1214
} from '@sentry/types';
1315
import type {
@@ -55,7 +57,7 @@ const MAX_ALLOWED_STRING_LENGTH = 1024;
5557

5658
const INTEGRATION_NAME = 'Breadcrumbs';
5759

58-
const breadcrumbsIntegration: IntegrationFn = (options: Partial<BreadcrumbsOptions> = {}) => {
60+
const breadcrumbsIntegration = ((options: Partial<BreadcrumbsOptions> = {}) => {
5961
const _options = {
6062
console: true,
6163
dom: true,
@@ -91,13 +93,31 @@ const breadcrumbsIntegration: IntegrationFn = (options: Partial<BreadcrumbsOptio
9193
}
9294
},
9395
};
94-
};
96+
}) satisfies IntegrationFn;
9597

9698
/**
9799
* Default Breadcrumbs instrumentations
98100
*/
99101
// eslint-disable-next-line deprecation/deprecation
100-
export const Breadcrumbs = convertIntegrationFnToClass(INTEGRATION_NAME, breadcrumbsIntegration);
102+
export const Breadcrumbs = convertIntegrationFnToClass(INTEGRATION_NAME, breadcrumbsIntegration) as IntegrationClass<
103+
Integration & { setup: (client: Client) => void }
104+
> & {
105+
new (
106+
options?: Partial<{
107+
console: boolean;
108+
dom:
109+
| boolean
110+
| {
111+
serializeAttribute?: string | string[];
112+
maxStringLength?: number;
113+
};
114+
fetch: boolean;
115+
history: boolean;
116+
sentry: boolean;
117+
xhr: boolean;
118+
}>,
119+
): Integration;
120+
};
101121

102122
/**
103123
* Adds a breadcrumb for Sentry events or transactions if this option is enabled.

packages/browser/src/integrations/dedupe.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
import { convertIntegrationFnToClass } from '@sentry/core';
2-
import type { Event, Exception, IntegrationFn, StackFrame } from '@sentry/types';
2+
import type { Event, Exception, Integration, IntegrationClass, IntegrationFn, StackFrame } from '@sentry/types';
33
import { logger } from '@sentry/utils';
44

55
import { DEBUG_BUILD } from '../debug-build';
66

77
const INTEGRATION_NAME = 'Dedupe';
88

9-
const dedupeIntegration: IntegrationFn = () => {
9+
const dedupeIntegration = (() => {
1010
let previousEvent: Event | undefined;
1111

1212
return {
@@ -31,11 +31,13 @@ const dedupeIntegration: IntegrationFn = () => {
3131
return (previousEvent = currentEvent);
3232
},
3333
};
34-
};
34+
}) satisfies IntegrationFn;
3535

3636
/** Deduplication filter */
3737
// eslint-disable-next-line deprecation/deprecation
38-
export const Dedupe = convertIntegrationFnToClass(INTEGRATION_NAME, dedupeIntegration);
38+
export const Dedupe = convertIntegrationFnToClass(INTEGRATION_NAME, dedupeIntegration) as IntegrationClass<
39+
Integration & { processEvent: (event: Event) => Event }
40+
>;
3941

4042
function _shouldDropEvent(currentEvent: Event, previousEvent?: Event): boolean {
4143
if (!previousEvent) {

packages/browser/src/integrations/globalhandlers.ts

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,14 @@
11
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
22
import { captureEvent, convertIntegrationFnToClass, getClient } from '@sentry/core';
3-
import type { Client, Event, IntegrationFn, Primitive, StackParser } from '@sentry/types';
3+
import type {
4+
Client,
5+
Event,
6+
Integration,
7+
IntegrationClass,
8+
IntegrationFn,
9+
Primitive,
10+
StackParser,
11+
} from '@sentry/types';
412
import {
513
addGlobalErrorInstrumentationHandler,
614
addGlobalUnhandledRejectionInstrumentationHandler,
@@ -22,7 +30,7 @@ type GlobalHandlersIntegrations = Record<GlobalHandlersIntegrationsOptionKeys, b
2230

2331
const INTEGRATION_NAME = 'GlobalHandlers';
2432

25-
const globalHandlersIntegrations: IntegrationFn = (options: Partial<GlobalHandlersIntegrations> = {}) => {
33+
const globalHandlersIntegration = ((options: Partial<GlobalHandlersIntegrations> = {}) => {
2634
const _options = {
2735
onerror: true,
2836
onunhandledrejection: true,
@@ -45,11 +53,16 @@ const globalHandlersIntegrations: IntegrationFn = (options: Partial<GlobalHandle
4553
}
4654
},
4755
};
48-
};
56+
}) satisfies IntegrationFn;
4957

5058
/** Global handlers */
5159
// eslint-disable-next-line deprecation/deprecation
52-
export const GlobalHandlers = convertIntegrationFnToClass(INTEGRATION_NAME, globalHandlersIntegrations);
60+
export const GlobalHandlers = convertIntegrationFnToClass(
61+
INTEGRATION_NAME,
62+
globalHandlersIntegration,
63+
) as IntegrationClass<Integration & { setup: (client: Client) => void }> & {
64+
new (options?: Partial<GlobalHandlersIntegrations>): Integration;
65+
};
5366

5467
function _installGlobalOnErrorHandler(client: Client): void {
5568
addGlobalErrorInstrumentationHandler(data => {

packages/browser/src/integrations/httpcontext.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import { convertIntegrationFnToClass } from '@sentry/core';
2-
import type { IntegrationFn } from '@sentry/types';
2+
import type { Event, Integration, IntegrationClass, IntegrationFn } from '@sentry/types';
33

44
import { WINDOW } from '../helpers';
55

66
const INTEGRATION_NAME = 'HttpContext';
77

8-
const httpContextIntegration: IntegrationFn = () => {
8+
const httpContextIntegration = (() => {
99
return {
1010
name: INTEGRATION_NAME,
1111
// TODO v8: Remove this
@@ -31,8 +31,10 @@ const httpContextIntegration: IntegrationFn = () => {
3131
event.request = request;
3232
},
3333
};
34-
};
34+
}) satisfies IntegrationFn;
3535

3636
/** HttpContext integration collects information about HTTP request headers */
3737
// eslint-disable-next-line deprecation/deprecation
38-
export const HttpContext = convertIntegrationFnToClass(INTEGRATION_NAME, httpContextIntegration);
38+
export const HttpContext = convertIntegrationFnToClass(INTEGRATION_NAME, httpContextIntegration) as IntegrationClass<
39+
Integration & { preprocessEvent: (event: Event) => void }
40+
>;

packages/browser/src/integrations/linkederrors.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { convertIntegrationFnToClass } from '@sentry/core';
2-
import type { IntegrationFn } from '@sentry/types';
2+
import type { Client, Event, EventHint, Integration, IntegrationClass, IntegrationFn } from '@sentry/types';
33
import { applyAggregateErrorsToEvent } from '@sentry/utils';
44
import { exceptionFromError } from '../eventbuilder';
55

@@ -13,7 +13,7 @@ const DEFAULT_LIMIT = 5;
1313

1414
const INTEGRATION_NAME = 'LinkedErrors';
1515

16-
const linkedErrorsIntegration: IntegrationFn = (options: LinkedErrorsOptions = {}) => {
16+
const linkedErrorsIntegration = ((options: LinkedErrorsOptions = {}) => {
1717
const limit = options.limit || DEFAULT_LIMIT;
1818
const key = options.key || DEFAULT_KEY;
1919

@@ -36,8 +36,10 @@ const linkedErrorsIntegration: IntegrationFn = (options: LinkedErrorsOptions = {
3636
);
3737
},
3838
};
39-
};
39+
}) satisfies IntegrationFn;
4040

4141
/** Aggregrate linked errors in an event. */
4242
// eslint-disable-next-line deprecation/deprecation
43-
export const LinkedErrors = convertIntegrationFnToClass(INTEGRATION_NAME, linkedErrorsIntegration);
43+
export const LinkedErrors = convertIntegrationFnToClass(INTEGRATION_NAME, linkedErrorsIntegration) as IntegrationClass<
44+
Integration & { preprocessEvent: (event: Event, hint: EventHint, client: Client) => void }
45+
> & { new (options?: { key?: string; limit?: number }): Integration };

packages/browser/src/integrations/trycatch.ts

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { convertIntegrationFnToClass } from '@sentry/core';
2-
import type { IntegrationFn, WrappedFunction } from '@sentry/types';
2+
import type { Integration, IntegrationClass, IntegrationFn, WrappedFunction } from '@sentry/types';
33
import { fill, getFunctionName, getOriginalFunction } from '@sentry/utils';
44

55
import { WINDOW, wrap } from '../helpers';
@@ -50,7 +50,7 @@ interface TryCatchOptions {
5050
eventTarget: boolean | string[];
5151
}
5252

53-
const tryCatchIntegration: IntegrationFn = (options: Partial<TryCatchOptions> = {}) => {
53+
const browserApiErrorsIntegration = ((options: Partial<TryCatchOptions> = {}) => {
5454
const _options = {
5555
XMLHttpRequest: true,
5656
eventTarget: true,
@@ -88,11 +88,22 @@ const tryCatchIntegration: IntegrationFn = (options: Partial<TryCatchOptions> =
8888
}
8989
},
9090
};
91-
};
91+
}) satisfies IntegrationFn;
9292

9393
/** Wrap timer functions and event targets to catch errors and provide better meta data */
9494
// eslint-disable-next-line deprecation/deprecation
95-
export const TryCatch = convertIntegrationFnToClass(INTEGRATION_NAME, tryCatchIntegration);
95+
export const TryCatch = convertIntegrationFnToClass(
96+
INTEGRATION_NAME,
97+
browserApiErrorsIntegration,
98+
) as IntegrationClass<Integration> & {
99+
new (options?: {
100+
setTimeout: boolean;
101+
setInterval: boolean;
102+
requestAnimationFrame: boolean;
103+
XMLHttpRequest: boolean;
104+
eventTarget: boolean | string[];
105+
}): Integration;
106+
};
96107

97108
function _wrapTimeFunction(original: () => void): () => number {
98109
// eslint-disable-next-line @typescript-eslint/no-explicit-any

packages/browser/src/profiling/integration.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { convertIntegrationFnToClass, getCurrentScope } from '@sentry/core';
2-
import type { EventEnvelope, IntegrationFn, Transaction } from '@sentry/types';
2+
import type { Client, EventEnvelope, Integration, IntegrationClass, IntegrationFn, Transaction } from '@sentry/types';
33
import type { Profile } from '@sentry/types/src/profiling';
44
import { logger } from '@sentry/utils';
55

@@ -18,7 +18,7 @@ import {
1818

1919
const INTEGRATION_NAME = 'BrowserProfiling';
2020

21-
const browserProfilingIntegration: IntegrationFn = () => {
21+
const browserProfilingIntegration = (() => {
2222
return {
2323
name: INTEGRATION_NAME,
2424
// TODO v8: Remove this
@@ -100,7 +100,7 @@ const browserProfilingIntegration: IntegrationFn = () => {
100100
});
101101
},
102102
};
103-
};
103+
}) satisfies IntegrationFn;
104104

105105
/**
106106
* Browser profiling integration. Stores any event that has contexts["profile"]["profile_id"]
@@ -112,4 +112,7 @@ const browserProfilingIntegration: IntegrationFn = () => {
112112
* @experimental
113113
*/
114114
// eslint-disable-next-line deprecation/deprecation
115-
export const BrowserProfilingIntegration = convertIntegrationFnToClass(INTEGRATION_NAME, browserProfilingIntegration);
115+
export const BrowserProfilingIntegration = convertIntegrationFnToClass(
116+
INTEGRATION_NAME,
117+
browserProfilingIntegration,
118+
) as IntegrationClass<Integration & { setup: (client: Client) => void }>;

packages/browser/test/unit/profiling/integration.test.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ describe('BrowserProfilingIntegration', () => {
3636
Sentry.init({
3737
tracesSampleRate: 1,
3838
profilesSampleRate: 1,
39-
debug: true,
4039
environment: 'test-environment',
4140
dsn: 'https://[email protected]/6625302',
4241
transport: _opts => {

packages/bun/src/integrations/bunserver.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,14 @@ import { getSanitizedUrlString, parseUrl } from '@sentry/utils';
1313

1414
const INTEGRATION_NAME = 'BunServer';
1515

16-
const bunServerIntegration: IntegrationFn = () => {
16+
const bunServerIntegration = (() => {
1717
return {
1818
name: INTEGRATION_NAME,
1919
setupOnce() {
2020
instrumentBunServe();
2121
},
2222
};
23-
};
23+
}) satisfies IntegrationFn;
2424

2525
/**
2626
* Instruments `Bun.serve` to automatically create transactions and capture errors.

packages/core/src/integration.ts

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { Client, Event, EventHint, Integration, IntegrationFn, Options } from '@sentry/types';
1+
import type { Client, Event, EventHint, Integration, IntegrationClass, IntegrationFn, Options } from '@sentry/types';
22
import { arrayify, logger } from '@sentry/utils';
33

44
import { DEBUG_BUILD } from './debug-build';
@@ -169,18 +169,11 @@ function findIndex<T>(arr: T[], callback: (item: T) => boolean): number {
169169
export function convertIntegrationFnToClass<Fn extends IntegrationFn>(
170170
name: string,
171171
fn: Fn,
172-
): Integration & {
173-
id: string;
174-
new (...args: Parameters<Fn>): Integration & ReturnType<Fn>;
175-
} {
172+
): IntegrationClass<Integration> {
176173
return Object.assign(
177-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
178-
function ConvertedIntegration(...rest: Parameters<Fn>) {
179-
return fn(...rest);
174+
function ConvertedIntegration(...args: Parameters<Fn>): Integration {
175+
return fn(...args);
180176
},
181177
{ id: name },
182-
) as unknown as Integration & {
183-
id: string;
184-
new (...args: Parameters<Fn>): Integration & ReturnType<Fn>;
185-
};
178+
) as unknown as IntegrationClass<Integration>;
186179
}

packages/core/src/integrations/functiontostring.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
import type { IntegrationFn, WrappedFunction } from '@sentry/types';
1+
import type { Integration, IntegrationClass, IntegrationFn, WrappedFunction } from '@sentry/types';
22
import { getOriginalFunction } from '@sentry/utils';
33
import { convertIntegrationFnToClass } from '../integration';
44

55
let originalFunctionToString: () => void;
66

77
const INTEGRATION_NAME = 'FunctionToString';
88

9-
const functionToStringIntegration: IntegrationFn = () => {
9+
const functionToStringIntegration = (() => {
1010
return {
1111
name: INTEGRATION_NAME,
1212
setupOnce() {
@@ -26,8 +26,11 @@ const functionToStringIntegration: IntegrationFn = () => {
2626
}
2727
},
2828
};
29-
};
29+
}) satisfies IntegrationFn;
3030

3131
/** Patch toString calls to return proper name for wrapped functions */
3232
// eslint-disable-next-line deprecation/deprecation
33-
export const FunctionToString = convertIntegrationFnToClass(INTEGRATION_NAME, functionToStringIntegration);
33+
export const FunctionToString = convertIntegrationFnToClass(
34+
INTEGRATION_NAME,
35+
functionToStringIntegration,
36+
) as IntegrationClass<Integration & { setupOnce: () => void }>;

packages/core/src/integrations/inboundfilters.ts

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { Event, IntegrationFn, StackFrame } from '@sentry/types';
1+
import type { Client, Event, EventHint, Integration, IntegrationClass, IntegrationFn, StackFrame } from '@sentry/types';
22
import { getEventDescription, logger, stringMatchesSomePattern } from '@sentry/utils';
33

44
import { DEBUG_BUILD } from '../debug-build';
@@ -30,7 +30,7 @@ export interface InboundFiltersOptions {
3030
}
3131

3232
const INTEGRATION_NAME = 'InboundFilters';
33-
const inboundFiltersIntegration: IntegrationFn = (options: Partial<InboundFiltersOptions>) => {
33+
const inboundFiltersIntegration = ((options: Partial<InboundFiltersOptions> = {}) => {
3434
return {
3535
name: INTEGRATION_NAME,
3636
// TODO v8: Remove this
@@ -41,11 +41,26 @@ const inboundFiltersIntegration: IntegrationFn = (options: Partial<InboundFilter
4141
return _shouldDropEvent(event, mergedOptions) ? null : event;
4242
},
4343
};
44-
};
44+
}) satisfies IntegrationFn;
4545

4646
/** Inbound filters configurable by the user */
4747
// eslint-disable-next-line deprecation/deprecation
48-
export const InboundFilters = convertIntegrationFnToClass(INTEGRATION_NAME, inboundFiltersIntegration);
48+
export const InboundFilters = convertIntegrationFnToClass(
49+
INTEGRATION_NAME,
50+
inboundFiltersIntegration,
51+
) as IntegrationClass<Integration & { preprocessEvent: (event: Event, hint: EventHint, client: Client) => void }> & {
52+
new (
53+
options?: Partial<{
54+
allowUrls: Array<string | RegExp>;
55+
denyUrls: Array<string | RegExp>;
56+
ignoreErrors: Array<string | RegExp>;
57+
ignoreTransactions: Array<string | RegExp>;
58+
ignoreInternal: boolean;
59+
disableErrorDefaults: boolean;
60+
disableTransactionDefaults: boolean;
61+
}>,
62+
): Integration;
63+
};
4964

5065
function _mergeOptions(
5166
internalOptions: Partial<InboundFiltersOptions> = {},

0 commit comments

Comments
 (0)