diff --git a/packages/browser/src/integrations/breadcrumbs.ts b/packages/browser/src/integrations/breadcrumbs.ts index 9799e6e73b4f..485b19d3b711 100644 --- a/packages/browser/src/integrations/breadcrumbs.ts +++ b/packages/browser/src/integrations/breadcrumbs.ts @@ -8,6 +8,8 @@ import type { HandlerDataFetch, HandlerDataHistory, HandlerDataXhr, + Integration, + IntegrationClass, IntegrationFn, } from '@sentry/types'; import type { @@ -55,7 +57,7 @@ const MAX_ALLOWED_STRING_LENGTH = 1024; const INTEGRATION_NAME = 'Breadcrumbs'; -const breadcrumbsIntegration: IntegrationFn = (options: Partial = {}) => { +const breadcrumbsIntegration = ((options: Partial = {}) => { const _options = { console: true, dom: true, @@ -91,13 +93,31 @@ const breadcrumbsIntegration: IntegrationFn = (options: Partial void } +> & { + new ( + options?: Partial<{ + console: boolean; + dom: + | boolean + | { + serializeAttribute?: string | string[]; + maxStringLength?: number; + }; + fetch: boolean; + history: boolean; + sentry: boolean; + xhr: boolean; + }>, + ): Integration; +}; /** * Adds a breadcrumb for Sentry events or transactions if this option is enabled. diff --git a/packages/browser/src/integrations/dedupe.ts b/packages/browser/src/integrations/dedupe.ts index a74a4b9ed9c6..394d5c5ae1e3 100644 --- a/packages/browser/src/integrations/dedupe.ts +++ b/packages/browser/src/integrations/dedupe.ts @@ -1,12 +1,12 @@ import { convertIntegrationFnToClass } from '@sentry/core'; -import type { Event, Exception, IntegrationFn, StackFrame } from '@sentry/types'; +import type { Event, Exception, Integration, IntegrationClass, IntegrationFn, StackFrame } from '@sentry/types'; import { logger } from '@sentry/utils'; import { DEBUG_BUILD } from '../debug-build'; const INTEGRATION_NAME = 'Dedupe'; -const dedupeIntegration: IntegrationFn = () => { +const dedupeIntegration = (() => { let previousEvent: Event | undefined; return { @@ -31,11 +31,13 @@ const dedupeIntegration: IntegrationFn = () => { return (previousEvent = currentEvent); }, }; -}; +}) satisfies IntegrationFn; /** Deduplication filter */ // eslint-disable-next-line deprecation/deprecation -export const Dedupe = convertIntegrationFnToClass(INTEGRATION_NAME, dedupeIntegration); +export const Dedupe = convertIntegrationFnToClass(INTEGRATION_NAME, dedupeIntegration) as IntegrationClass< + Integration & { processEvent: (event: Event) => Event } +>; function _shouldDropEvent(currentEvent: Event, previousEvent?: Event): boolean { if (!previousEvent) { diff --git a/packages/browser/src/integrations/globalhandlers.ts b/packages/browser/src/integrations/globalhandlers.ts index e829b6f92845..01ef16a02851 100644 --- a/packages/browser/src/integrations/globalhandlers.ts +++ b/packages/browser/src/integrations/globalhandlers.ts @@ -1,6 +1,14 @@ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ import { captureEvent, convertIntegrationFnToClass, getClient } from '@sentry/core'; -import type { Client, Event, IntegrationFn, Primitive, StackParser } from '@sentry/types'; +import type { + Client, + Event, + Integration, + IntegrationClass, + IntegrationFn, + Primitive, + StackParser, +} from '@sentry/types'; import { addGlobalErrorInstrumentationHandler, addGlobalUnhandledRejectionInstrumentationHandler, @@ -22,7 +30,7 @@ type GlobalHandlersIntegrations = Record = {}) => { +const globalHandlersIntegration = ((options: Partial = {}) => { const _options = { onerror: true, onunhandledrejection: true, @@ -45,11 +53,16 @@ const globalHandlersIntegrations: IntegrationFn = (options: Partial void }> & { + new (options?: Partial): Integration; +}; function _installGlobalOnErrorHandler(client: Client): void { addGlobalErrorInstrumentationHandler(data => { diff --git a/packages/browser/src/integrations/httpcontext.ts b/packages/browser/src/integrations/httpcontext.ts index d46f29257306..569eeffab45c 100644 --- a/packages/browser/src/integrations/httpcontext.ts +++ b/packages/browser/src/integrations/httpcontext.ts @@ -1,11 +1,11 @@ import { convertIntegrationFnToClass } from '@sentry/core'; -import type { IntegrationFn } from '@sentry/types'; +import type { Event, Integration, IntegrationClass, IntegrationFn } from '@sentry/types'; import { WINDOW } from '../helpers'; const INTEGRATION_NAME = 'HttpContext'; -const httpContextIntegration: IntegrationFn = () => { +const httpContextIntegration = (() => { return { name: INTEGRATION_NAME, // TODO v8: Remove this @@ -31,8 +31,10 @@ const httpContextIntegration: IntegrationFn = () => { event.request = request; }, }; -}; +}) satisfies IntegrationFn; /** HttpContext integration collects information about HTTP request headers */ // eslint-disable-next-line deprecation/deprecation -export const HttpContext = convertIntegrationFnToClass(INTEGRATION_NAME, httpContextIntegration); +export const HttpContext = convertIntegrationFnToClass(INTEGRATION_NAME, httpContextIntegration) as IntegrationClass< + Integration & { preprocessEvent: (event: Event) => void } +>; diff --git a/packages/browser/src/integrations/linkederrors.ts b/packages/browser/src/integrations/linkederrors.ts index bb351bcdc3c6..8a166e7667d9 100644 --- a/packages/browser/src/integrations/linkederrors.ts +++ b/packages/browser/src/integrations/linkederrors.ts @@ -1,5 +1,5 @@ import { convertIntegrationFnToClass } from '@sentry/core'; -import type { IntegrationFn } from '@sentry/types'; +import type { Client, Event, EventHint, Integration, IntegrationClass, IntegrationFn } from '@sentry/types'; import { applyAggregateErrorsToEvent } from '@sentry/utils'; import { exceptionFromError } from '../eventbuilder'; @@ -13,7 +13,7 @@ const DEFAULT_LIMIT = 5; const INTEGRATION_NAME = 'LinkedErrors'; -const linkedErrorsIntegration: IntegrationFn = (options: LinkedErrorsOptions = {}) => { +const linkedErrorsIntegration = ((options: LinkedErrorsOptions = {}) => { const limit = options.limit || DEFAULT_LIMIT; const key = options.key || DEFAULT_KEY; @@ -36,8 +36,10 @@ const linkedErrorsIntegration: IntegrationFn = (options: LinkedErrorsOptions = { ); }, }; -}; +}) satisfies IntegrationFn; /** Aggregrate linked errors in an event. */ // eslint-disable-next-line deprecation/deprecation -export const LinkedErrors = convertIntegrationFnToClass(INTEGRATION_NAME, linkedErrorsIntegration); +export const LinkedErrors = convertIntegrationFnToClass(INTEGRATION_NAME, linkedErrorsIntegration) as IntegrationClass< + Integration & { preprocessEvent: (event: Event, hint: EventHint, client: Client) => void } +> & { new (options?: { key?: string; limit?: number }): Integration }; diff --git a/packages/browser/src/integrations/trycatch.ts b/packages/browser/src/integrations/trycatch.ts index f555acfcdc9c..2f5f06592805 100644 --- a/packages/browser/src/integrations/trycatch.ts +++ b/packages/browser/src/integrations/trycatch.ts @@ -1,5 +1,5 @@ import { convertIntegrationFnToClass } from '@sentry/core'; -import type { IntegrationFn, WrappedFunction } from '@sentry/types'; +import type { Integration, IntegrationClass, IntegrationFn, WrappedFunction } from '@sentry/types'; import { fill, getFunctionName, getOriginalFunction } from '@sentry/utils'; import { WINDOW, wrap } from '../helpers'; @@ -50,7 +50,7 @@ interface TryCatchOptions { eventTarget: boolean | string[]; } -const tryCatchIntegration: IntegrationFn = (options: Partial = {}) => { +const browserApiErrorsIntegration = ((options: Partial = {}) => { const _options = { XMLHttpRequest: true, eventTarget: true, @@ -88,11 +88,22 @@ const tryCatchIntegration: IntegrationFn = (options: Partial = } }, }; -}; +}) satisfies IntegrationFn; /** Wrap timer functions and event targets to catch errors and provide better meta data */ // eslint-disable-next-line deprecation/deprecation -export const TryCatch = convertIntegrationFnToClass(INTEGRATION_NAME, tryCatchIntegration); +export const TryCatch = convertIntegrationFnToClass( + INTEGRATION_NAME, + browserApiErrorsIntegration, +) as IntegrationClass & { + new (options?: { + setTimeout: boolean; + setInterval: boolean; + requestAnimationFrame: boolean; + XMLHttpRequest: boolean; + eventTarget: boolean | string[]; + }): Integration; +}; function _wrapTimeFunction(original: () => void): () => number { // eslint-disable-next-line @typescript-eslint/no-explicit-any diff --git a/packages/browser/src/profiling/integration.ts b/packages/browser/src/profiling/integration.ts index c6e478e8554d..a3af7744c4e4 100644 --- a/packages/browser/src/profiling/integration.ts +++ b/packages/browser/src/profiling/integration.ts @@ -1,5 +1,5 @@ import { convertIntegrationFnToClass, getCurrentScope } from '@sentry/core'; -import type { EventEnvelope, IntegrationFn, Transaction } from '@sentry/types'; +import type { Client, EventEnvelope, Integration, IntegrationClass, IntegrationFn, Transaction } from '@sentry/types'; import type { Profile } from '@sentry/types/src/profiling'; import { logger } from '@sentry/utils'; @@ -18,7 +18,7 @@ import { const INTEGRATION_NAME = 'BrowserProfiling'; -const browserProfilingIntegration: IntegrationFn = () => { +const browserProfilingIntegration = (() => { return { name: INTEGRATION_NAME, // TODO v8: Remove this @@ -100,7 +100,7 @@ const browserProfilingIntegration: IntegrationFn = () => { }); }, }; -}; +}) satisfies IntegrationFn; /** * Browser profiling integration. Stores any event that has contexts["profile"]["profile_id"] @@ -112,4 +112,7 @@ const browserProfilingIntegration: IntegrationFn = () => { * @experimental */ // eslint-disable-next-line deprecation/deprecation -export const BrowserProfilingIntegration = convertIntegrationFnToClass(INTEGRATION_NAME, browserProfilingIntegration); +export const BrowserProfilingIntegration = convertIntegrationFnToClass( + INTEGRATION_NAME, + browserProfilingIntegration, +) as IntegrationClass void }>; diff --git a/packages/browser/test/unit/profiling/integration.test.ts b/packages/browser/test/unit/profiling/integration.test.ts index 0c7eb35f60e2..b69d3a52d655 100644 --- a/packages/browser/test/unit/profiling/integration.test.ts +++ b/packages/browser/test/unit/profiling/integration.test.ts @@ -36,7 +36,6 @@ describe('BrowserProfilingIntegration', () => { Sentry.init({ tracesSampleRate: 1, profilesSampleRate: 1, - debug: true, environment: 'test-environment', dsn: 'https://7fa19397baaf433f919fbe02228d5470@o1137848.ingest.sentry.io/6625302', transport: _opts => { diff --git a/packages/bun/src/integrations/bunserver.ts b/packages/bun/src/integrations/bunserver.ts index fec3aae439af..fb12cf94432b 100644 --- a/packages/bun/src/integrations/bunserver.ts +++ b/packages/bun/src/integrations/bunserver.ts @@ -13,14 +13,14 @@ import { getSanitizedUrlString, parseUrl } from '@sentry/utils'; const INTEGRATION_NAME = 'BunServer'; -const bunServerIntegration: IntegrationFn = () => { +const bunServerIntegration = (() => { return { name: INTEGRATION_NAME, setupOnce() { instrumentBunServe(); }, }; -}; +}) satisfies IntegrationFn; /** * Instruments `Bun.serve` to automatically create transactions and capture errors. diff --git a/packages/core/src/integration.ts b/packages/core/src/integration.ts index 4b4a3177c428..6b63b6fb7f85 100644 --- a/packages/core/src/integration.ts +++ b/packages/core/src/integration.ts @@ -1,4 +1,4 @@ -import type { Client, Event, EventHint, Integration, IntegrationFn, Options } from '@sentry/types'; +import type { Client, Event, EventHint, Integration, IntegrationClass, IntegrationFn, Options } from '@sentry/types'; import { arrayify, logger } from '@sentry/utils'; import { DEBUG_BUILD } from './debug-build'; @@ -169,18 +169,11 @@ function findIndex(arr: T[], callback: (item: T) => boolean): number { export function convertIntegrationFnToClass( name: string, fn: Fn, -): Integration & { - id: string; - new (...args: Parameters): Integration & ReturnType; -} { +): IntegrationClass { return Object.assign( - // eslint-disable-next-line @typescript-eslint/no-explicit-any - function ConvertedIntegration(...rest: Parameters) { - return fn(...rest); + function ConvertedIntegration(...args: Parameters): Integration { + return fn(...args); }, { id: name }, - ) as unknown as Integration & { - id: string; - new (...args: Parameters): Integration & ReturnType; - }; + ) as unknown as IntegrationClass; } diff --git a/packages/core/src/integrations/functiontostring.ts b/packages/core/src/integrations/functiontostring.ts index 124085c9c6c6..112899d525ac 100644 --- a/packages/core/src/integrations/functiontostring.ts +++ b/packages/core/src/integrations/functiontostring.ts @@ -1,4 +1,4 @@ -import type { IntegrationFn, WrappedFunction } from '@sentry/types'; +import type { Integration, IntegrationClass, IntegrationFn, WrappedFunction } from '@sentry/types'; import { getOriginalFunction } from '@sentry/utils'; import { convertIntegrationFnToClass } from '../integration'; @@ -6,7 +6,7 @@ let originalFunctionToString: () => void; const INTEGRATION_NAME = 'FunctionToString'; -const functionToStringIntegration: IntegrationFn = () => { +const functionToStringIntegration = (() => { return { name: INTEGRATION_NAME, setupOnce() { @@ -26,8 +26,11 @@ const functionToStringIntegration: IntegrationFn = () => { } }, }; -}; +}) satisfies IntegrationFn; /** Patch toString calls to return proper name for wrapped functions */ // eslint-disable-next-line deprecation/deprecation -export const FunctionToString = convertIntegrationFnToClass(INTEGRATION_NAME, functionToStringIntegration); +export const FunctionToString = convertIntegrationFnToClass( + INTEGRATION_NAME, + functionToStringIntegration, +) as IntegrationClass void }>; diff --git a/packages/core/src/integrations/inboundfilters.ts b/packages/core/src/integrations/inboundfilters.ts index 6d2ec6dfc799..42cbfbae7e46 100644 --- a/packages/core/src/integrations/inboundfilters.ts +++ b/packages/core/src/integrations/inboundfilters.ts @@ -1,4 +1,4 @@ -import type { Event, IntegrationFn, StackFrame } from '@sentry/types'; +import type { Client, Event, EventHint, Integration, IntegrationClass, IntegrationFn, StackFrame } from '@sentry/types'; import { getEventDescription, logger, stringMatchesSomePattern } from '@sentry/utils'; import { DEBUG_BUILD } from '../debug-build'; @@ -30,7 +30,7 @@ export interface InboundFiltersOptions { } const INTEGRATION_NAME = 'InboundFilters'; -const inboundFiltersIntegration: IntegrationFn = (options: Partial) => { +const inboundFiltersIntegration = ((options: Partial = {}) => { return { name: INTEGRATION_NAME, // TODO v8: Remove this @@ -41,11 +41,26 @@ const inboundFiltersIntegration: IntegrationFn = (options: Partial void }> & { + new ( + options?: Partial<{ + allowUrls: Array; + denyUrls: Array; + ignoreErrors: Array; + ignoreTransactions: Array; + ignoreInternal: boolean; + disableErrorDefaults: boolean; + disableTransactionDefaults: boolean; + }>, + ): Integration; +}; function _mergeOptions( internalOptions: Partial = {}, diff --git a/packages/core/src/integrations/linkederrors.ts b/packages/core/src/integrations/linkederrors.ts index 25e6417023f2..1b0b5135a2f1 100644 --- a/packages/core/src/integrations/linkederrors.ts +++ b/packages/core/src/integrations/linkederrors.ts @@ -1,4 +1,4 @@ -import type { IntegrationFn } from '@sentry/types'; +import type { Client, Event, EventHint, Integration, IntegrationClass, IntegrationFn } from '@sentry/types'; import { applyAggregateErrorsToEvent, exceptionFromError } from '@sentry/utils'; import { convertIntegrationFnToClass } from '../integration'; @@ -12,7 +12,7 @@ const DEFAULT_LIMIT = 5; const INTEGRATION_NAME = 'LinkedErrors'; -const linkedErrorsIntegration: IntegrationFn = (options: LinkedErrorsOptions = {}) => { +const linkedErrorsIntegration = ((options: LinkedErrorsOptions = {}) => { const limit = options.limit || DEFAULT_LIMIT; const key = options.key || DEFAULT_KEY; @@ -34,8 +34,10 @@ const linkedErrorsIntegration: IntegrationFn = (options: LinkedErrorsOptions = { ); }, }; -}; +}) satisfies IntegrationFn; /** Adds SDK info to an event. */ // eslint-disable-next-line deprecation/deprecation -export const LinkedErrors = convertIntegrationFnToClass(INTEGRATION_NAME, linkedErrorsIntegration); +export const LinkedErrors = convertIntegrationFnToClass(INTEGRATION_NAME, linkedErrorsIntegration) as IntegrationClass< + Integration & { preprocessEvent: (event: Event, hint: EventHint, client: Client) => void } +> & { new (options?: { key?: string; limit?: number }): Integration }; diff --git a/packages/core/src/integrations/metadata.ts b/packages/core/src/integrations/metadata.ts index a18fc5dffebc..652aa081529c 100644 --- a/packages/core/src/integrations/metadata.ts +++ b/packages/core/src/integrations/metadata.ts @@ -1,4 +1,4 @@ -import type { EventItem, IntegrationFn } from '@sentry/types'; +import type { Client, Event, EventHint, EventItem, Integration, IntegrationClass, IntegrationFn } from '@sentry/types'; import { forEachEnvelopeItem } from '@sentry/utils'; import { convertIntegrationFnToClass } from '../integration'; @@ -6,7 +6,7 @@ import { addMetadataToStackFrames, stripMetadataFromStackFrames } from '../metad const INTEGRATION_NAME = 'ModuleMetadata'; -const moduleMetadataIntegration: IntegrationFn = () => { +const moduleMetadataIntegration = (() => { return { name: INTEGRATION_NAME, // TODO v8: Remove this @@ -37,7 +37,7 @@ const moduleMetadataIntegration: IntegrationFn = () => { return event; }, }; -}; +}) satisfies IntegrationFn; /** * Adds module metadata to stack frames. @@ -49,4 +49,12 @@ const moduleMetadataIntegration: IntegrationFn = () => { * our sources */ // eslint-disable-next-line deprecation/deprecation -export const ModuleMetadata = convertIntegrationFnToClass(INTEGRATION_NAME, moduleMetadataIntegration); +export const ModuleMetadata = convertIntegrationFnToClass( + INTEGRATION_NAME, + moduleMetadataIntegration, +) as IntegrationClass< + Integration & { + setup: (client: Client) => void; + processEvent: (event: Event, hint: EventHint, client: Client) => Event; + } +>; diff --git a/packages/core/src/integrations/requestdata.ts b/packages/core/src/integrations/requestdata.ts index 76d29b4751b7..80d587e09a57 100644 --- a/packages/core/src/integrations/requestdata.ts +++ b/packages/core/src/integrations/requestdata.ts @@ -1,4 +1,12 @@ -import type { Client, IntegrationFn, Transaction } from '@sentry/types'; +import type { + Client, + Event, + EventHint, + Integration, + IntegrationClass, + IntegrationFn, + Transaction, +} from '@sentry/types'; import type { AddRequestDataToEventOptions, TransactionNamingScheme } from '@sentry/utils'; import { addRequestDataToEvent, extractPathForTransaction } from '@sentry/utils'; import { convertIntegrationFnToClass } from '../integration'; @@ -47,7 +55,7 @@ const DEFAULT_OPTIONS = { const INTEGRATION_NAME = 'RequestData'; -const requestDataIntegration: IntegrationFn = (options: RequestDataIntegrationOptions = {}) => { +const requestDataIntegration = ((options: RequestDataIntegrationOptions = {}) => { const _addRequestData = addRequestDataToEvent; const _options: Required = { ...DEFAULT_OPTIONS, @@ -129,12 +137,38 @@ const requestDataIntegration: IntegrationFn = (options: RequestDataIntegrationOp return processedEvent; }, }; -}; +}) satisfies IntegrationFn; /** Add data about a request to an event. Primarily for use in Node-based SDKs, but included in `@sentry/integrations` * so it can be used in cross-platform SDKs like `@sentry/nextjs`. */ // eslint-disable-next-line deprecation/deprecation -export const RequestData = convertIntegrationFnToClass(INTEGRATION_NAME, requestDataIntegration); +export const RequestData = convertIntegrationFnToClass(INTEGRATION_NAME, requestDataIntegration) as IntegrationClass< + Integration & { processEvent: (event: Event, hint: EventHint, client: Client) => Event } +> & { + new (options?: { + /** + * 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; + }; + }; + + /** Whether to identify transactions by parameterized path, parameterized path with method, or handler name */ + transactionNamingScheme?: TransactionNamingScheme; + }): Integration; +}; /** 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 */ diff --git a/packages/core/src/metrics/integration.ts b/packages/core/src/metrics/integration.ts index 5cadf47ce3f2..d4c77c6b61fe 100644 --- a/packages/core/src/metrics/integration.ts +++ b/packages/core/src/metrics/integration.ts @@ -1,11 +1,11 @@ -import type { ClientOptions, IntegrationFn } from '@sentry/types'; +import type { Client, ClientOptions, Integration, IntegrationClass, IntegrationFn } from '@sentry/types'; import type { BaseClient } from '../baseclient'; import { convertIntegrationFnToClass } from '../integration'; import { BrowserMetricsAggregator } from './browser-aggregator'; const INTEGRATION_NAME = 'MetricsAggregator'; -const metricsAggregatorIntegration: IntegrationFn = () => { +const metricsAggregatorIntegration = (() => { return { name: INTEGRATION_NAME, // TODO v8: Remove this @@ -14,7 +14,7 @@ const metricsAggregatorIntegration: IntegrationFn = () => { client.metricsAggregator = new BrowserMetricsAggregator(client); }, }; -}; +}) satisfies IntegrationFn; /** * Enables Sentry metrics monitoring. @@ -22,4 +22,7 @@ const metricsAggregatorIntegration: IntegrationFn = () => { * @experimental This API is experimental and might having breaking changes in the future. */ // eslint-disable-next-line deprecation/deprecation -export const MetricsAggregator = convertIntegrationFnToClass(INTEGRATION_NAME, metricsAggregatorIntegration); +export const MetricsAggregator = convertIntegrationFnToClass( + INTEGRATION_NAME, + metricsAggregatorIntegration, +) as IntegrationClass void }>; diff --git a/packages/core/test/lib/integration.test.ts b/packages/core/test/lib/integration.test.ts index 829ef4de991b..779567a4f1cb 100644 --- a/packages/core/test/lib/integration.test.ts +++ b/packages/core/test/lib/integration.test.ts @@ -675,7 +675,7 @@ describe('convertIntegrationFnToClass', () => { expect(IntegrationClass.id).toBe('testName'); - // @ts-expect-error This should fail TS without options + // not type safe options by default :( new IntegrationClass(); const integration = new IntegrationClass({ num: 3 }); diff --git a/packages/deno/src/integrations/context.ts b/packages/deno/src/integrations/context.ts index 426d296f6efc..199da80d9b4b 100644 --- a/packages/deno/src/integrations/context.ts +++ b/packages/deno/src/integrations/context.ts @@ -1,5 +1,5 @@ import { convertIntegrationFnToClass } from '@sentry/core'; -import type { Event, IntegrationFn } from '@sentry/types'; +import type { Event, Integration, IntegrationClass, IntegrationFn } from '@sentry/types'; const INTEGRATION_NAME = 'DenoContext'; @@ -52,7 +52,7 @@ async function addDenoRuntimeContext(event: Event): Promise { return event; } -const denoContextIntegration: IntegrationFn = () => { +const denoContextIntegration = (() => { return { name: INTEGRATION_NAME, // TODO v8: Remove this @@ -61,8 +61,10 @@ const denoContextIntegration: IntegrationFn = () => { return addDenoRuntimeContext(event); }, }; -}; +}) satisfies IntegrationFn; /** Adds Deno context to events. */ // eslint-disable-next-line deprecation/deprecation -export const DenoContext = convertIntegrationFnToClass(INTEGRATION_NAME, denoContextIntegration); +export const DenoContext = convertIntegrationFnToClass(INTEGRATION_NAME, denoContextIntegration) as IntegrationClass< + Integration & { processEvent: (event: Event) => Promise } +>; diff --git a/packages/deno/src/integrations/contextlines.ts b/packages/deno/src/integrations/contextlines.ts index f3099151908a..1b3b413699f6 100644 --- a/packages/deno/src/integrations/contextlines.ts +++ b/packages/deno/src/integrations/contextlines.ts @@ -1,5 +1,5 @@ import { convertIntegrationFnToClass } from '@sentry/core'; -import type { Event, IntegrationFn, StackFrame } from '@sentry/types'; +import type { Event, Integration, IntegrationClass, IntegrationFn, StackFrame } from '@sentry/types'; import { LRUMap, addContextToFrame } from '@sentry/utils'; const INTEGRATION_NAME = 'ContextLines'; @@ -47,7 +47,7 @@ interface ContextLinesOptions { frameContextLines?: number; } -const denoContextLinesIntegration: IntegrationFn = (options: ContextLinesOptions = {}) => { +const denoContextLinesIntegration = ((options: ContextLinesOptions = {}) => { const contextLines = options.frameContextLines !== undefined ? options.frameContextLines : DEFAULT_LINES_OF_CONTEXT; return { @@ -58,11 +58,14 @@ const denoContextLinesIntegration: IntegrationFn = (options: ContextLinesOptions return addSourceContext(event, contextLines); }, }; -}; +}) satisfies IntegrationFn; /** Add node modules / packages to the event */ // eslint-disable-next-line deprecation/deprecation -export const ContextLines = convertIntegrationFnToClass(INTEGRATION_NAME, denoContextLinesIntegration); +export const ContextLines = convertIntegrationFnToClass( + INTEGRATION_NAME, + denoContextLinesIntegration, +) as IntegrationClass Promise }>; /** Processes an event and adds context lines */ async function addSourceContext(event: Event, contextLines: number): Promise { diff --git a/packages/deno/src/integrations/deno-cron.ts b/packages/deno/src/integrations/deno-cron.ts index 73c1bc1954fb..3b337b004405 100644 --- a/packages/deno/src/integrations/deno-cron.ts +++ b/packages/deno/src/integrations/deno-cron.ts @@ -1,5 +1,5 @@ import { convertIntegrationFnToClass, getClient, withMonitor } from '@sentry/core'; -import type { Client, IntegrationFn } from '@sentry/types'; +import type { Client, Integration, IntegrationClass, IntegrationFn } from '@sentry/types'; import { parseScheduleToString } from './deno-cron-format'; type CronOptions = { backoffSchedule?: number[]; signal?: AbortSignal }; @@ -62,4 +62,6 @@ const denoCronIntegration = (() => { /** Instruments Deno.cron to automatically capture cron check-ins */ // eslint-disable-next-line deprecation/deprecation -export const DenoCron = convertIntegrationFnToClass(INTEGRATION_NAME, denoCronIntegration); +export const DenoCron = convertIntegrationFnToClass(INTEGRATION_NAME, denoCronIntegration) as IntegrationClass< + Integration & { setup: (client: Client) => void } +>; diff --git a/packages/deno/src/integrations/globalhandlers.ts b/packages/deno/src/integrations/globalhandlers.ts index 05b46b58c7a9..895c52ee59e4 100644 --- a/packages/deno/src/integrations/globalhandlers.ts +++ b/packages/deno/src/integrations/globalhandlers.ts @@ -3,7 +3,15 @@ import { convertIntegrationFnToClass } from '@sentry/core'; import { captureEvent } from '@sentry/core'; import { getClient } from '@sentry/core'; import { flush } from '@sentry/core'; -import type { Client, Event, IntegrationFn, Primitive, StackParser } from '@sentry/types'; +import type { + Client, + Event, + Integration, + IntegrationClass, + IntegrationFn, + Primitive, + StackParser, +} from '@sentry/types'; import { eventFromUnknownInput, isPrimitive } from '@sentry/utils'; type GlobalHandlersIntegrationsOptionKeys = 'error' | 'unhandledrejection'; @@ -13,7 +21,7 @@ type GlobalHandlersIntegrations = Record { +const globalHandlersIntegration = ((options?: GlobalHandlersIntegrations) => { const _options = { error: true, unhandledrejection: true, @@ -33,11 +41,14 @@ const globalHandlersIntegration: IntegrationFn = (options?: GlobalHandlersIntegr } }, }; -}; +}) satisfies IntegrationFn; /** Global handlers */ // eslint-disable-next-line deprecation/deprecation -export const GlobalHandlers = convertIntegrationFnToClass(INTEGRATION_NAME, globalHandlersIntegration); +export const GlobalHandlers = convertIntegrationFnToClass( + INTEGRATION_NAME, + globalHandlersIntegration, +) as IntegrationClass void }>; function installGlobalErrorHandler(client: Client): void { globalThis.addEventListener('error', data => { diff --git a/packages/deno/src/integrations/normalizepaths.ts b/packages/deno/src/integrations/normalizepaths.ts index 39a3bab5a1c5..68ba3986e805 100644 --- a/packages/deno/src/integrations/normalizepaths.ts +++ b/packages/deno/src/integrations/normalizepaths.ts @@ -1,5 +1,5 @@ import { convertIntegrationFnToClass } from '@sentry/core'; -import type { IntegrationFn } from '@sentry/types'; +import type { Event, Integration, IntegrationClass, IntegrationFn } from '@sentry/types'; import { createStackParser, dirname, nodeStackLineParser } from '@sentry/utils'; const INTEGRATION_NAME = 'NormalizePaths'; @@ -55,10 +55,11 @@ function getCwd(): string | undefined { return undefined; } -const normalizePathsIntegration: IntegrationFn = () => { +const normalizePathsIntegration = (() => { // Cached here let appRoot: string | undefined; + /** Get the app root, and cache it after it was first fetched. */ function getAppRoot(error: Error): string | undefined { if (appRoot === undefined) { appRoot = getCwd() || appRootFromErrorStack(error); @@ -95,8 +96,11 @@ const normalizePathsIntegration: IntegrationFn = () => { return event; }, }; -}; +}) satisfies IntegrationFn; /** Normalises paths to the app root directory. */ // eslint-disable-next-line deprecation/deprecation -export const NormalizePaths = convertIntegrationFnToClass(INTEGRATION_NAME, normalizePathsIntegration); +export const NormalizePaths = convertIntegrationFnToClass( + INTEGRATION_NAME, + normalizePathsIntegration, +) as IntegrationClass Event }>; diff --git a/packages/integrations/src/captureconsole.ts b/packages/integrations/src/captureconsole.ts index 4d9aa04ce116..ece89c0ac38c 100644 --- a/packages/integrations/src/captureconsole.ts +++ b/packages/integrations/src/captureconsole.ts @@ -1,5 +1,5 @@ import { captureException, captureMessage, convertIntegrationFnToClass, getClient, withScope } from '@sentry/core'; -import type { CaptureContext, IntegrationFn } from '@sentry/types'; +import type { CaptureContext, Client, Integration, IntegrationClass, IntegrationFn } from '@sentry/types'; import { CONSOLE_LEVELS, GLOBAL_OBJ, @@ -40,7 +40,12 @@ const captureConsoleIntegration = ((options: CaptureConsoleOptions = {}) => { /** Send Console API calls as Sentry Events */ // eslint-disable-next-line deprecation/deprecation -export const CaptureConsole = convertIntegrationFnToClass(INTEGRATION_NAME, captureConsoleIntegration); +export const CaptureConsole = convertIntegrationFnToClass( + INTEGRATION_NAME, + captureConsoleIntegration, +) as IntegrationClass void }> & { + new (options?: { levels?: string[] }): Integration; +}; function consoleHandler(args: unknown[], level: string): void { const captureContext: CaptureContext = { diff --git a/packages/integrations/src/contextlines.ts b/packages/integrations/src/contextlines.ts index 143fb0232bec..86647fd8a769 100644 --- a/packages/integrations/src/contextlines.ts +++ b/packages/integrations/src/contextlines.ts @@ -1,5 +1,5 @@ import { convertIntegrationFnToClass } from '@sentry/core'; -import type { Event, IntegrationFn, StackFrame } from '@sentry/types'; +import type { Event, Integration, IntegrationClass, IntegrationFn, StackFrame } from '@sentry/types'; import { GLOBAL_OBJ, addContextToFrame, stripUrlQueryAndFragment } from '@sentry/utils'; const WINDOW = GLOBAL_OBJ as typeof GLOBAL_OBJ & Window; @@ -18,7 +18,7 @@ interface ContextLinesOptions { frameContextLines?: number; } -const contextLinesIntegration: IntegrationFn = (options: ContextLinesOptions = {}) => { +const contextLinesIntegration = ((options: ContextLinesOptions = {}) => { const contextLines = options.frameContextLines != null ? options.frameContextLines : DEFAULT_LINES_OF_CONTEXT; return { @@ -29,7 +29,7 @@ const contextLinesIntegration: IntegrationFn = (options: ContextLinesOptions = { return addSourceContext(event, contextLines); }, }; -}; +}) satisfies IntegrationFn; /** * Collects source context lines around the lines of stackframes pointing to JS embedded in @@ -43,7 +43,9 @@ const contextLinesIntegration: IntegrationFn = (options: ContextLinesOptions = { * by our backend (e.g. due to a login-protected page). */ // eslint-disable-next-line deprecation/deprecation -export const ContextLines = convertIntegrationFnToClass(INTEGRATION_NAME, contextLinesIntegration); +export const ContextLines = convertIntegrationFnToClass(INTEGRATION_NAME, contextLinesIntegration) as IntegrationClass< + Integration & { processEvent: (event: Event) => Event } +> & { new (options?: { frameContextLines?: number }): Integration }; /** * Processes an event and adds context lines. diff --git a/packages/integrations/src/debug.ts b/packages/integrations/src/debug.ts index 8e20ce7f9dfc..159d8a462bea 100644 --- a/packages/integrations/src/debug.ts +++ b/packages/integrations/src/debug.ts @@ -1,5 +1,5 @@ import { convertIntegrationFnToClass } from '@sentry/core'; -import type { Event, EventHint, IntegrationFn } from '@sentry/types'; +import type { Client, Event, EventHint, Integration, IntegrationClass, IntegrationFn } from '@sentry/types'; import { consoleSandbox } from '@sentry/utils'; const INTEGRATION_NAME = 'Debug'; @@ -58,4 +58,11 @@ const debugIntegration = ((options: DebugOptions = {}) => { * This integration should not be used in production */ // eslint-disable-next-line deprecation/deprecation -export const Debug = convertIntegrationFnToClass(INTEGRATION_NAME, debugIntegration); +export const Debug = convertIntegrationFnToClass(INTEGRATION_NAME, debugIntegration) as IntegrationClass< + Integration & { setup: (client: Client) => void } +> & { + new (options?: { + stringify?: boolean; + debugger?: boolean; + }): Integration; +}; diff --git a/packages/integrations/src/dedupe.ts b/packages/integrations/src/dedupe.ts index 97a47193b19a..996fd6161f9f 100644 --- a/packages/integrations/src/dedupe.ts +++ b/packages/integrations/src/dedupe.ts @@ -1,5 +1,5 @@ import { convertIntegrationFnToClass } from '@sentry/core'; -import type { Event, Exception, IntegrationFn, StackFrame } from '@sentry/types'; +import type { Event, Exception, Integration, IntegrationClass, IntegrationFn, StackFrame } from '@sentry/types'; import { logger } from '@sentry/utils'; import { DEBUG_BUILD } from './debug-build'; @@ -35,7 +35,9 @@ const dedupeIntegration = (() => { /** Deduplication filter */ // eslint-disable-next-line deprecation/deprecation -export const Dedupe = convertIntegrationFnToClass(INTEGRATION_NAME, dedupeIntegration); +export const Dedupe = convertIntegrationFnToClass(INTEGRATION_NAME, dedupeIntegration) as IntegrationClass< + Integration & { processEvent: (event: Event) => Event } +>; /** only exported for tests. */ export function _shouldDropEvent(currentEvent: Event, previousEvent?: Event): boolean { diff --git a/packages/integrations/src/extraerrordata.ts b/packages/integrations/src/extraerrordata.ts index 6b340a1283bc..41c4668f49de 100644 --- a/packages/integrations/src/extraerrordata.ts +++ b/packages/integrations/src/extraerrordata.ts @@ -1,5 +1,13 @@ import { convertIntegrationFnToClass } from '@sentry/core'; -import type { Contexts, Event, EventHint, ExtendedError, IntegrationFn } from '@sentry/types'; +import type { + Contexts, + Event, + EventHint, + ExtendedError, + Integration, + IntegrationClass, + IntegrationFn, +} from '@sentry/types'; import { addNonEnumerableProperty, isError, isPlainObject, logger, normalize } from '@sentry/utils'; import { DEBUG_BUILD } from './debug-build'; @@ -38,7 +46,17 @@ const extraErrorDataIntegration = ((options: Partial = {} /** Extract additional data for from original exceptions. */ // eslint-disable-next-line deprecation/deprecation -export const ExtraErrorData = convertIntegrationFnToClass(INTEGRATION_NAME, extraErrorDataIntegration); +export const ExtraErrorData = convertIntegrationFnToClass( + INTEGRATION_NAME, + extraErrorDataIntegration, +) as IntegrationClass Event }> & { + new ( + options?: Partial<{ + depth: number; + captureErrorCause: boolean; + }>, + ): Integration; +}; function _enhanceEventWithErrorData( event: Event, diff --git a/packages/integrations/src/httpclient.ts b/packages/integrations/src/httpclient.ts index 0ef2dcca3f27..4368beab8364 100644 --- a/packages/integrations/src/httpclient.ts +++ b/packages/integrations/src/httpclient.ts @@ -1,5 +1,12 @@ import { captureEvent, convertIntegrationFnToClass, getClient, isSentryRequestUrl } from '@sentry/core'; -import type { Client, Event as SentryEvent, IntegrationFn, SentryWrappedXMLHttpRequest } from '@sentry/types'; +import type { + Client, + Event as SentryEvent, + Integration, + IntegrationClass, + IntegrationFn, + SentryWrappedXMLHttpRequest, +} from '@sentry/types'; import { GLOBAL_OBJ, SENTRY_XHR_DATA_KEY, @@ -58,7 +65,14 @@ const httpClientIntegration = ((options: Partial = {}) => { /** HTTPClient integration creates events for failed client side HTTP requests. */ // eslint-disable-next-line deprecation/deprecation -export const HttpClient = convertIntegrationFnToClass(INTEGRATION_NAME, httpClientIntegration); +export const HttpClient = convertIntegrationFnToClass(INTEGRATION_NAME, httpClientIntegration) as IntegrationClass< + Integration & { setup: (client: Client) => void } +> & { + new (options?: { + failedRequestStatusCodes: HttpStatusCodeRange[]; + failedRequestTargets: HttpRequestTarget[]; + }): Integration; +}; /** * Interceptor function for fetch requests diff --git a/packages/integrations/src/reportingobserver.ts b/packages/integrations/src/reportingobserver.ts index cd8c28b54f8c..39c7da5ce97c 100644 --- a/packages/integrations/src/reportingobserver.ts +++ b/packages/integrations/src/reportingobserver.ts @@ -1,5 +1,5 @@ import { captureMessage, convertIntegrationFnToClass, getClient, withScope } from '@sentry/core'; -import type { Client, IntegrationFn } from '@sentry/types'; +import type { Client, Integration, IntegrationClass, IntegrationFn } from '@sentry/types'; import { GLOBAL_OBJ, supportsReportingObserver } from '@sentry/utils'; const WINDOW = GLOBAL_OBJ as typeof GLOBAL_OBJ & Window; @@ -51,6 +51,7 @@ const SETUP_CLIENTS = new WeakMap(); const reportingObserverIntegration = ((options: ReportingObserverOptions = {}) => { const types = options.types || ['crash', 'deprecation', 'intervention']; + /** Handler for the reporting observer. */ function handler(reports: Report[]): void { if (!SETUP_CLIENTS.has(getClient() as Client)) { return; @@ -116,4 +117,11 @@ const reportingObserverIntegration = ((options: ReportingObserverOptions = {}) = /** Reporting API integration - https://w3c.github.io/reporting/ */ // eslint-disable-next-line deprecation/deprecation -export const ReportingObserver = convertIntegrationFnToClass(INTEGRATION_NAME, reportingObserverIntegration); +export const ReportingObserver = convertIntegrationFnToClass( + INTEGRATION_NAME, + reportingObserverIntegration, +) as IntegrationClass void }> & { + new (options?: { + types?: ReportTypes[]; + }): Integration; +}; diff --git a/packages/integrations/src/rewriteframes.ts b/packages/integrations/src/rewriteframes.ts index 7bb5957607b2..31e9691df261 100644 --- a/packages/integrations/src/rewriteframes.ts +++ b/packages/integrations/src/rewriteframes.ts @@ -1,5 +1,5 @@ import { convertIntegrationFnToClass } from '@sentry/core'; -import type { Event, IntegrationFn, StackFrame, Stacktrace } from '@sentry/types'; +import type { Event, Integration, IntegrationClass, IntegrationFn, StackFrame, Stacktrace } from '@sentry/types'; import { basename, relative } from '@sentry/utils'; type StackFrameIteratee = (frame: StackFrame) => StackFrame; @@ -41,6 +41,7 @@ const rewriteFramesIntegration = ((options: RewriteFramesOptions = {}) => { return frame; }); + /** Process an exception event. */ function _processExceptionsEvent(event: Event): Event { try { return { @@ -60,6 +61,7 @@ const rewriteFramesIntegration = ((options: RewriteFramesOptions = {}) => { } } + /** Process a stack trace. */ function _processStacktrace(stacktrace?: Stacktrace): Stacktrace { return { ...stacktrace, @@ -85,4 +87,9 @@ const rewriteFramesIntegration = ((options: RewriteFramesOptions = {}) => { /** Rewrite event frames paths */ // eslint-disable-next-line deprecation/deprecation -export const RewriteFrames = convertIntegrationFnToClass(INTEGRATION_NAME, rewriteFramesIntegration); +export const RewriteFrames = convertIntegrationFnToClass( + INTEGRATION_NAME, + rewriteFramesIntegration, +) as IntegrationClass Event }> & { + new (options?: { root?: string; prefix?: string; iteratee?: StackFrameIteratee }): Integration; +}; diff --git a/packages/integrations/src/sessiontiming.ts b/packages/integrations/src/sessiontiming.ts index b3511e6c3527..0a316ca02381 100644 --- a/packages/integrations/src/sessiontiming.ts +++ b/packages/integrations/src/sessiontiming.ts @@ -1,5 +1,5 @@ import { convertIntegrationFnToClass } from '@sentry/core'; -import type { IntegrationFn } from '@sentry/types'; +import type { Event, Integration, IntegrationClass, IntegrationFn } from '@sentry/types'; const INTEGRATION_NAME = 'SessionTiming'; @@ -28,4 +28,7 @@ const sessionTimingIntegration = (() => { /** This function adds duration since Sentry was initialized till the time event was sent */ // eslint-disable-next-line deprecation/deprecation -export const SessionTiming = convertIntegrationFnToClass(INTEGRATION_NAME, sessionTimingIntegration); +export const SessionTiming = convertIntegrationFnToClass( + INTEGRATION_NAME, + sessionTimingIntegration, +) as IntegrationClass Event }>; diff --git a/packages/integrations/src/transaction.ts b/packages/integrations/src/transaction.ts index ce1701f041a4..5d6d0cd595e9 100644 --- a/packages/integrations/src/transaction.ts +++ b/packages/integrations/src/transaction.ts @@ -1,5 +1,5 @@ import { convertIntegrationFnToClass } from '@sentry/core'; -import type { Event, IntegrationFn, StackFrame } from '@sentry/types'; +import type { Event, Integration, IntegrationClass, IntegrationFn, StackFrame } from '@sentry/types'; const INTEGRATION_NAME = 'Transaction'; @@ -31,7 +31,9 @@ const transactionIntegration = (() => { * @deprecated This integration will be removed in v8. */ // eslint-disable-next-line deprecation/deprecation -export const Transaction = convertIntegrationFnToClass(INTEGRATION_NAME, transactionIntegration); +export const Transaction = convertIntegrationFnToClass(INTEGRATION_NAME, transactionIntegration) as IntegrationClass< + Integration & { processEvent: (event: Event) => Event } +>; function _getFramesFromEvent(event: Event): StackFrame[] { const exception = event.exception && event.exception.values && event.exception.values[0]; diff --git a/packages/integrations/test/sessiontiming.test.ts b/packages/integrations/test/sessiontiming.test.ts index d1569db52095..3eba2b906134 100644 --- a/packages/integrations/test/sessiontiming.test.ts +++ b/packages/integrations/test/sessiontiming.test.ts @@ -10,9 +10,9 @@ describe('SessionTiming', () => { }, }); - expect(typeof event.extra['session:start']).toBe('number'); - expect(typeof event.extra['session:duration']).toBe('number'); - expect(typeof event.extra['session:end']).toBe('number'); - expect((event.extra as any).some).toEqual('value'); + expect(typeof event.extra?.['session:start']).toBe('number'); + expect(typeof event.extra?.['session:duration']).toBe('number'); + expect(typeof event.extra?.['session:end']).toBe('number'); + expect(event.extra?.some).toEqual('value'); }); }); diff --git a/packages/node/src/index.ts b/packages/node/src/index.ts index 6d856d14fc39..a6c5ba4ea1fd 100644 --- a/packages/node/src/index.ts +++ b/packages/node/src/index.ts @@ -99,7 +99,6 @@ export { createGetModuleFromFilename }; export { enableAnrDetection } from './integrations/anr/legacy'; import { Integrations as CoreIntegrations } from '@sentry/core'; -import type { Integration, IntegrationClass } from '@sentry/types'; import * as Handlers from './handlers'; import * as NodeIntegrations from './integrations'; @@ -107,23 +106,7 @@ import * as TracingIntegrations from './tracing/integrations'; const INTEGRATIONS = { ...CoreIntegrations, - // This typecast is somehow needed for now, probably because of the convertIntegrationFnToClass TS shenanigans - // This is OK for now but should be resolved in v8 when we just pass the functional integrations directly - ...(NodeIntegrations as { - Console: IntegrationClass; - Http: typeof NodeIntegrations.Http; - OnUncaughtException: IntegrationClass; - OnUnhandledRejection: IntegrationClass; - Modules: IntegrationClass; - ContextLines: IntegrationClass; - Context: IntegrationClass; - RequestData: IntegrationClass; - LocalVariables: IntegrationClass; - Undici: typeof NodeIntegrations.Undici; - Spotlight: IntegrationClass; - Anr: IntegrationClass; - Hapi: IntegrationClass; - }), + ...NodeIntegrations, ...TracingIntegrations, }; diff --git a/packages/node/src/integrations/anr/index.ts b/packages/node/src/integrations/anr/index.ts index 1ebca2fdff57..e444427f2e47 100644 --- a/packages/node/src/integrations/anr/index.ts +++ b/packages/node/src/integrations/anr/index.ts @@ -1,7 +1,7 @@ // TODO (v8): This import can be removed once we only support Node with global URL import { URL } from 'url'; import { convertIntegrationFnToClass, getCurrentScope } from '@sentry/core'; -import type { Contexts, Event, EventHint, IntegrationFn } from '@sentry/types'; +import type { Client, Contexts, Event, EventHint, Integration, IntegrationClass, IntegrationFn } from '@sentry/types'; import { dynamicRequire, logger } from '@sentry/utils'; import type { Worker, WorkerOptions } from 'worker_threads'; import type { NodeClient } from '../../client'; @@ -74,7 +74,11 @@ const anrIntegration = ((options: Partial = {}) => { * ANR detection requires Node 16.17.0 or later */ // eslint-disable-next-line deprecation/deprecation -export const Anr = convertIntegrationFnToClass(INTEGRATION_NAME, anrIntegration); +export const Anr = convertIntegrationFnToClass(INTEGRATION_NAME, anrIntegration) as IntegrationClass< + Integration & { setup: (client: NodeClient) => void } +> & { + new (options?: Partial): Integration & { setup(client: Client): void }; +}; /** * Starts the ANR worker thread diff --git a/packages/node/src/integrations/console.ts b/packages/node/src/integrations/console.ts index eb46b58adf74..1d4e0182e59a 100644 --- a/packages/node/src/integrations/console.ts +++ b/packages/node/src/integrations/console.ts @@ -1,6 +1,6 @@ import * as util from 'util'; import { addBreadcrumb, convertIntegrationFnToClass, getClient } from '@sentry/core'; -import type { IntegrationFn } from '@sentry/types'; +import type { Client, Integration, IntegrationClass, IntegrationFn } from '@sentry/types'; import { addConsoleInstrumentationHandler, severityLevelFromString } from '@sentry/utils'; const INTEGRATION_NAME = 'Console'; @@ -34,4 +34,6 @@ const consoleIntegration = (() => { /** Console module integration */ // eslint-disable-next-line deprecation/deprecation -export const Console = convertIntegrationFnToClass(INTEGRATION_NAME, consoleIntegration); +export const Console = convertIntegrationFnToClass(INTEGRATION_NAME, consoleIntegration) as IntegrationClass< + Integration & { setup: (client: Client) => void } +>; diff --git a/packages/node/src/integrations/context.ts b/packages/node/src/integrations/context.ts index 461f85297e4b..058ce40b4c11 100644 --- a/packages/node/src/integrations/context.ts +++ b/packages/node/src/integrations/context.ts @@ -12,6 +12,8 @@ import type { CultureContext, DeviceContext, Event, + Integration, + IntegrationClass, IntegrationFn, OsContext, } from '@sentry/types'; @@ -35,7 +37,7 @@ interface ContextOptions { cloudResource?: boolean; } -const contextIntegration = ((options: ContextOptions = {}) => { +const nodeContextIntegration = ((options: ContextOptions = {}) => { let cachedContext: Promise | undefined; const _options = { @@ -47,6 +49,7 @@ const contextIntegration = ((options: ContextOptions = {}) => { ...options, }; + /** Add contexts to the event. Caches the context so we only look it up once. */ async function addContext(event: Event): Promise { if (cachedContext === undefined) { cachedContext = _getContexts(); @@ -66,6 +69,7 @@ const contextIntegration = ((options: ContextOptions = {}) => { return event; } + /** Get the contexts from node. */ async function _getContexts(): Promise { const contexts: Contexts = {}; @@ -108,7 +112,17 @@ const contextIntegration = ((options: ContextOptions = {}) => { /** Add node modules / packages to the event */ // eslint-disable-next-line deprecation/deprecation -export const Context = convertIntegrationFnToClass(INTEGRATION_NAME, contextIntegration); +export const Context = convertIntegrationFnToClass(INTEGRATION_NAME, nodeContextIntegration) as IntegrationClass< + Integration & { processEvent: (event: Event) => Promise } +> & { + new (options?: { + app?: boolean; + os?: boolean; + device?: { cpu?: boolean; memory?: boolean } | boolean; + culture?: boolean; + cloudResource?: boolean; + }): Integration; +}; /** * Updates the context with dynamic values that can change diff --git a/packages/node/src/integrations/contextlines.ts b/packages/node/src/integrations/contextlines.ts index 4f7ab81f063e..eccc80f7527a 100644 --- a/packages/node/src/integrations/contextlines.ts +++ b/packages/node/src/integrations/contextlines.ts @@ -1,6 +1,6 @@ import { readFile } from 'fs'; import { convertIntegrationFnToClass } from '@sentry/core'; -import type { Event, IntegrationFn, StackFrame } from '@sentry/types'; +import type { Event, Integration, IntegrationClass, IntegrationFn, StackFrame } from '@sentry/types'; import { LRUMap, addContextToFrame } from '@sentry/utils'; const FILE_CONTENT_CACHE = new LRUMap(100); @@ -50,7 +50,9 @@ const contextLinesIntegration = ((options: ContextLinesOptions = {}) => { /** Add node modules / packages to the event */ // eslint-disable-next-line deprecation/deprecation -export const ContextLines = convertIntegrationFnToClass(INTEGRATION_NAME, contextLinesIntegration); +export const ContextLines = convertIntegrationFnToClass(INTEGRATION_NAME, contextLinesIntegration) as IntegrationClass< + Integration & { processEvent: (event: Event) => Promise } +> & { new (options?: { frameContextLines?: number }): Integration }; async function addSourceContext(event: Event, contextLines: number): Promise { // keep a lookup map of which files we've already enqueued to read, diff --git a/packages/node/src/integrations/local-variables/local-variables-async.ts b/packages/node/src/integrations/local-variables/local-variables-async.ts index 360d553e48a2..7e393dced9e0 100644 --- a/packages/node/src/integrations/local-variables/local-variables-async.ts +++ b/packages/node/src/integrations/local-variables/local-variables-async.ts @@ -1,6 +1,6 @@ import type { Session } from 'node:inspector/promises'; import { convertIntegrationFnToClass } from '@sentry/core'; -import type { Event, Exception, IntegrationFn, StackParser } from '@sentry/types'; +import type { Event, Exception, Integration, IntegrationClass, IntegrationFn, StackParser } from '@sentry/types'; import { LRUMap, dynamicRequire, logger } from '@sentry/utils'; import type { Debugger, InspectorNotification, Runtime } from 'inspector'; @@ -70,7 +70,7 @@ const INTEGRATION_NAME = 'LocalVariablesAsync'; /** * Adds local variables to exception frames */ -export const localVariablesAsync: IntegrationFn = (options: Options = {}) => { +const localVariablesAsyncIntegration = ((options: Options = {}) => { const cachedFrames: LRUMap = new LRUMap(20); let rateLimiter: RateLimitIncrement | undefined; let shouldProcessEvent = false; @@ -245,10 +245,13 @@ export const localVariablesAsync: IntegrationFn = (options: Options = {}) => { return event; }, }; -}; +}) satisfies IntegrationFn; /** * Adds local variables to exception frames */ // eslint-disable-next-line deprecation/deprecation -export const LocalVariablesAsync = convertIntegrationFnToClass(INTEGRATION_NAME, localVariablesAsync); +export const LocalVariablesAsync = convertIntegrationFnToClass( + INTEGRATION_NAME, + localVariablesAsyncIntegration, +) as IntegrationClass Event; setup: (client: NodeClient) => void }>; diff --git a/packages/node/src/integrations/local-variables/local-variables-sync.ts b/packages/node/src/integrations/local-variables/local-variables-sync.ts index 45d17748ec78..bfe255002975 100644 --- a/packages/node/src/integrations/local-variables/local-variables-sync.ts +++ b/packages/node/src/integrations/local-variables/local-variables-sync.ts @@ -1,6 +1,6 @@ /* eslint-disable max-lines */ import { convertIntegrationFnToClass } from '@sentry/core'; -import type { Event, Exception, IntegrationFn, StackParser } from '@sentry/types'; +import type { Event, Exception, Integration, IntegrationClass, IntegrationFn, StackParser } from '@sentry/types'; import { LRUMap, logger } from '@sentry/utils'; import type { Debugger, InspectorNotification, Runtime, Session } from 'inspector'; import type { NodeClient } from '../../client'; @@ -213,7 +213,7 @@ const INTEGRATION_NAME = 'LocalVariables'; /** * Adds local variables to exception frames */ -export const localVariablesSync: IntegrationFn = ( +const localVariablesSyncIntegration = (( options: Options = {}, session: DebugSession | undefined = tryNewAsyncSession(), ) => { @@ -385,10 +385,15 @@ export const localVariablesSync: IntegrationFn = ( return cachedFrames.values()[0]; }, }; -}; +}) satisfies IntegrationFn; /** * Adds local variables to exception frames */ // eslint-disable-next-line deprecation/deprecation -export const LocalVariablesSync = convertIntegrationFnToClass(INTEGRATION_NAME, localVariablesSync); +export const LocalVariablesSync = convertIntegrationFnToClass( + INTEGRATION_NAME, + localVariablesSyncIntegration, +) as IntegrationClass Event; setup: (client: NodeClient) => void }> & { + new (options?: Options, session?: DebugSession): Integration; +}; diff --git a/packages/node/src/integrations/modules.ts b/packages/node/src/integrations/modules.ts index 85bb792f60b2..e21a92e770d7 100644 --- a/packages/node/src/integrations/modules.ts +++ b/packages/node/src/integrations/modules.ts @@ -1,7 +1,7 @@ import { existsSync, readFileSync } from 'fs'; import { dirname, join } from 'path'; import { convertIntegrationFnToClass } from '@sentry/core'; -import type { IntegrationFn } from '@sentry/types'; +import type { Event, Integration, IntegrationClass, IntegrationFn } from '@sentry/types'; let moduleCache: { [key: string]: string }; @@ -94,4 +94,6 @@ const modulesIntegration = (() => { /** Add node modules / packages to the event */ // eslint-disable-next-line deprecation/deprecation -export const Modules = convertIntegrationFnToClass(INTEGRATION_NAME, modulesIntegration); +export const Modules = convertIntegrationFnToClass(INTEGRATION_NAME, modulesIntegration) as IntegrationClass< + Integration & { processEvent: (event: Event) => Event } +>; diff --git a/packages/node/src/integrations/onuncaughtexception.ts b/packages/node/src/integrations/onuncaughtexception.ts index bdee16d3e953..a3346f6153d5 100644 --- a/packages/node/src/integrations/onuncaughtexception.ts +++ b/packages/node/src/integrations/onuncaughtexception.ts @@ -1,6 +1,6 @@ import { captureException, convertIntegrationFnToClass } from '@sentry/core'; import { getClient } from '@sentry/core'; -import type { IntegrationFn } from '@sentry/types'; +import type { Integration, IntegrationClass, IntegrationFn } from '@sentry/types'; import { logger } from '@sentry/utils'; import type { NodeClient } from '../client'; @@ -58,7 +58,17 @@ const onUncaughtExceptionIntegration = ((options: Partial void }> & { + new ( + options?: Partial<{ + exitEvenIfOtherHandlersAreRegistered: boolean; + onFatalError?(this: void, firstError: Error, secondError?: Error): void; + }>, + ): Integration; +}; type ErrorHandler = { _errorHandler: boolean } & ((error: Error) => void); diff --git a/packages/node/src/integrations/onunhandledrejection.ts b/packages/node/src/integrations/onunhandledrejection.ts index 2820f8789065..45fa5a61ca57 100644 --- a/packages/node/src/integrations/onunhandledrejection.ts +++ b/packages/node/src/integrations/onunhandledrejection.ts @@ -1,5 +1,5 @@ import { captureException, convertIntegrationFnToClass, getClient } from '@sentry/core'; -import type { Client, IntegrationFn } from '@sentry/types'; +import type { Client, Integration, IntegrationClass, IntegrationFn } from '@sentry/types'; import { consoleSandbox } from '@sentry/utils'; import { logAndExitProcess } from './utils/errorhandling'; @@ -31,7 +31,12 @@ const onUnhandledRejectionIntegration = ((options: Partial void }> & { + new (options?: Partial<{ mode: UnhandledRejectionMode }>): Integration; +}; /** * Send an exception with reason diff --git a/packages/node/src/integrations/spotlight.ts b/packages/node/src/integrations/spotlight.ts index a248810cb2f6..f6e5c1e45adc 100644 --- a/packages/node/src/integrations/spotlight.ts +++ b/packages/node/src/integrations/spotlight.ts @@ -1,7 +1,7 @@ import * as http from 'http'; import { URL } from 'url'; import { convertIntegrationFnToClass } from '@sentry/core'; -import type { Client, Envelope, IntegrationFn } from '@sentry/types'; +import type { Client, Envelope, Integration, IntegrationClass, IntegrationFn } from '@sentry/types'; import { logger, serializeEnvelope } from '@sentry/utils'; type SpotlightConnectionOptions = { @@ -40,7 +40,15 @@ const spotlightIntegration = ((options: Partial = {} * Important: This integration only works with Node 18 or newer */ // eslint-disable-next-line deprecation/deprecation -export const Spotlight = convertIntegrationFnToClass(INTEGRATION_NAME, spotlightIntegration); +export const Spotlight = convertIntegrationFnToClass(INTEGRATION_NAME, spotlightIntegration) as IntegrationClass< + Integration & { setup: (client: Client) => void } +> & { + new ( + options?: Partial<{ + sidecarUrl?: string; + }>, + ): Integration; +}; function connectToSpotlight(client: Client, options: Required): void { const spotlightUrl = parseSidecarUrl(options.sidecarUrl);