diff --git a/packages/aws-serverless/src/sdk.ts b/packages/aws-serverless/src/sdk.ts index 34921d24c7ff..23706f0a4463 100644 --- a/packages/aws-serverless/src/sdk.ts +++ b/packages/aws-serverless/src/sdk.ts @@ -71,7 +71,7 @@ export function getDefaultIntegrations(_options: Options): Integration[] { * * @param options Configuration options for the SDK, @see {@link AWSLambdaOptions}. */ -export function init(options: NodeOptions = {}): NodeClient | undefined { +export function init(options: NodeOptions<['Aws', 'AwsLambda']> = {}): NodeClient | undefined { const opts = { _metadata: {} as SdkMetadata, defaultIntegrations: getDefaultIntegrations(options), diff --git a/packages/browser/src/client.ts b/packages/browser/src/client.ts index 0e5b3fb6214c..91f6aac3ed8c 100644 --- a/packages/browser/src/client.ts +++ b/packages/browser/src/client.ts @@ -24,7 +24,22 @@ import type { BrowserTransportOptions } from './transports/types'; * Configuration options for the Sentry Browser SDK. * @see @sentry/core Options for more information. */ -export type BrowserOptions = Options & +export type BrowserOptions = Options< + BrowserTransportOptions, + [ + 'InboundFilters', + 'FunctionToString', + 'BrowserApiErrors', + 'Breadcrumbs', + 'GlobalHandlers', + 'LinkedErrors', + 'Dedupe', + 'HttpContext', + 'BrowserSession', + 'BrowserTracing', + ...AdditionalDefaultIntegrations, + ] +> & BrowserClientReplayOptions & BrowserClientProfilingOptions & { /** diff --git a/packages/browser/src/sdk.ts b/packages/browser/src/sdk.ts index 36dcade62859..9d5f931b11b8 100644 --- a/packages/browser/src/sdk.ts +++ b/packages/browser/src/sdk.ts @@ -32,6 +32,8 @@ export function getDefaultIntegrations(_options: Options): Integration[] { /** * Note: Please make sure this stays in sync with Angular SDK, which re-exports * `getDefaultIntegrations` but with an adjusted set of integrations. + * + * Ensure to keep this in sync with `BrowserOptions`! */ return [ inboundFiltersIntegration(), diff --git a/packages/bun/src/sdk.ts b/packages/bun/src/sdk.ts index 8bded2d492af..385ba164f19c 100644 --- a/packages/bun/src/sdk.ts +++ b/packages/bun/src/sdk.ts @@ -23,7 +23,10 @@ import { bunServerIntegration } from './integrations/bunserver'; import { makeFetchTransport } from './transports'; import type { BunOptions } from './types'; -/** Get the default integrations for the Bun SDK. */ +/** + * Get the default integrations for the Bun SDK. + * Ensure to keep this in sync with `BunOptions`! + */ export function getDefaultIntegrations(_options: Options): Integration[] { // We return a copy of the defaultIntegrations here to avoid mutating this return [ diff --git a/packages/bun/src/types.ts b/packages/bun/src/types.ts index fa0e2171214f..cea7ef4fc16c 100644 --- a/packages/bun/src/types.ts +++ b/packages/bun/src/types.ts @@ -41,7 +41,26 @@ export interface BaseBunOptions { * Configuration options for the Sentry Bun SDK * @see @sentry/core Options for more information. */ -export interface BunOptions extends Options, BaseBunOptions {} +export interface BunOptions + extends Options< + BunTransportOptions, + [ + 'InboundFilters', + 'FunctionToString', + 'LinkedErrors', + 'RequestData', + 'Console', + 'Http', + 'NodeFetch', + 'OnUncaughtException', + 'OnUnhandledRejection', + 'ContextLines', + 'Context', + 'Modules', + 'BunServer', + ] + >, + BaseBunOptions {} /** * Configuration options for the Sentry Bun SDK Client class diff --git a/packages/cloudflare/src/client.ts b/packages/cloudflare/src/client.ts index dd8a0cccdec8..60e72bca52f3 100644 --- a/packages/cloudflare/src/client.ts +++ b/packages/cloudflare/src/client.ts @@ -37,7 +37,12 @@ interface BaseCloudflareOptions {} * * @see @sentry/core Options for more information. */ -export interface CloudflareOptions extends Options, BaseCloudflareOptions {} +export interface CloudflareOptions + extends Options< + CloudflareTransportOptions, + ['Dedupe', 'InboundFilters', 'FunctionToString', 'LinkedErrors', 'Fetch', 'RequestData'] + >, + BaseCloudflareOptions {} /** * Configuration options for the Sentry Cloudflare SDK Client class diff --git a/packages/cloudflare/src/sdk.ts b/packages/cloudflare/src/sdk.ts index 89f3fe99d050..5af758703a4c 100644 --- a/packages/cloudflare/src/sdk.ts +++ b/packages/cloudflare/src/sdk.ts @@ -15,7 +15,10 @@ import { fetchIntegration } from './integrations/fetch'; import { makeCloudflareTransport } from './transport'; import { defaultStackParser } from './vendor/stacktrace'; -/** Get the default integrations for the Cloudflare SDK. */ +/** + * Get the default integrations for the Cloudflare SDK. + * Ensure to keep this in sync with `CloudflareOptions`! + */ export function getDefaultIntegrations(options: CloudflareOptions): Integration[] { const sendDefaultPii = options.sendDefaultPii ?? false; return [ diff --git a/packages/core/src/integration.ts b/packages/core/src/integration.ts index 31d5426d4fbc..152d011b0852 100644 --- a/packages/core/src/integration.ts +++ b/packages/core/src/integration.ts @@ -40,9 +40,12 @@ function filterDuplicates(integrations: Integration[]): Integration[] { } /** Gets integrations to install */ -export function getIntegrationsToSetup(options: Pick): Integration[] { +export function getIntegrationsToSetup( + options: Pick, +): Integration[] { const defaultIntegrations = options.defaultIntegrations || []; const userIntegrations = options.integrations; + const disableIntegrations = options.disableIntegrations || {}; // We flag default instances, so that later we can tell them apart from any user-created instances of the same class defaultIntegrations.forEach((integration: IntegrationWithDefaultInstance) => { @@ -60,6 +63,9 @@ export function getIntegrationsToSetup(options: Pick !disableIntegrations[integration.name]); + return filterDuplicates(integrations); } diff --git a/packages/core/src/types-hoist/integration.ts b/packages/core/src/types-hoist/integration.ts index cc9e4bc580ce..11fbaf6a9681 100644 --- a/packages/core/src/types-hoist/integration.ts +++ b/packages/core/src/types-hoist/integration.ts @@ -48,3 +48,10 @@ export interface Integration { * This is expected to return an integration. */ export type IntegrationFn = (...rest: any[]) => IntegrationType; + +/** + * A map of integration names to true/false. + */ +export type IntegrationsMapping = Record & { + [key in KnownIntegrationNames[number]]?: boolean | undefined; +}; diff --git a/packages/core/src/types-hoist/options.ts b/packages/core/src/types-hoist/options.ts index 8e52b32eacf7..05929c3119e7 100644 --- a/packages/core/src/types-hoist/options.ts +++ b/packages/core/src/types-hoist/options.ts @@ -1,7 +1,7 @@ import type { CaptureContext } from '../scope'; import type { Breadcrumb, BreadcrumbHint } from './breadcrumb'; import type { ErrorEvent, EventHint, TransactionEvent } from './event'; -import type { Integration } from './integration'; +import type { Integration, IntegrationsMapping } from './integration'; import type { TracesSamplerSamplingContext } from './samplingcontext'; import type { SdkMetadata } from './sdkmetadata'; import type { SpanJSON } from './span'; @@ -302,14 +302,27 @@ export interface ClientOptions - extends Omit>, 'integrations' | 'transport' | 'stackParser'> { +export interface Options< + TO extends BaseTransportOptions = BaseTransportOptions, + DefaultIntegrationNames extends string[] = [], +> extends Omit>, 'integrations' | 'transport' | 'stackParser'> { /** * If this is set to false, default integrations will not be added, otherwise this will internally be set to the * recommended default integrations. */ defaultIntegrations?: false | Integration[]; + /** + * Pass a map of integrations that should be explicitly disabled. + * This allows you to e.g. opt out of default integrations easily. + * For example, if you do not want to add the `inboundFiltersIntegration`, you can configure: + * + * ```js + * disableIntegrations: { InboundFilters: true } + * ``` + */ + disableIntegrations?: IntegrationsMapping; + /** * List of integrations that should be installed after SDK was initialized. * Accepts either a list of integrations or a function that receives diff --git a/packages/core/test/lib/integration.test.ts b/packages/core/test/lib/integration.test.ts index aa4be2432699..ea241819b770 100644 --- a/packages/core/test/lib/integration.test.ts +++ b/packages/core/test/lib/integration.test.ts @@ -189,6 +189,63 @@ describe('getIntegrationsToSetup', () => { }); }); + describe('disableIntegrations', () => { + it('works without integrations', () => { + const integrations = getIntegrationsToSetup({ + integrations: [], + disableIntegrations: {}, + }); + + expect(integrations.map(i => i.name)).toEqual([]); + }); + + it('ignores unknown integration names', () => { + const integrations = getIntegrationsToSetup({ + integrations: [new MockIntegration('foo'), new MockIntegration('bar')], + disableIntegrations: { + foo2: true, + bar2: true, + }, + }); + + expect(integrations.map(i => i.name)).toEqual(['foo', 'bar']); + }); + + it('removes default integrations', () => { + const integrations = getIntegrationsToSetup({ + defaultIntegrations: [new MockIntegration('foo'), new MockIntegration('bar'), new MockIntegration('baz')], + disableIntegrations: { + bar: true, + }, + }); + + expect(integrations.map(i => i.name)).toEqual(['foo', 'baz']); + }); + + it('removes default integrations', () => { + const integrations = getIntegrationsToSetup({ + defaultIntegrations: [new MockIntegration('foo'), new MockIntegration('bar'), new MockIntegration('baz')], + disableIntegrations: { + bar: true, + }, + }); + + expect(integrations.map(i => i.name)).toEqual(['foo', 'baz']); + }); + + it('ignores default integrations when setting false or undefined', () => { + const integrations = getIntegrationsToSetup({ + defaultIntegrations: [new MockIntegration('foo'), new MockIntegration('bar'), new MockIntegration('baz')], + disableIntegrations: { + bar: false, + foo: undefined, + }, + }); + + expect(integrations.map(i => i.name)).toEqual(['foo', 'bar', 'baz']); + }); + }); + it('works with empty array', () => { const integrations = getIntegrationsToSetup({ integrations: [], diff --git a/packages/deno/src/sdk.ts b/packages/deno/src/sdk.ts index 25dc550fc353..2f68b437f4e7 100644 --- a/packages/deno/src/sdk.ts +++ b/packages/deno/src/sdk.ts @@ -1,4 +1,4 @@ -import type { Client, Integration, Options, ServerRuntimeClientOptions, StackParser } from '@sentry/core'; +import type { Client, Integration, ServerRuntimeClientOptions, StackParser } from '@sentry/core'; import { createStackParser, dedupeIntegration, @@ -19,8 +19,11 @@ import { normalizePathsIntegration } from './integrations/normalizepaths'; import { makeFetchTransport } from './transports'; import type { DenoOptions } from './types'; -/** Get the default integrations for the Deno SDK. */ -export function getDefaultIntegrations(_options: Options): Integration[] { +/** + * Get the default integrations for the Deno SDK. + * Ensure to keep this in sync with `DenoOptions`! + */ +export function getDefaultIntegrations(_options: DenoOptions): Integration[] { // We return a copy of the defaultIntegrations here to avoid mutating this return [ // Common diff --git a/packages/deno/src/types.ts b/packages/deno/src/types.ts index 422e561bb644..462c33ce3726 100644 --- a/packages/deno/src/types.ts +++ b/packages/deno/src/types.ts @@ -31,7 +31,22 @@ export interface BaseDenoOptions { * Configuration options for the Sentry Deno SDK * @see @sentry/core Options for more information. */ -export interface DenoOptions extends Options, BaseDenoOptions {} +export interface DenoOptions + extends Options< + DenoTransportOptions, + [ + 'InboundFilters', + 'FunctionToString', + 'LinkedErrors', + 'Dedupe', + 'Breadcrumbs', + 'DenoContext', + 'ContextLines', + 'NormalizePaths', + 'GLobalHandlers', + ] + >, + BaseDenoOptions {} /** * Configuration options for the Sentry Deno SDK Client class diff --git a/packages/google-cloud-serverless/src/sdk.ts b/packages/google-cloud-serverless/src/sdk.ts index 03054d4bd1ff..7b570b030ec9 100644 --- a/packages/google-cloud-serverless/src/sdk.ts +++ b/packages/google-cloud-serverless/src/sdk.ts @@ -26,7 +26,7 @@ export function getDefaultIntegrations(_options: Options): Integration[] { /** * @see {@link Sentry.init} */ -export function init(options: NodeOptions = {}): NodeClient | undefined { +export function init(options: NodeOptions<['GoogleCloudHttp', 'GoogleCloudGrpc']> = {}): NodeClient | undefined { const opts = { _metadata: {} as SdkMetadata, defaultIntegrations: getDefaultIntegrations(options), diff --git a/packages/nestjs/src/sdk.ts b/packages/nestjs/src/sdk.ts index d9c00369e8b3..cd9c5d45d317 100644 --- a/packages/nestjs/src/sdk.ts +++ b/packages/nestjs/src/sdk.ts @@ -12,7 +12,7 @@ import { nestIntegration } from './integrations/nest'; /** * Initializes the NestJS SDK */ -export function init(options: NodeOptions | undefined = {}): NodeClient | undefined { +export function init(options: NodeOptions<['Nest']> | undefined = {}): NodeClient | undefined { const opts: NodeOptions = { defaultIntegrations: getDefaultIntegrations(options), ...options, diff --git a/packages/nextjs/src/client/index.ts b/packages/nextjs/src/client/index.ts index 163e29f0b9a7..38f0c51e9312 100644 --- a/packages/nextjs/src/client/index.ts +++ b/packages/nextjs/src/client/index.ts @@ -23,7 +23,7 @@ const globalWithInjectedValues = GLOBAL_OBJ as typeof GLOBAL_OBJ & { declare const __SENTRY_TRACING__: boolean; /** Inits the Sentry NextJS SDK on the browser with the React SDK. */ -export function init(options: BrowserOptions): Client | undefined { +export function init(options: BrowserOptions<['NextjsClientStackFrameNormalization']>): Client | undefined { const opts = { environment: getVercelEnv(true) || process.env.NODE_ENV, defaultIntegrations: getDefaultIntegrations(options), @@ -59,7 +59,7 @@ export function init(options: BrowserOptions): Client | undefined { return client; } -function getDefaultIntegrations(options: BrowserOptions): Integration[] { +function getDefaultIntegrations(options: BrowserOptions<['NextjsClientStackFrameNormalization']>): Integration[] { const customDefaultIntegrations = getReactDefaultIntegrations(options); // This evaluates to true unless __SENTRY_TRACING__ is text-replaced with "false", // in which case everything inside will get tree-shaken away diff --git a/packages/node/src/integrations/tracing/index.ts b/packages/node/src/integrations/tracing/index.ts index 7d06689f250d..d63f91c0c029 100644 --- a/packages/node/src/integrations/tracing/index.ts +++ b/packages/node/src/integrations/tracing/index.ts @@ -22,6 +22,8 @@ import { instrumentVercelAi, vercelAIIntegration } from './vercelai'; /** * With OTEL, all performance integrations will be added, as OTEL only initializes them when the patched package is actually required. + * + * Ensure to keep this in sync with `NodeOptions`! */ export function getAutoPerformanceIntegrations(): Integration[] { return [ diff --git a/packages/node/src/integrations/tracing/vercelai/index.ts b/packages/node/src/integrations/tracing/vercelai/index.ts index 2b2b843d00f7..4170a5393bb0 100644 --- a/packages/node/src/integrations/tracing/vercelai/index.ts +++ b/packages/node/src/integrations/tracing/vercelai/index.ts @@ -9,7 +9,7 @@ export const instrumentVercelAi = generateInstrumentOnce('vercelAI', () => new S const _vercelAIIntegration = (() => { return { - name: 'vercelAI', + name: 'VercelAI', setupOnce() { instrumentVercelAi(); }, diff --git a/packages/node/src/sdk/index.ts b/packages/node/src/sdk/index.ts index 4a4900cf5b60..41414f6d3db2 100644 --- a/packages/node/src/sdk/index.ts +++ b/packages/node/src/sdk/index.ts @@ -47,6 +47,8 @@ function getCjsOnlyIntegrations(): Integration[] { /** * Get default integrations, excluding performance. + * + * Ensure to keep this in sync with `NodeOptions`! */ export function getDefaultIntegrationsWithoutPerformance(): Integration[] { return [ diff --git a/packages/node/src/types.ts b/packages/node/src/types.ts index bf4913688470..f683e6da1c6e 100644 --- a/packages/node/src/types.ts +++ b/packages/node/src/types.ts @@ -136,7 +136,48 @@ export interface BaseNodeOptions { * Configuration options for the Sentry Node SDK * @see @sentry/core Options for more information. */ -export interface NodeOptions extends Options, BaseNodeOptions {} +export interface NodeOptions + extends Options< + NodeTransportOptions, + [ + 'InboundFilters', + 'FunctionToString', + 'LinkedErrors', + 'RequestData', + 'Console', + 'Http', + 'NodeFetch', + 'OnUncaughtException', + 'OnUnhandledRejection', + 'ContextLines', + 'LocalVariables', + 'Context', + 'ChildProcess', + 'ProcessSession', + 'Modules', + 'Express', + 'Fastify', + 'Graphql', + 'Mongo', + 'Mongoose', + 'Mysql', + 'Mysql2', + 'Redis', + 'Postgres', + 'Prisma', + 'Hapi', + 'Koa', + 'Connect', + 'Tedious', + 'GenericPool', + 'Kafka', + 'Amqplib', + 'LruMemoizer', + 'VercelAI', + ...AdditionalDefaultIntegrations, + ] + >, + BaseNodeOptions {} /** * Configuration options for the Sentry Node SDK Client class diff --git a/packages/vercel-edge/src/sdk.ts b/packages/vercel-edge/src/sdk.ts index fb6c524df4b4..e0e1941ef0c4 100644 --- a/packages/vercel-edge/src/sdk.ts +++ b/packages/vercel-edge/src/sdk.ts @@ -6,7 +6,7 @@ import { ATTR_SERVICE_VERSION, SEMRESATTRS_SERVICE_NAMESPACE, } from '@opentelemetry/semantic-conventions'; -import type { Client, Integration, Options } from '@sentry/core'; +import type { Client, Integration } from '@sentry/core'; import { GLOBAL_OBJ, SDK_VERSION, @@ -47,8 +47,11 @@ declare const process: { const nodeStackParser = createStackParser(nodeStackLineParser()); -/** Get the default integrations for the browser SDK. */ -export function getDefaultIntegrations(options: Options): Integration[] { +/** + * Get the default integrations for the VercelEdge SDK. + * Ensure to keep this in sync with `VercelEdgeOptions`! + */ +export function getDefaultIntegrations(options: VercelEdgeOptions): Integration[] { return [ dedupeIntegration(), inboundFiltersIntegration(), diff --git a/packages/vercel-edge/src/types.ts b/packages/vercel-edge/src/types.ts index 2128f23b35a8..8173576b0ebf 100644 --- a/packages/vercel-edge/src/types.ts +++ b/packages/vercel-edge/src/types.ts @@ -62,7 +62,12 @@ export interface BaseVercelEdgeOptions { * Configuration options for the Sentry VercelEdge SDK * @see @sentry/core Options for more information. */ -export interface VercelEdgeOptions extends Options, BaseVercelEdgeOptions {} +export interface VercelEdgeOptions + extends Options< + VercelEdgeTransportOptions, + ['Dedupe', 'InboundFilters', 'FunctionToString', 'LinkedErrors', 'WinterCGFetch', 'RequestData'] + >, + BaseVercelEdgeOptions {} /** * Configuration options for the Sentry VercelEdge SDK Client class diff --git a/packages/vue/src/types.ts b/packages/vue/src/types.ts index 6f61fc4e6104..406a8c9859eb 100644 --- a/packages/vue/src/types.ts +++ b/packages/vue/src/types.ts @@ -56,7 +56,7 @@ export interface VueOptions { tracingOptions?: Partial; } -export type Options = BrowserOptions & VueOptions; +export type Options = BrowserOptions<['Vue']> & VueOptions; /** Vue specific configuration for Tracing Integration */ export interface TracingOptions {