Skip to content

Commit 25f1c49

Browse files
authored
fix: Ensure we never mutate options passed to init (#9162)
In various places we mutate the `options` passed to `init()`, which is a) not a great pattern and b) may break if users pass in frozen or similar objects (for whatever reason). I also normalized this to ensure a passed in `_metadata.sdk` always takes precedent (we had this in most places, but not all). Closes #9155
1 parent 1140b25 commit 25f1c49

File tree

9 files changed

+93
-69
lines changed

9 files changed

+93
-69
lines changed

packages/angular-ivy/src/sdk.ts

Lines changed: 17 additions & 15 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';
33
import { defaultIntegrations, init as browserInit, SDK_VERSION, setContext } from '@sentry/browser';
4+
import type { SdkMetadata } from '@sentry/types';
45
import { logger } from '@sentry/utils';
56

67
import { IS_DEBUG_BUILD } from './flags';
@@ -9,8 +10,21 @@ import { IS_DEBUG_BUILD } from './flags';
910
* Inits the Angular SDK
1011
*/
1112
export function init(options: BrowserOptions): void {
12-
options._metadata = options._metadata || {};
13-
options._metadata.sdk = {
13+
const opts = {
14+
_metadata: {} as SdkMetadata,
15+
// Filter out TryCatch integration as it interferes with our Angular `ErrorHandler`:
16+
// TryCatch would catch certain errors before they reach the `ErrorHandler` and thus provide a
17+
// lower fidelity error than what `SentryErrorHandler` (see errorhandler.ts) would provide.
18+
// see:
19+
// - https://github.com/getsentry/sentry-javascript/issues/5417#issuecomment-1453407097
20+
// - https://github.com/getsentry/sentry-javascript/issues/2744
21+
defaultIntegrations: defaultIntegrations.filter(integration => {
22+
return integration.name !== 'TryCatch';
23+
}),
24+
...options,
25+
};
26+
27+
opts._metadata.sdk = opts._metadata.sdk || {
1428
name: 'sentry.javascript.angular-ivy',
1529
packages: [
1630
{
@@ -21,20 +35,8 @@ export function init(options: BrowserOptions): void {
2135
version: SDK_VERSION,
2236
};
2337

24-
// Filter out TryCatch integration as it interferes with our Angular `ErrorHandler`:
25-
// TryCatch would catch certain errors before they reach the `ErrorHandler` and thus provide a
26-
// lower fidelity error than what `SentryErrorHandler` (see errorhandler.ts) would provide.
27-
// see:
28-
// - https://github.com/getsentry/sentry-javascript/issues/5417#issuecomment-1453407097
29-
// - https://github.com/getsentry/sentry-javascript/issues/2744
30-
if (options.defaultIntegrations === undefined) {
31-
options.defaultIntegrations = defaultIntegrations.filter(integration => {
32-
return integration.name !== 'TryCatch';
33-
});
34-
}
35-
3638
checkAndSetAngularVersion();
37-
browserInit(options);
39+
browserInit(opts);
3840
}
3941

4042
function checkAndSetAngularVersion(): void {

packages/angular/src/sdk.ts

Lines changed: 17 additions & 15 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';
33
import { defaultIntegrations, init as browserInit, SDK_VERSION, setContext } from '@sentry/browser';
4+
import type { SdkMetadata } from '@sentry/types';
45
import { logger } from '@sentry/utils';
56

67
import { IS_DEBUG_BUILD } from './flags';
@@ -9,8 +10,21 @@ import { IS_DEBUG_BUILD } from './flags';
910
* Inits the Angular SDK
1011
*/
1112
export function init(options: BrowserOptions): void {
12-
options._metadata = options._metadata || {};
13-
options._metadata.sdk = {
13+
const opts = {
14+
_metadata: {} as SdkMetadata,
15+
// Filter out TryCatch integration as it interferes with our Angular `ErrorHandler`:
16+
// TryCatch would catch certain errors before they reach the `ErrorHandler` and thus provide a
17+
// lower fidelity error than what `SentryErrorHandler` (see errorhandler.ts) would provide.
18+
// see:
19+
// - https://github.com/getsentry/sentry-javascript/issues/5417#issuecomment-1453407097
20+
// - https://github.com/getsentry/sentry-javascript/issues/2744
21+
defaultIntegrations: defaultIntegrations.filter(integration => {
22+
return integration.name !== 'TryCatch';
23+
}),
24+
...options,
25+
};
26+
27+
opts._metadata.sdk = opts._metadata.sdk || {
1428
name: 'sentry.javascript.angular',
1529
packages: [
1630
{
@@ -21,20 +35,8 @@ export function init(options: BrowserOptions): void {
2135
version: SDK_VERSION,
2236
};
2337

24-
// Filter out TryCatch integration as it interferes with our Angular `ErrorHandler`:
25-
// TryCatch would catch certain errors before they reach the `ErrorHandler` and thus provide a
26-
// lower fidelity error than what `SentryErrorHandler` (see errorhandler.ts) would provide.
27-
// see:
28-
// - https://github.com/getsentry/sentry-javascript/issues/5417#issuecomment-1453407097
29-
// - https://github.com/getsentry/sentry-javascript/issues/2744
30-
if (options.defaultIntegrations === undefined) {
31-
options.defaultIntegrations = defaultIntegrations.filter(integration => {
32-
return integration.name !== 'TryCatch';
33-
});
34-
}
35-
3638
checkAndSetAngularVersion();
37-
browserInit(options);
39+
browserInit(opts);
3840
}
3941

4042
function checkAndSetAngularVersion(): void {

packages/nextjs/src/client/index.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,14 +44,17 @@ const globalWithInjectedValues = global as typeof global & {
4444

4545
/** Inits the Sentry NextJS SDK on the browser with the React SDK. */
4646
export function init(options: BrowserOptions): void {
47-
applyTunnelRouteOption(options);
48-
buildMetadata(options, ['nextjs', 'react']);
47+
const opts = {
48+
environment: getVercelEnv(true) || process.env.NODE_ENV,
49+
...options,
50+
};
4951

50-
options.environment = options.environment || getVercelEnv(true) || process.env.NODE_ENV;
52+
applyTunnelRouteOption(opts);
53+
buildMetadata(opts, ['nextjs', 'react']);
5154

52-
addClientIntegrations(options);
55+
addClientIntegrations(opts);
5356

54-
reactInit(options);
57+
reactInit(opts);
5558

5659
configureScope(scope => {
5760
scope.setTag('runtime', 'browser');

packages/nextjs/src/edge/index.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,18 @@
11
import { SDK_VERSION } from '@sentry/core';
2+
import type { SdkMetadata } from '@sentry/types';
23
import type { VercelEdgeOptions } from '@sentry/vercel-edge';
34
import { init as vercelEdgeInit } from '@sentry/vercel-edge';
45

56
export type EdgeOptions = VercelEdgeOptions;
67

78
/** Inits the Sentry NextJS SDK on the Edge Runtime. */
89
export function init(options: VercelEdgeOptions = {}): void {
9-
options._metadata = options._metadata || {};
10-
options._metadata.sdk = options._metadata.sdk || {
10+
const opts = {
11+
_metadata: {} as SdkMetadata,
12+
...options,
13+
};
14+
15+
opts._metadata.sdk = opts._metadata.sdk || {
1116
name: 'sentry.javascript.nextjs',
1217
packages: [
1318
{
@@ -18,7 +23,7 @@ export function init(options: VercelEdgeOptions = {}): void {
1823
version: SDK_VERSION,
1924
};
2025

21-
vercelEdgeInit(options);
26+
vercelEdgeInit(opts);
2227
}
2328

2429
/**

packages/nextjs/src/server/index.ts

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,14 @@ const IS_VERCEL = !!process.env.VERCEL;
6464

6565
/** Inits the Sentry NextJS SDK on node. */
6666
export function init(options: NodeOptions): void {
67-
if (__DEBUG_BUILD__ && options.debug) {
67+
const opts = {
68+
environment: process.env.SENTRY_ENVIRONMENT || getVercelEnv(false) || process.env.NODE_ENV,
69+
...options,
70+
// Right now we only capture frontend sessions for Next.js
71+
autoSessionTracking: false,
72+
};
73+
74+
if (__DEBUG_BUILD__ && opts.debug) {
6875
logger.enable();
6976
}
7077

@@ -75,16 +82,11 @@ export function init(options: NodeOptions): void {
7582
return;
7683
}
7784

78-
buildMetadata(options, ['nextjs', 'node']);
79-
80-
options.environment =
81-
options.environment || process.env.SENTRY_ENVIRONMENT || getVercelEnv(false) || process.env.NODE_ENV;
85+
buildMetadata(opts, ['nextjs', 'node']);
8286

83-
addServerIntegrations(options);
84-
// Right now we only capture frontend sessions for Next.js
85-
options.autoSessionTracking = false;
87+
addServerIntegrations(opts);
8688

87-
nodeInit(options);
89+
nodeInit(opts);
8890

8991
const filterTransactions: EventProcessor = event => {
9092
return event.type === 'transaction' && event.transaction === '/404' ? null : event;

packages/react/src/sdk.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,17 @@
11
import type { BrowserOptions } from '@sentry/browser';
22
import { init as browserInit, SDK_VERSION } from '@sentry/browser';
3+
import type { SdkMetadata } from '@sentry/types';
34

45
/**
56
* Inits the React SDK
67
*/
78
export function init(options: BrowserOptions): void {
8-
options._metadata = options._metadata || {};
9-
options._metadata.sdk = options._metadata.sdk || {
9+
const opts = {
10+
_metadata: {} as SdkMetadata,
11+
...options,
12+
};
13+
14+
opts._metadata.sdk = opts._metadata.sdk || {
1015
name: 'sentry.javascript.react',
1116
packages: [
1217
{
@@ -16,5 +21,5 @@ export function init(options: BrowserOptions): void {
1621
],
1722
version: SDK_VERSION,
1823
};
19-
browserInit(options);
24+
browserInit(opts);
2025
}

packages/serverless/src/awslambda.ts

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import type { Scope } from '@sentry/node';
33
import * as Sentry from '@sentry/node';
44
import { captureException, captureMessage, flush, getCurrentHub, withScope } from '@sentry/node';
5-
import type { Integration } from '@sentry/types';
5+
import type { Integration, SdkMetadata } from '@sentry/types';
66
import { isString, logger, tracingContextFromHeaders } from '@sentry/utils';
77
// NOTE: I have no idea how to fix this right now, and don't want to waste more time, as it builds just fine — Kamil
88
// eslint-disable-next-line import/no-unresolved
@@ -61,12 +61,13 @@ interface AWSLambdaOptions extends Sentry.NodeOptions {
6161
* @see {@link Sentry.init}
6262
*/
6363
export function init(options: AWSLambdaOptions = {}): void {
64-
if (options.defaultIntegrations === undefined) {
65-
options.defaultIntegrations = defaultIntegrations;
66-
}
64+
const opts = {
65+
_metadata: {} as SdkMetadata,
66+
defaultIntegrations,
67+
...options,
68+
};
6769

68-
options._metadata = options._metadata || {};
69-
options._metadata.sdk = {
70+
opts._metadata.sdk = opts._metadata.sdk || {
7071
name: 'sentry.javascript.serverless',
7172
integrations: ['AWSLambda'],
7273
packages: [
@@ -78,7 +79,7 @@ export function init(options: AWSLambdaOptions = {}): void {
7879
version: Sentry.SDK_VERSION,
7980
};
8081

81-
Sentry.init(options);
82+
Sentry.init(opts);
8283
Sentry.addGlobalEventProcessor(serverlessEventProcessor);
8384
}
8485

packages/serverless/src/gcpfunction/index.ts

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import * as Sentry from '@sentry/node';
2-
import type { Integration } from '@sentry/types';
2+
import type { Integration, SdkMetadata } from '@sentry/types';
33

44
import { GoogleCloudGrpc } from '../google-cloud-grpc';
55
import { GoogleCloudHttp } from '../google-cloud-http';
@@ -19,12 +19,13 @@ export const defaultIntegrations: Integration[] = [
1919
* @see {@link Sentry.init}
2020
*/
2121
export function init(options: Sentry.NodeOptions = {}): void {
22-
if (options.defaultIntegrations === undefined) {
23-
options.defaultIntegrations = defaultIntegrations;
24-
}
22+
const opts = {
23+
_metadata: {} as SdkMetadata,
24+
defaultIntegrations,
25+
...options,
26+
};
2527

26-
options._metadata = options._metadata || {};
27-
options._metadata.sdk = {
28+
opts._metadata.sdk = opts._metadata.sdk || {
2829
name: 'sentry.javascript.serverless',
2930
integrations: ['GCPFunction'],
3031
packages: [
@@ -36,6 +37,6 @@ export function init(options: Sentry.NodeOptions = {}): void {
3637
version: Sentry.SDK_VERSION,
3738
};
3839

39-
Sentry.init(options);
40+
Sentry.init(opts);
4041
Sentry.addGlobalEventProcessor(serverlessEventProcessor);
4142
}

packages/svelte/src/sdk.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
11
import type { BrowserOptions } from '@sentry/browser';
22
import { addGlobalEventProcessor, init as browserInit, SDK_VERSION } from '@sentry/browser';
3-
import type { EventProcessor } from '@sentry/types';
3+
import type { EventProcessor, SdkMetadata } from '@sentry/types';
44
import { getDomElement } from '@sentry/utils';
55
/**
66
* Inits the Svelte SDK
77
*/
88
export function init(options: BrowserOptions): void {
9-
options._metadata = options._metadata || {};
10-
options._metadata.sdk = options._metadata.sdk || {
9+
const opts = {
10+
_metadata: {} as SdkMetadata,
11+
...options,
12+
};
13+
14+
opts._metadata.sdk = opts._metadata.sdk || {
1115
name: 'sentry.javascript.svelte',
1216
packages: [
1317
{
@@ -17,8 +21,7 @@ export function init(options: BrowserOptions): void {
1721
],
1822
version: SDK_VERSION,
1923
};
20-
21-
browserInit(options);
24+
browserInit(opts);
2225

2326
detectAndReportSvelteKit();
2427
}

0 commit comments

Comments
 (0)