Skip to content

Commit e227076

Browse files
committed
feat: Refactor exposed defaultIntegrations to getDefaultIntegrations()
The current implementation has some problems: 1. It is weird that you can accidentally mutate the default integrations of another package 2. We sometimes have logic-based default integrations - e.g. adding an integration only if tracing is enabled, or similar. This means that either we have to add some logic in the _upstream_ SDK to ensure this is still added even if downstream SDKs overwrite default integrations, or we need to duplicate the logic in the _downstream_ SDKs. With this new method, we can instead centralize this, and downstream SDKs simply need to call upstream `getDefaultIntegrations(options)`.
1 parent caad0bc commit e227076

File tree

33 files changed

+256
-171
lines changed

33 files changed

+256
-171
lines changed

packages/angular-ivy/src/sdk.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { VERSION } from '@angular/core';
22
import type { BrowserOptions } from '@sentry/browser';
3-
import { SDK_VERSION, defaultIntegrations, init as browserInit, setContext } from '@sentry/browser';
3+
import { getDefaultIntegrations } from '@sentry/browser';
4+
import { SDK_VERSION, init as browserInit, setContext } from '@sentry/browser';
45
import type { SdkMetadata } from '@sentry/types';
56
import { logger } from '@sentry/utils';
67

@@ -18,7 +19,7 @@ export function init(options: BrowserOptions): void {
1819
// see:
1920
// - https://github.com/getsentry/sentry-javascript/issues/5417#issuecomment-1453407097
2021
// - https://github.com/getsentry/sentry-javascript/issues/2744
21-
defaultIntegrations: defaultIntegrations.filter(integration => {
22+
defaultIntegrations: getDefaultIntegrations(options).filter(integration => {
2223
return integration.name !== 'TryCatch';
2324
}),
2425
...options,

packages/angular/src/sdk.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { VERSION } from '@angular/core';
22
import type { BrowserOptions } from '@sentry/browser';
3-
import { SDK_VERSION, defaultIntegrations, init as browserInit, setContext } from '@sentry/browser';
3+
import { getDefaultIntegrations } from '@sentry/browser';
4+
import { SDK_VERSION, init as browserInit, setContext } from '@sentry/browser';
45
import type { SdkMetadata } from '@sentry/types';
56
import { logger } from '@sentry/utils';
67

@@ -18,7 +19,7 @@ export function init(options: BrowserOptions): void {
1819
// see:
1920
// - https://github.com/getsentry/sentry-javascript/issues/5417#issuecomment-1453407097
2021
// - https://github.com/getsentry/sentry-javascript/issues/2744
21-
defaultIntegrations: defaultIntegrations.filter(integration => {
22+
defaultIntegrations: getDefaultIntegrations(options).filter(integration => {
2223
return integration.name !== 'TryCatch';
2324
}),
2425
...options,

packages/angular/test/sdk.test.ts

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import * as SentryBrowser from '@sentry/browser';
22

3-
import { defaultIntegrations, init } from '../src/index';
3+
import { getDefaultIntegrations, init } from '../src/index';
44

55
describe('init', () => {
66
it('sets the Angular version (if available) in the global scope', () => {
@@ -30,16 +30,23 @@ describe('init', () => {
3030
expect(options.defaultIntegrations).not.toContainEqual(expect.objectContaining({ name: 'TryCatch' }));
3131
});
3232

33-
it.each([false as const, defaultIntegrations])(
34-
"doesn't filter if `defaultIntegrations` is set to %s",
35-
defaultIntegrations => {
36-
init({ defaultIntegrations });
33+
it("doesn't filter if `defaultIntegrations` is set to `false`", () => {
34+
init({ defaultIntegrations: false });
3735

38-
expect(browserInitSpy).toHaveBeenCalledTimes(1);
36+
expect(browserInitSpy).toHaveBeenCalledTimes(1);
37+
38+
const options = browserInitSpy.mock.calls[0][0] || {};
39+
expect(options.defaultIntegrations).toEqual(false);
40+
});
41+
42+
it("doesn't filter if `defaultIntegrations` is overwritten", () => {
43+
const defaultIntegrations = getDefaultIntegrations({});
44+
init({ defaultIntegrations });
3945

40-
const options = browserInitSpy.mock.calls[0][0] || {};
41-
expect(options.defaultIntegrations).toEqual(defaultIntegrations);
42-
},
43-
);
46+
expect(browserInitSpy).toHaveBeenCalledTimes(1);
47+
48+
const options = browserInitSpy.mock.calls[0][0] || {};
49+
expect(options.defaultIntegrations).toEqual(defaultIntegrations);
50+
});
4451
});
4552
});

packages/astro/src/index.server.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,9 @@ export {
5252
withIsolationScope,
5353
autoDiscoverNodePerformanceMonitoringIntegrations,
5454
makeNodeTransport,
55+
// eslint-disable-next-line deprecation/deprecation
5556
defaultIntegrations,
57+
getDefaultIntegrations,
5658
defaultStackParser,
5759
// eslint-disable-next-line deprecation/deprecation
5860
lastEventId,

packages/astro/src/index.types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ export declare function init(options: Options | clientSdk.BrowserOptions | serve
1717
export declare const Integrations: typeof clientSdk.Integrations & typeof serverSdk.Integrations;
1818

1919
export declare const defaultIntegrations: Integration[];
20+
export declare const getDefaultIntegrations: (options: Options) => Integration[];
2021
export declare const defaultStackParser: StackParser;
2122

2223
export declare function close(timeout?: number | undefined): PromiseLike<boolean>;

packages/browser/src/exports.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,9 @@ export {
8989
export { eventFromException, eventFromMessage, exceptionFromError } from './eventbuilder';
9090
export { createUserFeedbackEnvelope } from './userfeedback';
9191
export {
92+
// eslint-disable-next-line deprecation/deprecation
9293
defaultIntegrations,
94+
getDefaultIntegrations,
9395
forceLoad,
9496
init,
9597
onLoad,

packages/browser/src/sdk.ts

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import {
1010
initAndBind,
1111
startSession,
1212
} from '@sentry/core';
13-
import type { UserFeedback } from '@sentry/types';
13+
import type { Integration, Options, UserFeedback } from '@sentry/types';
1414
import {
1515
addHistoryInstrumentationHandler,
1616
logger,
@@ -27,18 +27,28 @@ import { Breadcrumbs, Dedupe, GlobalHandlers, HttpContext, LinkedErrors, TryCatc
2727
import { defaultStackParser } from './stack-parsers';
2828
import { makeFetchTransport, makeXHRTransport } from './transports';
2929

30-
/* eslint-disable deprecation/deprecation */
30+
/** @deprecated Use `getDefaultIntegrations(options)` instead. */
3131
export const defaultIntegrations = [
32+
/* eslint-disable deprecation/deprecation */
3233
new InboundFilters(),
3334
new FunctionToString(),
35+
/* eslint-enable deprecation/deprecation */
3436
new TryCatch(),
3537
new Breadcrumbs(),
3638
new GlobalHandlers(),
3739
new LinkedErrors(),
3840
new Dedupe(),
3941
new HttpContext(),
4042
];
41-
/* eslint-enable deprecation/deprecation */
43+
44+
/** Get the default integrations for the browser SDK. */
45+
export function getDefaultIntegrations(_options: Options): Integration[] {
46+
// We return a copy of the defaultIntegrations here to avoid mutating this
47+
return [
48+
// eslint-disable-next-line deprecation/deprecation
49+
...defaultIntegrations,
50+
];
51+
}
4252

4353
/**
4454
* A magic string that build tooling can leverage in order to inject a release value into the SDK.
@@ -104,7 +114,7 @@ declare const __SENTRY_RELEASE__: string | undefined;
104114
*/
105115
export function init(options: BrowserOptions = {}): void {
106116
if (options.defaultIntegrations === undefined) {
107-
options.defaultIntegrations = defaultIntegrations;
117+
options.defaultIntegrations = getDefaultIntegrations(options);
108118
}
109119
if (options.release === undefined) {
110120
// This allows build tooling to find-and-replace __SENTRY_RELEASE__ to inject a release value

packages/bun/src/index.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,12 @@ export type { SpanStatusType } from '@sentry/core';
8888
export { autoDiscoverNodePerformanceMonitoringIntegrations, cron } from '@sentry/node';
8989

9090
export { BunClient } from './client';
91-
export { defaultIntegrations, init } from './sdk';
91+
export {
92+
// eslint-disable-next-line deprecation/deprecation
93+
defaultIntegrations,
94+
getDefaultIntegrations,
95+
init,
96+
} from './sdk';
9297

9398
import { Integrations as CoreIntegrations } from '@sentry/core';
9499
import { Integrations as NodeIntegrations } from '@sentry/node';

packages/bun/src/sdk.ts

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,21 @@
11
/* eslint-disable max-lines */
22
import { FunctionToString, InboundFilters, LinkedErrors } from '@sentry/core';
33
import { Integrations as NodeIntegrations, init as initNode } from '@sentry/node';
4+
import type { Integration, Options } from '@sentry/types';
45

56
import { BunClient } from './client';
67
import { BunServer } from './integrations';
78
import { makeFetchTransport } from './transports';
89
import type { BunOptions } from './types';
910

10-
/* eslint-disable deprecation/deprecation */
11+
/** @deprecated Use `getDefaultIntegrations(options)` instead. */
1112
export const defaultIntegrations = [
13+
/* eslint-disable deprecation/deprecation */
1214
// Common
1315
new InboundFilters(),
1416
new FunctionToString(),
1517
new LinkedErrors(),
18+
/* eslint-enable deprecation/deprecation */
1619
// Native Wrappers
1720
new NodeIntegrations.Console(),
1821
new NodeIntegrations.Http(),
@@ -29,7 +32,15 @@ export const defaultIntegrations = [
2932
// Bun Specific
3033
new BunServer(),
3134
];
32-
/* eslint-enable deprecation/deprecation */
35+
36+
/** Get the default integrations for the Bun SDK. */
37+
export function getDefaultIntegrations(_options: Options): Integration[] {
38+
// We return a copy of the defaultIntegrations here to avoid mutating this
39+
return [
40+
// eslint-disable-next-line deprecation/deprecation
41+
...defaultIntegrations,
42+
];
43+
}
3344

3445
/**
3546
* The Sentry Bun SDK Client.
@@ -90,9 +101,9 @@ export function init(options: BunOptions = {}): void {
90101
options.clientClass = BunClient;
91102
options.transport = options.transport || makeFetchTransport;
92103

93-
options.defaultIntegrations =
94-
options.defaultIntegrations === false
95-
? []
96-
: [...(Array.isArray(options.defaultIntegrations) ? options.defaultIntegrations : defaultIntegrations)];
104+
if (options.defaultIntegrations === undefined) {
105+
options.defaultIntegrations = getDefaultIntegrations(options);
106+
}
107+
97108
initNode(options);
98109
}

packages/deno/src/index.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,12 @@ export type { SpanStatusType } from '@sentry/core';
8686

8787
export { DenoClient } from './client';
8888

89-
export { defaultIntegrations, init } from './sdk';
89+
export {
90+
// eslint-disable-next-line deprecation/deprecation
91+
defaultIntegrations,
92+
getDefaultIntegrations,
93+
init,
94+
} from './sdk';
9095

9196
import { Integrations as CoreIntegrations } from '@sentry/core';
9297

packages/deno/src/sdk.ts

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,22 @@ import { Breadcrumbs, Dedupe } from '@sentry/browser';
22
import type { ServerRuntimeClientOptions } from '@sentry/core';
33
import { FunctionToString, InboundFilters, LinkedErrors } from '@sentry/core';
44
import { getIntegrationsToSetup, initAndBind } from '@sentry/core';
5-
import type { StackParser } from '@sentry/types';
5+
import type { Integration, Options, StackParser } from '@sentry/types';
66
import { createStackParser, nodeStackLineParser, stackParserFromStackParserOptions } from '@sentry/utils';
77

88
import { DenoClient } from './client';
99
import { ContextLines, DenoContext, GlobalHandlers, NormalizePaths } from './integrations';
1010
import { makeFetchTransport } from './transports';
1111
import type { DenoOptions } from './types';
1212

13-
/* eslint-disable deprecation/deprecation */
13+
/** @deprecated Use `getDefaultIntegrations(options)` instead. */
1414
export const defaultIntegrations = [
15+
/* eslint-disable deprecation/deprecation */
1516
// Common
1617
new InboundFilters(),
1718
new FunctionToString(),
1819
new LinkedErrors(),
20+
/* eslint-enable deprecation/deprecation */
1921
// From Browser
2022
new Dedupe(),
2123
new Breadcrumbs({
@@ -29,7 +31,15 @@ export const defaultIntegrations = [
2931
new NormalizePaths(),
3032
new GlobalHandlers(),
3133
];
32-
/* eslint-enable deprecation/deprecation */
34+
35+
/** Get the default integrations for the Deno SDK. */
36+
export function getDefaultIntegrations(_options: Options): Integration[] {
37+
// We return a copy of the defaultIntegrations here to avoid mutating this
38+
return [
39+
// eslint-disable-next-line deprecation/deprecation
40+
...defaultIntegrations,
41+
];
42+
}
3343

3444
const defaultStackParser: StackParser = createStackParser(nodeStackLineParser());
3545

@@ -89,10 +99,9 @@ const defaultStackParser: StackParser = createStackParser(nodeStackLineParser())
8999
* @see {@link DenoOptions} for documentation on configuration options.
90100
*/
91101
export function init(options: DenoOptions = {}): void {
92-
options.defaultIntegrations =
93-
options.defaultIntegrations === false
94-
? []
95-
: [...(Array.isArray(options.defaultIntegrations) ? options.defaultIntegrations : defaultIntegrations)];
102+
if (options.defaultIntegrations === undefined) {
103+
options.defaultIntegrations = getDefaultIntegrations(options);
104+
}
96105

97106
const clientOptions: ServerRuntimeClientOptions = {
98107
...options,

packages/deno/test/mod.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { assertSnapshot } from 'https://deno.land/[email protected]/testing/snapshot.t
33

44
import type { sentryTypes } from '../build-test/index.js';
55
import { sentryUtils } from '../build-test/index.js';
6-
import { DenoClient, Hub, Scope, defaultIntegrations } from '../build/index.mjs';
6+
import { DenoClient, Hub, Scope, getDefaultIntegrations } from '../build/index.mjs';
77
import { getNormalizedEvent } from './normalize.ts';
88
import { makeTestTransport } from './transport.ts';
99

@@ -14,7 +14,7 @@ function getTestClient(
1414
const client = new DenoClient({
1515
dsn: 'https://[email protected]/5650507',
1616
debug: true,
17-
integrations: [...defaultIntegrations, ...integrations],
17+
integrations: [...getDefaultIntegrations({}), ...integrations],
1818
stackParser: sentryUtils.createStackParser(sentryUtils.nodeStackLineParser()),
1919
transport: makeTestTransport(envelope => {
2020
callback(getNormalizedEvent(envelope));

packages/nextjs/src/index.types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ export declare const Integrations: typeof clientSdk.Integrations &
2525
typeof edgeSdk.Integrations;
2626

2727
export declare const defaultIntegrations: Integration[];
28+
export declare const getDefaultIntegrations: (options: Options) => Integration[];
2829
export declare const defaultStackParser: StackParser;
2930

3031
export declare function getSentryRelease(fallback?: string): string | undefined;

packages/nextjs/test/clientSdk.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ describe('Client init()', () => {
184184
});
185185

186186
const reactInitOptions = reactInit.mock.calls[0][0] as ModifiedInitOptionsIntegrationFunction;
187-
const materializedIntegrations = reactInitOptions.integrations(SentryReact.defaultIntegrations);
187+
const materializedIntegrations = reactInitOptions.integrations(SentryReact.getDefaultIntegrations({}));
188188
const browserTracingIntegration = findIntegrationByName(materializedIntegrations, 'BrowserTracing');
189189

190190
expect(browserTracingIntegration).toEqual(

packages/node-experimental/src/integrations/node-fetch.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,14 @@ import type { Instrumentation } from '@opentelemetry/instrumentation';
44
import { addBreadcrumb, hasTracingEnabled } from '@sentry/core';
55
import { _INTERNAL, getClient, getSpanKind } from '@sentry/opentelemetry';
66
import type { Integration } from '@sentry/types';
7+
import { parseSemver } from '@sentry/utils';
78

89
import type { NodeExperimentalClient } from '../types';
910
import { addOriginToSpan } from '../utils/addOriginToSpan';
1011
import { NodePerformanceIntegration } from './NodePerformanceIntegration';
1112

13+
const NODE_VERSION: ReturnType<typeof parseSemver> = parseSemver(process.versions.node);
14+
1215
interface NodeFetchOptions {
1316
/**
1417
* Whether breadcrumbs should be recorded for requests
@@ -65,6 +68,11 @@ export class NodeFetch extends NodePerformanceIntegration<NodeFetchOptions> impl
6568

6669
/** @inheritDoc */
6770
public setupInstrumentation(): void | Instrumentation[] {
71+
// Only add NodeFetch if Node >= 16, as previous versions do not support it
72+
if (!NODE_VERSION.major || NODE_VERSION.major < 16) {
73+
return;
74+
}
75+
6876
try {
6977
// eslint-disable-next-line @typescript-eslint/no-var-requires
7078
const { FetchInstrumentation } = require('opentelemetry-instrumentation-fetch-node');

0 commit comments

Comments
 (0)