Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions MIGRATION.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -8,6 +8,10 @@ npx @sentry/migr8@latest

This will let you select which updates to run, and automatically update your code. Make sure to still review all code changes!

## Deprecate `client.setupIntegrations()`

Instead, use the new `client.init()` method. You should probably not use this directly and instead use `Sentry.init()`, which calls this under the hood. But if you have a special use case that requires that, you can call `client.init()` instead now.

## Deprecate `scope.getSpan()` and `scope.setSpan()`

Instead, you can get the currently active span via `Sentry.getActiveSpan()`.
Expand Down
2 changes: 1 addition & 1 deletion packages/browser/test/unit/sdk.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -42,7 +42,7 @@ jest.mock('@sentry/core', () => {
return new Scope();
},
bindClient(client: Client): boolean {
client.setupIntegrations();
client.init!();
return true;
},
};
Expand Down
20 changes: 17 additions & 3 deletions packages/core/src/baseclient.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -314,12 +314,19 @@ export abstract class BaseClient<O extends ClientOptions> implements Client<O> {
}

/**
* Sets up the integrations
* This is an internal function to setup all integrations that should run on the client.
* @deprecated Use `client.init()` instead.
*/
public setupIntegrations(forceInitialize?: boolean): void {
if ((forceInitialize && !this._integrationsInitialized) || (this._isEnabled() && !this._integrationsInitialized)) {
this._integrations = setupIntegrations(this, this._options.integrations);
this._integrationsInitialized = true;
this._setupIntegrations();
}
}

/** @inheritdoc */
public init(): void {
if (this._isEnabled()) {
this._setupIntegrations();
}
}

Expand DownExpand Up@@ -512,6 +519,13 @@ export abstract class BaseClient<O extends ClientOptions> implements Client<O> {

/* eslint-enable @typescript-eslint/unified-signatures */

/** Setup integrations for this client. */
protected _setupIntegrations(): void {
this._integrations = setupIntegrations(this, this._options.integrations);
// TODO v8: We don't need this flag anymore
this._integrationsInitialized = true;
}

/** Updates existing session based on the provided event */
protected _updateSessionFromEvent(session: Session, event: Event): void {
let crashed = false;
Expand Down
2 changes: 2 additions & 0 deletions packages/core/src/hub.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -167,7 +167,9 @@ export class Hub implements HubInterface {
const top = this.getStackTop();
top.client = client;
top.scope.setClient(client);
// eslint-disable-next-line deprecation/deprecation
if (client && client.setupIntegrations) {
// eslint-disable-next-line deprecation/deprecation
client.setupIntegrations();
}
}
Expand Down
74 changes: 69 additions & 5 deletions packages/core/test/lib/base.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -671,7 +671,7 @@ describe('BaseClient', () => {
test('adds installed integrations to sdk info', () => {
const options = getDefaultTestClientOptions({ dsn: PUBLIC_DSN, integrations: [new TestIntegration()] });
const client = new TestClient(options);
client.setupIntegrations();
client.init();

client.captureEvent({ message: 'message' });

Expand All@@ -685,7 +685,7 @@ describe('BaseClient', () => {

const options = getDefaultTestClientOptions({ dsn: PUBLIC_DSN, integrations: [new TestIntegration()] });
const client = new TestClient(options);
client.setupIntegrations();
client.init();
client.addIntegration(new AdHocIntegration());

client.captureException(new Error('test exception'));
Expand All@@ -706,7 +706,7 @@ describe('BaseClient', () => {
integrations: [new TestIntegration(), null, undefined],
});
const client = new TestClient(options);
client.setupIntegrations();
client.init();

client.captureEvent({ message: 'message' });

Expand DownExpand Up@@ -1482,24 +1482,48 @@ describe('BaseClient', () => {

const options = getDefaultTestClientOptions({ dsn: PUBLIC_DSN, integrations: [new TestIntegration()] });
const client = new TestClient(options);
// eslint-disable-next-line deprecation/deprecation
client.setupIntegrations();

expect(Object.keys((client as any)._integrations).length).toEqual(1);
expect(client.getIntegration(TestIntegration)).toBeTruthy();
});

test('skips installation if DSN is not provided', () => {
test('sets up each integration on `init` call', () => {
expect.assertions(2);

const options = getDefaultTestClientOptions({ dsn: PUBLIC_DSN, integrations: [new TestIntegration()] });
const client = new TestClient(options);
client.init();

expect(Object.keys((client as any)._integrations).length).toEqual(1);
expect(client.getIntegration(TestIntegration)).toBeTruthy();
});

test('skips installation for `setupIntegrations()` if DSN is not provided', () => {
expect.assertions(2);

const options = getDefaultTestClientOptions({ integrations: [new TestIntegration()] });
const client = new TestClient(options);
// eslint-disable-next-line deprecation/deprecation
client.setupIntegrations();

expect(Object.keys((client as any)._integrations).length).toEqual(0);
expect(client.getIntegration(TestIntegration)).toBeFalsy();
});

test('skips installation if `enabled` is set to `false`', () => {
test('skips installation for `init()` if DSN is not provided', () => {
expect.assertions(2);

const options = getDefaultTestClientOptions({ integrations: [new TestIntegration()] });
const client = new TestClient(options);
client.init();

expect(Object.keys((client as any)._integrations).length).toEqual(0);
expect(client.getIntegration(TestIntegration)).toBeFalsy();
});

test('skips installation for `setupIntegrations()` if `enabled` is set to `false`', () => {
expect.assertions(2);

const options = getDefaultTestClientOptions({
Expand All@@ -1508,12 +1532,28 @@ describe('BaseClient', () => {
integrations: [new TestIntegration()],
});
const client = new TestClient(options);
// eslint-disable-next-line deprecation/deprecation
client.setupIntegrations();

expect(Object.keys((client as any)._integrations).length).toEqual(0);
expect(client.getIntegration(TestIntegration)).toBeFalsy();
});

test('skips installation for `init()` if `enabled` is set to `false`', () => {
expect.assertions(2);

const options = getDefaultTestClientOptions({
dsn: PUBLIC_DSN,
enabled: false,
integrations: [new TestIntegration()],
});
const client = new TestClient(options);
client.init();

expect(Object.keys((client as any)._integrations).length).toEqual(0);
expect(client.getIntegration(TestIntegration)).toBeFalsy();
});

test('skips installation if integrations are already installed', () => {
expect.assertions(4);

Expand All@@ -1523,17 +1563,41 @@ describe('BaseClient', () => {
const setupIntegrationsHelper = jest.spyOn(integrationModule, 'setupIntegrations');

// it should install the first time, because integrations aren't yet installed...
// eslint-disable-next-line deprecation/deprecation
client.setupIntegrations();

expect(Object.keys((client as any)._integrations).length).toEqual(1);
expect(client.getIntegration(TestIntegration)).toBeTruthy();
expect(setupIntegrationsHelper).toHaveBeenCalledTimes(1);

// ...but it shouldn't try to install a second time
// eslint-disable-next-line deprecation/deprecation
client.setupIntegrations();

expect(setupIntegrationsHelper).toHaveBeenCalledTimes(1);
});

test('does not add integrations twice when calling `init` multiple times', () => {
const options = getDefaultTestClientOptions({ dsn: PUBLIC_DSN, integrations: [new TestIntegration()] });
const client = new TestClient(options);
// note: not the `Client` method `setupIntegrations`, but the free-standing function which that method calls
const setupIntegrationsHelper = jest.spyOn(integrationModule, 'setupIntegrations');

// it should install the first time, because integrations aren't yet installed...
client.init();

expect(Object.keys((client as any)._integrations).length).toEqual(1);
expect(client.getIntegration(TestIntegration)).toBeTruthy();
expect(setupIntegrationsHelper).toHaveBeenCalledTimes(1);

client.init();

// is called again...
expect(setupIntegrationsHelper).toHaveBeenCalledTimes(2);

// but integrations are only added once anyhow!
expect(client['_integrations']).toEqual({ TestIntegration: expect.any(TestIntegration) });
});
});

describe('flush/close', () => {
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -37,7 +37,7 @@ function createInboundFiltersEventProcessor(
}),
);

client.setupIntegrations();
client.init();

const eventProcessors = client['_eventProcessors'];
const eventProcessor = eventProcessors.find(processor => processor.id === 'InboundFilters');
Expand Down
16 changes: 13 additions & 3 deletions packages/node-experimental/src/sdk/init.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -6,7 +6,7 @@ import {
getSentryRelease,
makeNodeTransport,
} from '@sentry/node';
import type { Integration } from '@sentry/types';
import type { Client, Integration } from '@sentry/types';
import {
consoleSandbox,
dropUndefinedKeys,
Expand DownExpand Up@@ -67,7 +67,9 @@ export function init(options: NodeExperimentalOptions | undefined = {}): void {
// unless somebody specifically sets a different one on a scope/isolations cope
getGlobalScope().setClient(client);

client.setupIntegrations();
if (isEnabled(client)) {
client.init();
}

if (options.autoSessionTracking) {
startSessionTracking();
Expand All@@ -79,7 +81,11 @@ export function init(options: NodeExperimentalOptions | undefined = {}): void {
const client = getClient();
if (client.addIntegration) {
// force integrations to be setup even if no DSN was set
client.setupIntegrations(true);
// If they have already been added before, they will be ignored anyhow
const integrations = client.getOptions().integrations;
for (const integration of integrations) {
client.addIntegration(integration);
}
client.addIntegration(
new Integrations.Spotlight({
sidecarUrl: typeof options.spotlight === 'string' ? options.spotlight : undefined,
Expand DownExpand Up@@ -213,3 +219,7 @@ function startSessionTracking(): void {
}
});
}

function isEnabled(client: Client): boolean {
return client.getOptions().enabled !== false && client.getTransport() !== undefined;
}
6 changes: 5 additions & 1 deletion packages/node/src/sdk.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -183,7 +183,11 @@ export function init(options: NodeOptions = {}): void {
const client = getClient();
if (client && client.addIntegration) {
// force integrations to be setup even if no DSN was set
client.setupIntegrations(true);
// If they have already been added before, they will be ignored anyhow
const integrations = client.getOptions().integrations;
for (const integration of integrations) {
client.addIntegration(integration);
}
client.addIntegration(
new Spotlight({ sidecarUrl: typeof options.spotlight === 'string' ? options.spotlight : undefined }),
);
Expand Down
24 changes: 12 additions & 12 deletions packages/node/test/integrations/localvariables.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -162,11 +162,11 @@ describeIf(NODE_VERSION.major >= 18)('LocalVariables', () => {
const options = getDefaultNodeClientOptions({
stackParser: defaultStackParser,
includeLocalVariables: true,
integrations: [localVariables],
integrations: [],
});

const client = new NodeClient(options);
client.setupIntegrations(true);
client.addIntegration(localVariables);

const eventProcessors = client['_eventProcessors'];
const eventProcessor = eventProcessors.find(processor => processor.id === 'LocalVariables');
Expand DownExpand Up@@ -253,11 +253,11 @@ describeIf(NODE_VERSION.major >= 18)('LocalVariables', () => {
const options = getDefaultNodeClientOptions({
stackParser: defaultStackParser,
includeLocalVariables: true,
integrations: [localVariables],
integrations: [],
});

const client = new NodeClient(options);
client.setupIntegrations(true);
client.addIntegration(localVariables);

await session.runPause(exceptionEvent100Frames);

Expand All@@ -278,11 +278,11 @@ describeIf(NODE_VERSION.major >= 18)('LocalVariables', () => {
const options = getDefaultNodeClientOptions({
stackParser: defaultStackParser,
includeLocalVariables: true,
integrations: [localVariables],
integrations: [],
});

const client = new NodeClient(options);
client.setupIntegrations(true);
client.addIntegration(localVariables);

const nonExceptionEvent = {
method: exceptionEvent.method,
Expand All@@ -299,11 +299,11 @@ describeIf(NODE_VERSION.major >= 18)('LocalVariables', () => {
const localVariables = new LocalVariablesSync({}, session);
const options = getDefaultNodeClientOptions({
stackParser: defaultStackParser,
integrations: [localVariables],
integrations: [],
});

const client = new NodeClient(options);
client.setupIntegrations(true);
client.addIntegration(localVariables);

const eventProcessors = client['_eventProcessors'];
const eventProcessor = eventProcessors.find(processor => processor.id === 'LocalVariables');
Expand All@@ -315,11 +315,11 @@ describeIf(NODE_VERSION.major >= 18)('LocalVariables', () => {
const localVariables = new LocalVariablesSync({}, undefined);
const options = getDefaultNodeClientOptions({
stackParser: defaultStackParser,
integrations: [localVariables],
integrations: [],
});

const client = new NodeClient(options);
client.setupIntegrations(true);
client.addIntegration(localVariables);

const eventProcessors = client['_eventProcessors'];
const eventProcessor = eventProcessors.find(processor => processor.id === 'LocalVariables');
Expand All@@ -336,11 +336,11 @@ describeIf(NODE_VERSION.major >= 18)('LocalVariables', () => {
const options = getDefaultNodeClientOptions({
stackParser: defaultStackParser,
includeLocalVariables: true,
integrations: [localVariables],
integrations: [],
});

const client = new NodeClient(options);
client.setupIntegrations(true);
client.addIntegration(localVariables);

await session.runPause(exceptionEvent);
await session.runPause(exceptionEvent);
Expand Down
11 changes: 10 additions & 1 deletion packages/types/src/client.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -151,9 +151,18 @@ export interface Client<O extends ClientOptions = ClientOptions> {
* */
addIntegration?(integration: Integration): void;

/** This is an internal function to setup all integrations that should run on the client */
/**
* This is an internal function to setup all integrations that should run on the client.
* @deprecated Use `client.init()` instead.
*/
setupIntegrations(forceInitialize?: boolean): void;

/**
* Initialize this client.
* Call this after the client was set on a scope.
*/
init?(): void;

/** Creates an {@link Event} from all inputs to `captureException` and non-primitive inputs to `captureMessage`. */
// eslint-disable-next-line @typescript-eslint/no-explicit-any
eventFromException(exception: any, hint?: EventHint): PromiseLike<Event>;
Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions MIGRATION.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -8,6 +8,10 @@ npx @sentry/migr8@latest

This will let you select which updates to run, and automatically update your code. Make sure to still review all code changes!

## Deprecate `client.setupIntegrations()`

Instead, use the new `client.init()` method. You should probably not use this directly and instead use `Sentry.init()`, which calls this under the hood. But if you have a special use case that requires that, you can call `client.init()` instead now.

## Deprecate `scope.getSpan()` and `scope.setSpan()`

Instead, you can get the currently active span via `Sentry.getActiveSpan()`.
Expand Down
2 changes: 1 addition & 1 deletion packages/browser/test/unit/sdk.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -42,7 +42,7 @@ jest.mock('@sentry/core', () => {
return new Scope();
},
bindClient(client: Client): boolean {
client.setupIntegrations();
client.init!();
return true;
},
};
Expand Down
20 changes: 17 additions & 3 deletions packages/core/src/baseclient.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -314,12 +314,19 @@ export abstract class BaseClient<O extends ClientOptions> implements Client<O> {
}

/**
* Sets up the integrations
* This is an internal function to setup all integrations that should run on the client.
* @deprecated Use `client.init()` instead.
*/
public setupIntegrations(forceInitialize?: boolean): void {
if ((forceInitialize && !this._integrationsInitialized) || (this._isEnabled() && !this._integrationsInitialized)) {
this._integrations = setupIntegrations(this, this._options.integrations);
this._integrationsInitialized = true;
this._setupIntegrations();
}
}

/** @inheritdoc */
public init(): void {
if (this._isEnabled()) {
this._setupIntegrations();
}
}

Expand DownExpand Up@@ -512,6 +519,13 @@ export abstract class BaseClient<O extends ClientOptions> implements Client<O> {

/* eslint-enable @typescript-eslint/unified-signatures */

/** Setup integrations for this client. */
protected _setupIntegrations(): void {
this._integrations = setupIntegrations(this, this._options.integrations);
// TODO v8: We don't need this flag anymore
this._integrationsInitialized = true;
}

/** Updates existing session based on the provided event */
protected _updateSessionFromEvent(session: Session, event: Event): void {
let crashed = false;
Expand Down
2 changes: 2 additions & 0 deletions packages/core/src/hub.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -167,7 +167,9 @@ export class Hub implements HubInterface {
const top = this.getStackTop();
top.client = client;
top.scope.setClient(client);
// eslint-disable-next-line deprecation/deprecation
if (client && client.setupIntegrations) {
// eslint-disable-next-line deprecation/deprecation
client.setupIntegrations();
}
}
Expand Down
74 changes: 69 additions & 5 deletions packages/core/test/lib/base.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -671,7 +671,7 @@ describe('BaseClient', () => {
test('adds installed integrations to sdk info', () => {
const options = getDefaultTestClientOptions({ dsn: PUBLIC_DSN, integrations: [new TestIntegration()] });
const client = new TestClient(options);
client.setupIntegrations();
client.init();

client.captureEvent({ message: 'message' });

Expand All@@ -685,7 +685,7 @@ describe('BaseClient', () => {

const options = getDefaultTestClientOptions({ dsn: PUBLIC_DSN, integrations: [new TestIntegration()] });
const client = new TestClient(options);
client.setupIntegrations();
client.init();
client.addIntegration(new AdHocIntegration());

client.captureException(new Error('test exception'));
Expand All@@ -706,7 +706,7 @@ describe('BaseClient', () => {
integrations: [new TestIntegration(), null, undefined],
});
const client = new TestClient(options);
client.setupIntegrations();
client.init();

client.captureEvent({ message: 'message' });

Expand DownExpand Up@@ -1482,24 +1482,48 @@ describe('BaseClient', () => {

const options = getDefaultTestClientOptions({ dsn: PUBLIC_DSN, integrations: [new TestIntegration()] });
const client = new TestClient(options);
// eslint-disable-next-line deprecation/deprecation
client.setupIntegrations();

expect(Object.keys((client as any)._integrations).length).toEqual(1);
expect(client.getIntegration(TestIntegration)).toBeTruthy();
});

test('skips installation if DSN is not provided', () => {
test('sets up each integration on `init` call', () => {
expect.assertions(2);

const options = getDefaultTestClientOptions({ dsn: PUBLIC_DSN, integrations: [new TestIntegration()] });
const client = new TestClient(options);
client.init();

expect(Object.keys((client as any)._integrations).length).toEqual(1);
expect(client.getIntegration(TestIntegration)).toBeTruthy();
});

test('skips installation for `setupIntegrations()` if DSN is not provided', () => {
expect.assertions(2);

const options = getDefaultTestClientOptions({ integrations: [new TestIntegration()] });
const client = new TestClient(options);
// eslint-disable-next-line deprecation/deprecation
client.setupIntegrations();

expect(Object.keys((client as any)._integrations).length).toEqual(0);
expect(client.getIntegration(TestIntegration)).toBeFalsy();
});

test('skips installation if `enabled` is set to `false`', () => {
test('skips installation for `init()` if DSN is not provided', () => {
expect.assertions(2);

const options = getDefaultTestClientOptions({ integrations: [new TestIntegration()] });
const client = new TestClient(options);
client.init();

expect(Object.keys((client as any)._integrations).length).toEqual(0);
expect(client.getIntegration(TestIntegration)).toBeFalsy();
});

test('skips installation for `setupIntegrations()` if `enabled` is set to `false`', () => {
expect.assertions(2);

const options = getDefaultTestClientOptions({
Expand All@@ -1508,12 +1532,28 @@ describe('BaseClient', () => {
integrations: [new TestIntegration()],
});
const client = new TestClient(options);
// eslint-disable-next-line deprecation/deprecation
client.setupIntegrations();

expect(Object.keys((client as any)._integrations).length).toEqual(0);
expect(client.getIntegration(TestIntegration)).toBeFalsy();
});

test('skips installation for `init()` if `enabled` is set to `false`', () => {
expect.assertions(2);

const options = getDefaultTestClientOptions({
dsn: PUBLIC_DSN,
enabled: false,
integrations: [new TestIntegration()],
});
const client = new TestClient(options);
client.init();

expect(Object.keys((client as any)._integrations).length).toEqual(0);
expect(client.getIntegration(TestIntegration)).toBeFalsy();
});

test('skips installation if integrations are already installed', () => {
expect.assertions(4);

Expand All@@ -1523,17 +1563,41 @@ describe('BaseClient', () => {
const setupIntegrationsHelper = jest.spyOn(integrationModule, 'setupIntegrations');

// it should install the first time, because integrations aren't yet installed...
// eslint-disable-next-line deprecation/deprecation
client.setupIntegrations();

expect(Object.keys((client as any)._integrations).length).toEqual(1);
expect(client.getIntegration(TestIntegration)).toBeTruthy();
expect(setupIntegrationsHelper).toHaveBeenCalledTimes(1);

// ...but it shouldn't try to install a second time
// eslint-disable-next-line deprecation/deprecation
client.setupIntegrations();

expect(setupIntegrationsHelper).toHaveBeenCalledTimes(1);
});

test('does not add integrations twice when calling `init` multiple times', () => {
const options = getDefaultTestClientOptions({ dsn: PUBLIC_DSN, integrations: [new TestIntegration()] });
const client = new TestClient(options);
// note: not the `Client` method `setupIntegrations`, but the free-standing function which that method calls
const setupIntegrationsHelper = jest.spyOn(integrationModule, 'setupIntegrations');

// it should install the first time, because integrations aren't yet installed...
client.init();

expect(Object.keys((client as any)._integrations).length).toEqual(1);
expect(client.getIntegration(TestIntegration)).toBeTruthy();
expect(setupIntegrationsHelper).toHaveBeenCalledTimes(1);

client.init();

// is called again...
expect(setupIntegrationsHelper).toHaveBeenCalledTimes(2);

// but integrations are only added once anyhow!
expect(client['_integrations']).toEqual({ TestIntegration: expect.any(TestIntegration) });
});
});

describe('flush/close', () => {
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -37,7 +37,7 @@ function createInboundFiltersEventProcessor(
}),
);

client.setupIntegrations();
client.init();

const eventProcessors = client['_eventProcessors'];
const eventProcessor = eventProcessors.find(processor => processor.id === 'InboundFilters');
Expand Down
16 changes: 13 additions & 3 deletions packages/node-experimental/src/sdk/init.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -6,7 +6,7 @@ import {
getSentryRelease,
makeNodeTransport,
} from '@sentry/node';
import type { Integration } from '@sentry/types';
import type { Client, Integration } from '@sentry/types';
import {
consoleSandbox,
dropUndefinedKeys,
Expand DownExpand Up@@ -67,7 +67,9 @@ export function init(options: NodeExperimentalOptions | undefined = {}): void {
// unless somebody specifically sets a different one on a scope/isolations cope
getGlobalScope().setClient(client);

client.setupIntegrations();
if (isEnabled(client)) {
client.init();
}

if (options.autoSessionTracking) {
startSessionTracking();
Expand All@@ -79,7 +81,11 @@ export function init(options: NodeExperimentalOptions | undefined = {}): void {
const client = getClient();
if (client.addIntegration) {
// force integrations to be setup even if no DSN was set
client.setupIntegrations(true);
// If they have already been added before, they will be ignored anyhow
const integrations = client.getOptions().integrations;
for (const integration of integrations) {
client.addIntegration(integration);
}
client.addIntegration(
new Integrations.Spotlight({
sidecarUrl: typeof options.spotlight === 'string' ? options.spotlight : undefined,
Expand DownExpand Up@@ -213,3 +219,7 @@ function startSessionTracking(): void {
}
});
}

function isEnabled(client: Client): boolean {
return client.getOptions().enabled !== false && client.getTransport() !== undefined;
}
6 changes: 5 additions & 1 deletion packages/node/src/sdk.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -183,7 +183,11 @@ export function init(options: NodeOptions = {}): void {
const client = getClient();
if (client && client.addIntegration) {
// force integrations to be setup even if no DSN was set
client.setupIntegrations(true);
// If they have already been added before, they will be ignored anyhow
const integrations = client.getOptions().integrations;
for (const integration of integrations) {
client.addIntegration(integration);
}
client.addIntegration(
new Spotlight({ sidecarUrl: typeof options.spotlight === 'string' ? options.spotlight : undefined }),
);
Expand Down
24 changes: 12 additions & 12 deletions packages/node/test/integrations/localvariables.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -162,11 +162,11 @@ describeIf(NODE_VERSION.major >= 18)('LocalVariables', () => {
const options = getDefaultNodeClientOptions({
stackParser: defaultStackParser,
includeLocalVariables: true,
integrations: [localVariables],
integrations: [],
});

const client = new NodeClient(options);
client.setupIntegrations(true);
client.addIntegration(localVariables);

const eventProcessors = client['_eventProcessors'];
const eventProcessor = eventProcessors.find(processor => processor.id === 'LocalVariables');
Expand DownExpand Up@@ -253,11 +253,11 @@ describeIf(NODE_VERSION.major >= 18)('LocalVariables', () => {
const options = getDefaultNodeClientOptions({
stackParser: defaultStackParser,
includeLocalVariables: true,
integrations: [localVariables],
integrations: [],
});

const client = new NodeClient(options);
client.setupIntegrations(true);
client.addIntegration(localVariables);

await session.runPause(exceptionEvent100Frames);

Expand All@@ -278,11 +278,11 @@ describeIf(NODE_VERSION.major >= 18)('LocalVariables', () => {
const options = getDefaultNodeClientOptions({
stackParser: defaultStackParser,
includeLocalVariables: true,
integrations: [localVariables],
integrations: [],
});

const client = new NodeClient(options);
client.setupIntegrations(true);
client.addIntegration(localVariables);

const nonExceptionEvent = {
method: exceptionEvent.method,
Expand All@@ -299,11 +299,11 @@ describeIf(NODE_VERSION.major >= 18)('LocalVariables', () => {
const localVariables = new LocalVariablesSync({}, session);
const options = getDefaultNodeClientOptions({
stackParser: defaultStackParser,
integrations: [localVariables],
integrations: [],
});

const client = new NodeClient(options);
client.setupIntegrations(true);
client.addIntegration(localVariables);

const eventProcessors = client['_eventProcessors'];
const eventProcessor = eventProcessors.find(processor => processor.id === 'LocalVariables');
Expand All@@ -315,11 +315,11 @@ describeIf(NODE_VERSION.major >= 18)('LocalVariables', () => {
const localVariables = new LocalVariablesSync({}, undefined);
const options = getDefaultNodeClientOptions({
stackParser: defaultStackParser,
integrations: [localVariables],
integrations: [],
});

const client = new NodeClient(options);
client.setupIntegrations(true);
client.addIntegration(localVariables);

const eventProcessors = client['_eventProcessors'];
const eventProcessor = eventProcessors.find(processor => processor.id === 'LocalVariables');
Expand All@@ -336,11 +336,11 @@ describeIf(NODE_VERSION.major >= 18)('LocalVariables', () => {
const options = getDefaultNodeClientOptions({
stackParser: defaultStackParser,
includeLocalVariables: true,
integrations: [localVariables],
integrations: [],
});

const client = new NodeClient(options);
client.setupIntegrations(true);
client.addIntegration(localVariables);

await session.runPause(exceptionEvent);
await session.runPause(exceptionEvent);
Expand Down
11 changes: 10 additions & 1 deletion packages/types/src/client.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -151,9 +151,18 @@ export interface Client<O extends ClientOptions = ClientOptions> {
* */
addIntegration?(integration: Integration): void;

/** This is an internal function to setup all integrations that should run on the client */
/**
* This is an internal function to setup all integrations that should run on the client.
* @deprecated Use `client.init()` instead.
*/
setupIntegrations(forceInitialize?: boolean): void;

/**
* Initialize this client.
* Call this after the client was set on a scope.
*/
init?(): void;

/** Creates an {@link Event} from all inputs to `captureException` and non-primitive inputs to `captureMessage`. */
// eslint-disable-next-line @typescript-eslint/no-explicit-any
eventFromException(exception: any, hint?: EventHint): PromiseLike<Event>;
Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions MIGRATION.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -8,6 +8,10 @@ npx @sentry/migr8@latest

This will let you select which updates to run, and automatically update your code. Make sure to still review all code changes!

## Deprecate `client.setupIntegrations()`

Instead, use the new `client.init()` method. You should probably not use this directly and instead use `Sentry.init()`, which calls this under the hood. But if you have a special use case that requires that, you can call `client.init()` instead now.

## Deprecate `scope.getSpan()` and `scope.setSpan()`

Instead, you can get the currently active span via `Sentry.getActiveSpan()`.
Expand Down
2 changes: 1 addition & 1 deletion packages/browser/test/unit/sdk.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -42,7 +42,7 @@ jest.mock('@sentry/core', () => {
return new Scope();
},
bindClient(client: Client): boolean {
client.setupIntegrations();
client.init!();
return true;
},
};
Expand Down
20 changes: 17 additions & 3 deletions packages/core/src/baseclient.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -314,12 +314,19 @@ export abstract class BaseClient<O extends ClientOptions> implements Client<O> {
}

/**
* Sets up the integrations
* This is an internal function to setup all integrations that should run on the client.
* @deprecated Use `client.init()` instead.
*/
public setupIntegrations(forceInitialize?: boolean): void {
if ((forceInitialize && !this._integrationsInitialized) || (this._isEnabled() && !this._integrationsInitialized)) {
this._integrations = setupIntegrations(this, this._options.integrations);
this._integrationsInitialized = true;
this._setupIntegrations();
}
}

/** @inheritdoc */
public init(): void {
if (this._isEnabled()) {
this._setupIntegrations();
}
}

Expand DownExpand Up@@ -512,6 +519,13 @@ export abstract class BaseClient<O extends ClientOptions> implements Client<O> {

/* eslint-enable @typescript-eslint/unified-signatures */

/** Setup integrations for this client. */
protected _setupIntegrations(): void {
this._integrations = setupIntegrations(this, this._options.integrations);
// TODO v8: We don't need this flag anymore
this._integrationsInitialized = true;
}

/** Updates existing session based on the provided event */
protected _updateSessionFromEvent(session: Session, event: Event): void {
let crashed = false;
Expand Down
2 changes: 2 additions & 0 deletions packages/core/src/hub.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -167,7 +167,9 @@ export class Hub implements HubInterface {
const top = this.getStackTop();
top.client = client;
top.scope.setClient(client);
// eslint-disable-next-line deprecation/deprecation
if (client && client.setupIntegrations) {
// eslint-disable-next-line deprecation/deprecation
client.setupIntegrations();
}
}
Expand Down
74 changes: 69 additions & 5 deletions packages/core/test/lib/base.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -671,7 +671,7 @@ describe('BaseClient', () => {
test('adds installed integrations to sdk info', () => {
const options = getDefaultTestClientOptions({ dsn: PUBLIC_DSN, integrations: [new TestIntegration()] });
const client = new TestClient(options);
client.setupIntegrations();
client.init();

client.captureEvent({ message: 'message' });

Expand All@@ -685,7 +685,7 @@ describe('BaseClient', () => {

const options = getDefaultTestClientOptions({ dsn: PUBLIC_DSN, integrations: [new TestIntegration()] });
const client = new TestClient(options);
client.setupIntegrations();
client.init();
client.addIntegration(new AdHocIntegration());

client.captureException(new Error('test exception'));
Expand All@@ -706,7 +706,7 @@ describe('BaseClient', () => {
integrations: [new TestIntegration(), null, undefined],
});
const client = new TestClient(options);
client.setupIntegrations();
client.init();

client.captureEvent({ message: 'message' });

Expand DownExpand Up@@ -1482,24 +1482,48 @@ describe('BaseClient', () => {

const options = getDefaultTestClientOptions({ dsn: PUBLIC_DSN, integrations: [new TestIntegration()] });
const client = new TestClient(options);
// eslint-disable-next-line deprecation/deprecation
client.setupIntegrations();

expect(Object.keys((client as any)._integrations).length).toEqual(1);
expect(client.getIntegration(TestIntegration)).toBeTruthy();
});

test('skips installation if DSN is not provided', () => {
test('sets up each integration on `init` call', () => {
expect.assertions(2);

const options = getDefaultTestClientOptions({ dsn: PUBLIC_DSN, integrations: [new TestIntegration()] });
const client = new TestClient(options);
client.init();

expect(Object.keys((client as any)._integrations).length).toEqual(1);
expect(client.getIntegration(TestIntegration)).toBeTruthy();
});

test('skips installation for `setupIntegrations()` if DSN is not provided', () => {
expect.assertions(2);

const options = getDefaultTestClientOptions({ integrations: [new TestIntegration()] });
const client = new TestClient(options);
// eslint-disable-next-line deprecation/deprecation
client.setupIntegrations();

expect(Object.keys((client as any)._integrations).length).toEqual(0);
expect(client.getIntegration(TestIntegration)).toBeFalsy();
});

test('skips installation if `enabled` is set to `false`', () => {
test('skips installation for `init()` if DSN is not provided', () => {
expect.assertions(2);

const options = getDefaultTestClientOptions({ integrations: [new TestIntegration()] });
const client = new TestClient(options);
client.init();

expect(Object.keys((client as any)._integrations).length).toEqual(0);
expect(client.getIntegration(TestIntegration)).toBeFalsy();
});

test('skips installation for `setupIntegrations()` if `enabled` is set to `false`', () => {
expect.assertions(2);

const options = getDefaultTestClientOptions({
Expand All@@ -1508,12 +1532,28 @@ describe('BaseClient', () => {
integrations: [new TestIntegration()],
});
const client = new TestClient(options);
// eslint-disable-next-line deprecation/deprecation
client.setupIntegrations();

expect(Object.keys((client as any)._integrations).length).toEqual(0);
expect(client.getIntegration(TestIntegration)).toBeFalsy();
});

test('skips installation for `init()` if `enabled` is set to `false`', () => {
expect.assertions(2);

const options = getDefaultTestClientOptions({
dsn: PUBLIC_DSN,
enabled: false,
integrations: [new TestIntegration()],
});
const client = new TestClient(options);
client.init();

expect(Object.keys((client as any)._integrations).length).toEqual(0);
expect(client.getIntegration(TestIntegration)).toBeFalsy();
});

test('skips installation if integrations are already installed', () => {
expect.assertions(4);

Expand All@@ -1523,17 +1563,41 @@ describe('BaseClient', () => {
const setupIntegrationsHelper = jest.spyOn(integrationModule, 'setupIntegrations');

// it should install the first time, because integrations aren't yet installed...
// eslint-disable-next-line deprecation/deprecation
client.setupIntegrations();

expect(Object.keys((client as any)._integrations).length).toEqual(1);
expect(client.getIntegration(TestIntegration)).toBeTruthy();
expect(setupIntegrationsHelper).toHaveBeenCalledTimes(1);

// ...but it shouldn't try to install a second time
// eslint-disable-next-line deprecation/deprecation
client.setupIntegrations();

expect(setupIntegrationsHelper).toHaveBeenCalledTimes(1);
});

test('does not add integrations twice when calling `init` multiple times', () => {
const options = getDefaultTestClientOptions({ dsn: PUBLIC_DSN, integrations: [new TestIntegration()] });
const client = new TestClient(options);
// note: not the `Client` method `setupIntegrations`, but the free-standing function which that method calls
const setupIntegrationsHelper = jest.spyOn(integrationModule, 'setupIntegrations');

// it should install the first time, because integrations aren't yet installed...
client.init();

expect(Object.keys((client as any)._integrations).length).toEqual(1);
expect(client.getIntegration(TestIntegration)).toBeTruthy();
expect(setupIntegrationsHelper).toHaveBeenCalledTimes(1);

client.init();

// is called again...
expect(setupIntegrationsHelper).toHaveBeenCalledTimes(2);

// but integrations are only added once anyhow!
expect(client['_integrations']).toEqual({ TestIntegration: expect.any(TestIntegration) });
});
});

describe('flush/close', () => {
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -37,7 +37,7 @@ function createInboundFiltersEventProcessor(
}),
);

client.setupIntegrations();
client.init();

const eventProcessors = client['_eventProcessors'];
const eventProcessor = eventProcessors.find(processor => processor.id === 'InboundFilters');
Expand Down
16 changes: 13 additions & 3 deletions packages/node-experimental/src/sdk/init.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -6,7 +6,7 @@ import {
getSentryRelease,
makeNodeTransport,
} from '@sentry/node';
import type { Integration } from '@sentry/types';
import type { Client, Integration } from '@sentry/types';
import {
consoleSandbox,
dropUndefinedKeys,
Expand DownExpand Up@@ -67,7 +67,9 @@ export function init(options: NodeExperimentalOptions | undefined = {}): void {
// unless somebody specifically sets a different one on a scope/isolations cope
getGlobalScope().setClient(client);

client.setupIntegrations();
if (isEnabled(client)) {
client.init();
}

if (options.autoSessionTracking) {
startSessionTracking();
Expand All@@ -79,7 +81,11 @@ export function init(options: NodeExperimentalOptions | undefined = {}): void {
const client = getClient();
if (client.addIntegration) {
// force integrations to be setup even if no DSN was set
client.setupIntegrations(true);
// If they have already been added before, they will be ignored anyhow
const integrations = client.getOptions().integrations;
for (const integration of integrations) {
client.addIntegration(integration);
}
client.addIntegration(
new Integrations.Spotlight({
sidecarUrl: typeof options.spotlight === 'string' ? options.spotlight : undefined,
Expand DownExpand Up@@ -213,3 +219,7 @@ function startSessionTracking(): void {
}
});
}

function isEnabled(client: Client): boolean {
return client.getOptions().enabled !== false && client.getTransport() !== undefined;
}
6 changes: 5 additions & 1 deletion packages/node/src/sdk.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -183,7 +183,11 @@ export function init(options: NodeOptions = {}): void {
const client = getClient();
if (client && client.addIntegration) {
// force integrations to be setup even if no DSN was set
client.setupIntegrations(true);
// If they have already been added before, they will be ignored anyhow
const integrations = client.getOptions().integrations;
for (const integration of integrations) {
client.addIntegration(integration);
}
client.addIntegration(
new Spotlight({ sidecarUrl: typeof options.spotlight === 'string' ? options.spotlight : undefined }),
);
Expand Down
24 changes: 12 additions & 12 deletions packages/node/test/integrations/localvariables.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -162,11 +162,11 @@ describeIf(NODE_VERSION.major >= 18)('LocalVariables', () => {
const options = getDefaultNodeClientOptions({
stackParser: defaultStackParser,
includeLocalVariables: true,
integrations: [localVariables],
integrations: [],
});

const client = new NodeClient(options);
client.setupIntegrations(true);
client.addIntegration(localVariables);

const eventProcessors = client['_eventProcessors'];
const eventProcessor = eventProcessors.find(processor => processor.id === 'LocalVariables');
Expand DownExpand Up@@ -253,11 +253,11 @@ describeIf(NODE_VERSION.major >= 18)('LocalVariables', () => {
const options = getDefaultNodeClientOptions({
stackParser: defaultStackParser,
includeLocalVariables: true,
integrations: [localVariables],
integrations: [],
});

const client = new NodeClient(options);
client.setupIntegrations(true);
client.addIntegration(localVariables);

await session.runPause(exceptionEvent100Frames);

Expand All@@ -278,11 +278,11 @@ describeIf(NODE_VERSION.major >= 18)('LocalVariables', () => {
const options = getDefaultNodeClientOptions({
stackParser: defaultStackParser,
includeLocalVariables: true,
integrations: [localVariables],
integrations: [],
});

const client = new NodeClient(options);
client.setupIntegrations(true);
client.addIntegration(localVariables);

const nonExceptionEvent = {
method: exceptionEvent.method,
Expand All@@ -299,11 +299,11 @@ describeIf(NODE_VERSION.major >= 18)('LocalVariables', () => {
const localVariables = new LocalVariablesSync({}, session);
const options = getDefaultNodeClientOptions({
stackParser: defaultStackParser,
integrations: [localVariables],
integrations: [],
});

const client = new NodeClient(options);
client.setupIntegrations(true);
client.addIntegration(localVariables);

const eventProcessors = client['_eventProcessors'];
const eventProcessor = eventProcessors.find(processor => processor.id === 'LocalVariables');
Expand All@@ -315,11 +315,11 @@ describeIf(NODE_VERSION.major >= 18)('LocalVariables', () => {
const localVariables = new LocalVariablesSync({}, undefined);
const options = getDefaultNodeClientOptions({
stackParser: defaultStackParser,
integrations: [localVariables],
integrations: [],
});

const client = new NodeClient(options);
client.setupIntegrations(true);
client.addIntegration(localVariables);

const eventProcessors = client['_eventProcessors'];
const eventProcessor = eventProcessors.find(processor => processor.id === 'LocalVariables');
Expand All@@ -336,11 +336,11 @@ describeIf(NODE_VERSION.major >= 18)('LocalVariables', () => {
const options = getDefaultNodeClientOptions({
stackParser: defaultStackParser,
includeLocalVariables: true,
integrations: [localVariables],
integrations: [],
});

const client = new NodeClient(options);
client.setupIntegrations(true);
client.addIntegration(localVariables);

await session.runPause(exceptionEvent);
await session.runPause(exceptionEvent);
Expand Down
11 changes: 10 additions & 1 deletion packages/types/src/client.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -151,9 +151,18 @@ export interface Client<O extends ClientOptions = ClientOptions> {
* */
addIntegration?(integration: Integration): void;

/** This is an internal function to setup all integrations that should run on the client */
/**
* This is an internal function to setup all integrations that should run on the client.
* @deprecated Use `client.init()` instead.
*/
setupIntegrations(forceInitialize?: boolean): void;

/**
* Initialize this client.
* Call this after the client was set on a scope.
*/
init?(): void;

/** Creates an {@link Event} from all inputs to `captureException` and non-primitive inputs to `captureMessage`. */
// eslint-disable-next-line @typescript-eslint/no-explicit-any
eventFromException(exception: any, hint?: EventHint): PromiseLike<Event>;
Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions MIGRATION.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -8,6 +8,10 @@ npx @sentry/migr8@latest

This will let you select which updates to run, and automatically update your code. Make sure to still review all code changes!

## Deprecate `client.setupIntegrations()`

Instead, use the new `client.init()` method. You should probably not use this directly and instead use `Sentry.init()`, which calls this under the hood. But if you have a special use case that requires that, you can call `client.init()` instead now.

## Deprecate `scope.getSpan()` and `scope.setSpan()`

Instead, you can get the currently active span via `Sentry.getActiveSpan()`.
Expand Down
2 changes: 1 addition & 1 deletion packages/browser/test/unit/sdk.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -42,7 +42,7 @@ jest.mock('@sentry/core', () => {
return new Scope();
},
bindClient(client: Client): boolean {
client.setupIntegrations();
client.init!();
return true;
},
};
Expand Down
20 changes: 17 additions & 3 deletions packages/core/src/baseclient.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -314,12 +314,19 @@ export abstract class BaseClient<O extends ClientOptions> implements Client<O> {
}

/**
* Sets up the integrations
* This is an internal function to setup all integrations that should run on the client.
* @deprecated Use `client.init()` instead.
*/
public setupIntegrations(forceInitialize?: boolean): void {
if ((forceInitialize && !this._integrationsInitialized) || (this._isEnabled() && !this._integrationsInitialized)) {
this._integrations = setupIntegrations(this, this._options.integrations);
this._integrationsInitialized = true;
this._setupIntegrations();
}
}

/** @inheritdoc */
public init(): void {
if (this._isEnabled()) {
this._setupIntegrations();
}
}

Expand DownExpand Up@@ -512,6 +519,13 @@ export abstract class BaseClient<O extends ClientOptions> implements Client<O> {

/* eslint-enable @typescript-eslint/unified-signatures */

/** Setup integrations for this client. */
protected _setupIntegrations(): void {
this._integrations = setupIntegrations(this, this._options.integrations);
// TODO v8: We don't need this flag anymore
this._integrationsInitialized = true;
}

/** Updates existing session based on the provided event */
protected _updateSessionFromEvent(session: Session, event: Event): void {
let crashed = false;
Expand Down
2 changes: 2 additions & 0 deletions packages/core/src/hub.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -167,7 +167,9 @@ export class Hub implements HubInterface {
const top = this.getStackTop();
top.client = client;
top.scope.setClient(client);
// eslint-disable-next-line deprecation/deprecation
if (client && client.setupIntegrations) {
// eslint-disable-next-line deprecation/deprecation
client.setupIntegrations();
}
}
Expand Down
74 changes: 69 additions & 5 deletions packages/core/test/lib/base.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -671,7 +671,7 @@ describe('BaseClient', () => {
test('adds installed integrations to sdk info', () => {
const options = getDefaultTestClientOptions({ dsn: PUBLIC_DSN, integrations: [new TestIntegration()] });
const client = new TestClient(options);
client.setupIntegrations();
client.init();

client.captureEvent({ message: 'message' });

Expand All@@ -685,7 +685,7 @@ describe('BaseClient', () => {

const options = getDefaultTestClientOptions({ dsn: PUBLIC_DSN, integrations: [new TestIntegration()] });
const client = new TestClient(options);
client.setupIntegrations();
client.init();
client.addIntegration(new AdHocIntegration());

client.captureException(new Error('test exception'));
Expand All@@ -706,7 +706,7 @@ describe('BaseClient', () => {
integrations: [new TestIntegration(), null, undefined],
});
const client = new TestClient(options);
client.setupIntegrations();
client.init();

client.captureEvent({ message: 'message' });

Expand DownExpand Up@@ -1482,24 +1482,48 @@ describe('BaseClient', () => {

const options = getDefaultTestClientOptions({ dsn: PUBLIC_DSN, integrations: [new TestIntegration()] });
const client = new TestClient(options);
// eslint-disable-next-line deprecation/deprecation
client.setupIntegrations();

expect(Object.keys((client as any)._integrations).length).toEqual(1);
expect(client.getIntegration(TestIntegration)).toBeTruthy();
});

test('skips installation if DSN is not provided', () => {
test('sets up each integration on `init` call', () => {
expect.assertions(2);

const options = getDefaultTestClientOptions({ dsn: PUBLIC_DSN, integrations: [new TestIntegration()] });
const client = new TestClient(options);
client.init();

expect(Object.keys((client as any)._integrations).length).toEqual(1);
expect(client.getIntegration(TestIntegration)).toBeTruthy();
});

test('skips installation for `setupIntegrations()` if DSN is not provided', () => {
expect.assertions(2);

const options = getDefaultTestClientOptions({ integrations: [new TestIntegration()] });
const client = new TestClient(options);
// eslint-disable-next-line deprecation/deprecation
client.setupIntegrations();

expect(Object.keys((client as any)._integrations).length).toEqual(0);
expect(client.getIntegration(TestIntegration)).toBeFalsy();
});

test('skips installation if `enabled` is set to `false`', () => {
test('skips installation for `init()` if DSN is not provided', () => {
expect.assertions(2);

const options = getDefaultTestClientOptions({ integrations: [new TestIntegration()] });
const client = new TestClient(options);
client.init();

expect(Object.keys((client as any)._integrations).length).toEqual(0);
expect(client.getIntegration(TestIntegration)).toBeFalsy();
});

test('skips installation for `setupIntegrations()` if `enabled` is set to `false`', () => {
expect.assertions(2);

const options = getDefaultTestClientOptions({
Expand All@@ -1508,12 +1532,28 @@ describe('BaseClient', () => {
integrations: [new TestIntegration()],
});
const client = new TestClient(options);
// eslint-disable-next-line deprecation/deprecation
client.setupIntegrations();

expect(Object.keys((client as any)._integrations).length).toEqual(0);
expect(client.getIntegration(TestIntegration)).toBeFalsy();
});

test('skips installation for `init()` if `enabled` is set to `false`', () => {
expect.assertions(2);

const options = getDefaultTestClientOptions({
dsn: PUBLIC_DSN,
enabled: false,
integrations: [new TestIntegration()],
});
const client = new TestClient(options);
client.init();

expect(Object.keys((client as any)._integrations).length).toEqual(0);
expect(client.getIntegration(TestIntegration)).toBeFalsy();
});

test('skips installation if integrations are already installed', () => {
expect.assertions(4);

Expand All@@ -1523,17 +1563,41 @@ describe('BaseClient', () => {
const setupIntegrationsHelper = jest.spyOn(integrationModule, 'setupIntegrations');

// it should install the first time, because integrations aren't yet installed...
// eslint-disable-next-line deprecation/deprecation
client.setupIntegrations();

expect(Object.keys((client as any)._integrations).length).toEqual(1);
expect(client.getIntegration(TestIntegration)).toBeTruthy();
expect(setupIntegrationsHelper).toHaveBeenCalledTimes(1);

// ...but it shouldn't try to install a second time
// eslint-disable-next-line deprecation/deprecation
client.setupIntegrations();

expect(setupIntegrationsHelper).toHaveBeenCalledTimes(1);
});

test('does not add integrations twice when calling `init` multiple times', () => {
const options = getDefaultTestClientOptions({ dsn: PUBLIC_DSN, integrations: [new TestIntegration()] });
const client = new TestClient(options);
// note: not the `Client` method `setupIntegrations`, but the free-standing function which that method calls
const setupIntegrationsHelper = jest.spyOn(integrationModule, 'setupIntegrations');

// it should install the first time, because integrations aren't yet installed...
client.init();

expect(Object.keys((client as any)._integrations).length).toEqual(1);
expect(client.getIntegration(TestIntegration)).toBeTruthy();
expect(setupIntegrationsHelper).toHaveBeenCalledTimes(1);

client.init();

// is called again...
expect(setupIntegrationsHelper).toHaveBeenCalledTimes(2);

// but integrations are only added once anyhow!
expect(client['_integrations']).toEqual({ TestIntegration: expect.any(TestIntegration) });
});
});

describe('flush/close', () => {
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -37,7 +37,7 @@ function createInboundFiltersEventProcessor(
}),
);

client.setupIntegrations();
client.init();

const eventProcessors = client['_eventProcessors'];
const eventProcessor = eventProcessors.find(processor => processor.id === 'InboundFilters');
Expand Down
16 changes: 13 additions & 3 deletions packages/node-experimental/src/sdk/init.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -6,7 +6,7 @@ import {
getSentryRelease,
makeNodeTransport,
} from '@sentry/node';
import type { Integration } from '@sentry/types';
import type { Client, Integration } from '@sentry/types';
import {
consoleSandbox,
dropUndefinedKeys,
Expand DownExpand Up@@ -67,7 +67,9 @@ export function init(options: NodeExperimentalOptions | undefined = {}): void {
// unless somebody specifically sets a different one on a scope/isolations cope
getGlobalScope().setClient(client);

client.setupIntegrations();
if (isEnabled(client)) {
client.init();
}

if (options.autoSessionTracking) {
startSessionTracking();
Expand All@@ -79,7 +81,11 @@ export function init(options: NodeExperimentalOptions | undefined = {}): void {
const client = getClient();
if (client.addIntegration) {
// force integrations to be setup even if no DSN was set
client.setupIntegrations(true);
// If they have already been added before, they will be ignored anyhow
const integrations = client.getOptions().integrations;
for (const integration of integrations) {
client.addIntegration(integration);
}
client.addIntegration(
new Integrations.Spotlight({
sidecarUrl: typeof options.spotlight === 'string' ? options.spotlight : undefined,
Expand DownExpand Up@@ -213,3 +219,7 @@ function startSessionTracking(): void {
}
});
}

function isEnabled(client: Client): boolean {
return client.getOptions().enabled !== false && client.getTransport() !== undefined;
}
6 changes: 5 additions & 1 deletion packages/node/src/sdk.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -183,7 +183,11 @@ export function init(options: NodeOptions = {}): void {
const client = getClient();
if (client && client.addIntegration) {
// force integrations to be setup even if no DSN was set
client.setupIntegrations(true);
// If they have already been added before, they will be ignored anyhow
const integrations = client.getOptions().integrations;
for (const integration of integrations) {
client.addIntegration(integration);
}
client.addIntegration(
new Spotlight({ sidecarUrl: typeof options.spotlight === 'string' ? options.spotlight : undefined }),
);
Expand Down
24 changes: 12 additions & 12 deletions packages/node/test/integrations/localvariables.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -162,11 +162,11 @@ describeIf(NODE_VERSION.major >= 18)('LocalVariables', () => {
const options = getDefaultNodeClientOptions({
stackParser: defaultStackParser,
includeLocalVariables: true,
integrations: [localVariables],
integrations: [],
});

const client = new NodeClient(options);
client.setupIntegrations(true);
client.addIntegration(localVariables);

const eventProcessors = client['_eventProcessors'];
const eventProcessor = eventProcessors.find(processor => processor.id === 'LocalVariables');
Expand DownExpand Up@@ -253,11 +253,11 @@ describeIf(NODE_VERSION.major >= 18)('LocalVariables', () => {
const options = getDefaultNodeClientOptions({
stackParser: defaultStackParser,
includeLocalVariables: true,
integrations: [localVariables],
integrations: [],
});

const client = new NodeClient(options);
client.setupIntegrations(true);
client.addIntegration(localVariables);

await session.runPause(exceptionEvent100Frames);

Expand All@@ -278,11 +278,11 @@ describeIf(NODE_VERSION.major >= 18)('LocalVariables', () => {
const options = getDefaultNodeClientOptions({
stackParser: defaultStackParser,
includeLocalVariables: true,
integrations: [localVariables],
integrations: [],
});

const client = new NodeClient(options);
client.setupIntegrations(true);
client.addIntegration(localVariables);

const nonExceptionEvent = {
method: exceptionEvent.method,
Expand All@@ -299,11 +299,11 @@ describeIf(NODE_VERSION.major >= 18)('LocalVariables', () => {
const localVariables = new LocalVariablesSync({}, session);
const options = getDefaultNodeClientOptions({
stackParser: defaultStackParser,
integrations: [localVariables],
integrations: [],
});

const client = new NodeClient(options);
client.setupIntegrations(true);
client.addIntegration(localVariables);

const eventProcessors = client['_eventProcessors'];
const eventProcessor = eventProcessors.find(processor => processor.id === 'LocalVariables');
Expand All@@ -315,11 +315,11 @@ describeIf(NODE_VERSION.major >= 18)('LocalVariables', () => {
const localVariables = new LocalVariablesSync({}, undefined);
const options = getDefaultNodeClientOptions({
stackParser: defaultStackParser,
integrations: [localVariables],
integrations: [],
});

const client = new NodeClient(options);
client.setupIntegrations(true);
client.addIntegration(localVariables);

const eventProcessors = client['_eventProcessors'];
const eventProcessor = eventProcessors.find(processor => processor.id === 'LocalVariables');
Expand All@@ -336,11 +336,11 @@ describeIf(NODE_VERSION.major >= 18)('LocalVariables', () => {
const options = getDefaultNodeClientOptions({
stackParser: defaultStackParser,
includeLocalVariables: true,
integrations: [localVariables],
integrations: [],
});

const client = new NodeClient(options);
client.setupIntegrations(true);
client.addIntegration(localVariables);

await session.runPause(exceptionEvent);
await session.runPause(exceptionEvent);
Expand Down
11 changes: 10 additions & 1 deletion packages/types/src/client.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -151,9 +151,18 @@ export interface Client<O extends ClientOptions = ClientOptions> {
* */
addIntegration?(integration: Integration): void;

/** This is an internal function to setup all integrations that should run on the client */
/**
* This is an internal function to setup all integrations that should run on the client.
* @deprecated Use `client.init()` instead.
*/
setupIntegrations(forceInitialize?: boolean): void;

/**
* Initialize this client.
* Call this after the client was set on a scope.
*/
init?(): void;

/** Creates an {@link Event} from all inputs to `captureException` and non-primitive inputs to `captureMessage`. */
// eslint-disable-next-line @typescript-eslint/no-explicit-any
eventFromException(exception: any, hint?: EventHint): PromiseLike<Event>;
Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions MIGRATION.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -8,6 +8,10 @@ npx @sentry/migr8@latest

This will let you select which updates to run, and automatically update your code. Make sure to still review all code changes!

## Deprecate `client.setupIntegrations()`

Instead, use the new `client.init()` method. You should probably not use this directly and instead use `Sentry.init()`, which calls this under the hood. But if you have a special use case that requires that, you can call `client.init()` instead now.

## Deprecate `scope.getSpan()` and `scope.setSpan()`

Instead, you can get the currently active span via `Sentry.getActiveSpan()`.
Expand Down
2 changes: 1 addition & 1 deletion packages/browser/test/unit/sdk.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -42,7 +42,7 @@ jest.mock('@sentry/core', () => {
return new Scope();
},
bindClient(client: Client): boolean {
client.setupIntegrations();
client.init!();
return true;
},
};
Expand Down
20 changes: 17 additions & 3 deletions packages/core/src/baseclient.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -314,12 +314,19 @@ export abstract class BaseClient<O extends ClientOptions> implements Client<O> {
}

/**
* Sets up the integrations
* This is an internal function to setup all integrations that should run on the client.
* @deprecated Use `client.init()` instead.
*/
public setupIntegrations(forceInitialize?: boolean): void {
if ((forceInitialize && !this._integrationsInitialized) || (this._isEnabled() && !this._integrationsInitialized)) {
this._integrations = setupIntegrations(this, this._options.integrations);
this._integrationsInitialized = true;
this._setupIntegrations();
}
}

/** @inheritdoc */
public init(): void {
if (this._isEnabled()) {
this._setupIntegrations();
}
}

Expand DownExpand Up@@ -512,6 +519,13 @@ export abstract class BaseClient<O extends ClientOptions> implements Client<O> {

/* eslint-enable @typescript-eslint/unified-signatures */

/** Setup integrations for this client. */
protected _setupIntegrations(): void {
this._integrations = setupIntegrations(this, this._options.integrations);
// TODO v8: We don't need this flag anymore
this._integrationsInitialized = true;
}

/** Updates existing session based on the provided event */
protected _updateSessionFromEvent(session: Session, event: Event): void {
let crashed = false;
Expand Down
2 changes: 2 additions & 0 deletions packages/core/src/hub.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -167,7 +167,9 @@ export class Hub implements HubInterface {
const top = this.getStackTop();
top.client = client;
top.scope.setClient(client);
// eslint-disable-next-line deprecation/deprecation
if (client && client.setupIntegrations) {
// eslint-disable-next-line deprecation/deprecation
client.setupIntegrations();
}
}
Expand Down
74 changes: 69 additions & 5 deletions packages/core/test/lib/base.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -671,7 +671,7 @@ describe('BaseClient', () => {
test('adds installed integrations to sdk info', () => {
const options = getDefaultTestClientOptions({ dsn: PUBLIC_DSN, integrations: [new TestIntegration()] });
const client = new TestClient(options);
client.setupIntegrations();
client.init();

client.captureEvent({ message: 'message' });

Expand All@@ -685,7 +685,7 @@ describe('BaseClient', () => {

const options = getDefaultTestClientOptions({ dsn: PUBLIC_DSN, integrations: [new TestIntegration()] });
const client = new TestClient(options);
client.setupIntegrations();
client.init();
client.addIntegration(new AdHocIntegration());

client.captureException(new Error('test exception'));
Expand All@@ -706,7 +706,7 @@ describe('BaseClient', () => {
integrations: [new TestIntegration(), null, undefined],
});
const client = new TestClient(options);
client.setupIntegrations();
client.init();

client.captureEvent({ message: 'message' });

Expand DownExpand Up@@ -1482,24 +1482,48 @@ describe('BaseClient', () => {

const options = getDefaultTestClientOptions({ dsn: PUBLIC_DSN, integrations: [new TestIntegration()] });
const client = new TestClient(options);
// eslint-disable-next-line deprecation/deprecation
client.setupIntegrations();

expect(Object.keys((client as any)._integrations).length).toEqual(1);
expect(client.getIntegration(TestIntegration)).toBeTruthy();
});

test('skips installation if DSN is not provided', () => {
test('sets up each integration on `init` call', () => {
expect.assertions(2);

const options = getDefaultTestClientOptions({ dsn: PUBLIC_DSN, integrations: [new TestIntegration()] });
const client = new TestClient(options);
client.init();

expect(Object.keys((client as any)._integrations).length).toEqual(1);
expect(client.getIntegration(TestIntegration)).toBeTruthy();
});

test('skips installation for `setupIntegrations()` if DSN is not provided', () => {
expect.assertions(2);

const options = getDefaultTestClientOptions({ integrations: [new TestIntegration()] });
const client = new TestClient(options);
// eslint-disable-next-line deprecation/deprecation
client.setupIntegrations();

expect(Object.keys((client as any)._integrations).length).toEqual(0);
expect(client.getIntegration(TestIntegration)).toBeFalsy();
});

test('skips installation if `enabled` is set to `false`', () => {
test('skips installation for `init()` if DSN is not provided', () => {
expect.assertions(2);

const options = getDefaultTestClientOptions({ integrations: [new TestIntegration()] });
const client = new TestClient(options);
client.init();

expect(Object.keys((client as any)._integrations).length).toEqual(0);
expect(client.getIntegration(TestIntegration)).toBeFalsy();
});

test('skips installation for `setupIntegrations()` if `enabled` is set to `false`', () => {
expect.assertions(2);

const options = getDefaultTestClientOptions({
Expand All@@ -1508,12 +1532,28 @@ describe('BaseClient', () => {
integrations: [new TestIntegration()],
});
const client = new TestClient(options);
// eslint-disable-next-line deprecation/deprecation
client.setupIntegrations();

expect(Object.keys((client as any)._integrations).length).toEqual(0);
expect(client.getIntegration(TestIntegration)).toBeFalsy();
});

test('skips installation for `init()` if `enabled` is set to `false`', () => {
expect.assertions(2);

const options = getDefaultTestClientOptions({
dsn: PUBLIC_DSN,
enabled: false,
integrations: [new TestIntegration()],
});
const client = new TestClient(options);
client.init();

expect(Object.keys((client as any)._integrations).length).toEqual(0);
expect(client.getIntegration(TestIntegration)).toBeFalsy();
});

test('skips installation if integrations are already installed', () => {
expect.assertions(4);

Expand All@@ -1523,17 +1563,41 @@ describe('BaseClient', () => {
const setupIntegrationsHelper = jest.spyOn(integrationModule, 'setupIntegrations');

// it should install the first time, because integrations aren't yet installed...
// eslint-disable-next-line deprecation/deprecation
client.setupIntegrations();

expect(Object.keys((client as any)._integrations).length).toEqual(1);
expect(client.getIntegration(TestIntegration)).toBeTruthy();
expect(setupIntegrationsHelper).toHaveBeenCalledTimes(1);

// ...but it shouldn't try to install a second time
// eslint-disable-next-line deprecation/deprecation
client.setupIntegrations();

expect(setupIntegrationsHelper).toHaveBeenCalledTimes(1);
});

test('does not add integrations twice when calling `init` multiple times', () => {
const options = getDefaultTestClientOptions({ dsn: PUBLIC_DSN, integrations: [new TestIntegration()] });
const client = new TestClient(options);
// note: not the `Client` method `setupIntegrations`, but the free-standing function which that method calls
const setupIntegrationsHelper = jest.spyOn(integrationModule, 'setupIntegrations');

// it should install the first time, because integrations aren't yet installed...
client.init();

expect(Object.keys((client as any)._integrations).length).toEqual(1);
expect(client.getIntegration(TestIntegration)).toBeTruthy();
expect(setupIntegrationsHelper).toHaveBeenCalledTimes(1);

client.init();

// is called again...
expect(setupIntegrationsHelper).toHaveBeenCalledTimes(2);

// but integrations are only added once anyhow!
expect(client['_integrations']).toEqual({ TestIntegration: expect.any(TestIntegration) });
});
});

describe('flush/close', () => {
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -37,7 +37,7 @@ function createInboundFiltersEventProcessor(
}),
);

client.setupIntegrations();
client.init();

const eventProcessors = client['_eventProcessors'];
const eventProcessor = eventProcessors.find(processor => processor.id === 'InboundFilters');
Expand Down
16 changes: 13 additions & 3 deletions packages/node-experimental/src/sdk/init.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -6,7 +6,7 @@ import {
getSentryRelease,
makeNodeTransport,
} from '@sentry/node';
import type { Integration } from '@sentry/types';
import type { Client, Integration } from '@sentry/types';
import {
consoleSandbox,
dropUndefinedKeys,
Expand DownExpand Up@@ -67,7 +67,9 @@ export function init(options: NodeExperimentalOptions | undefined = {}): void {
// unless somebody specifically sets a different one on a scope/isolations cope
getGlobalScope().setClient(client);

client.setupIntegrations();
if (isEnabled(client)) {
client.init();
}

if (options.autoSessionTracking) {
startSessionTracking();
Expand All@@ -79,7 +81,11 @@ export function init(options: NodeExperimentalOptions | undefined = {}): void {
const client = getClient();
if (client.addIntegration) {
// force integrations to be setup even if no DSN was set
client.setupIntegrations(true);
// If they have already been added before, they will be ignored anyhow
const integrations = client.getOptions().integrations;
for (const integration of integrations) {
client.addIntegration(integration);
}
client.addIntegration(
new Integrations.Spotlight({
sidecarUrl: typeof options.spotlight === 'string' ? options.spotlight : undefined,
Expand DownExpand Up@@ -213,3 +219,7 @@ function startSessionTracking(): void {
}
});
}

function isEnabled(client: Client): boolean {
return client.getOptions().enabled !== false && client.getTransport() !== undefined;
}
6 changes: 5 additions & 1 deletion packages/node/src/sdk.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -183,7 +183,11 @@ export function init(options: NodeOptions = {}): void {
const client = getClient();
if (client && client.addIntegration) {
// force integrations to be setup even if no DSN was set
client.setupIntegrations(true);
// If they have already been added before, they will be ignored anyhow
const integrations = client.getOptions().integrations;
for (const integration of integrations) {
client.addIntegration(integration);
}
client.addIntegration(
new Spotlight({ sidecarUrl: typeof options.spotlight === 'string' ? options.spotlight : undefined }),
);
Expand Down
24 changes: 12 additions & 12 deletions packages/node/test/integrations/localvariables.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -162,11 +162,11 @@ describeIf(NODE_VERSION.major >= 18)('LocalVariables', () => {
const options = getDefaultNodeClientOptions({
stackParser: defaultStackParser,
includeLocalVariables: true,
integrations: [localVariables],
integrations: [],
});

const client = new NodeClient(options);
client.setupIntegrations(true);
client.addIntegration(localVariables);

const eventProcessors = client['_eventProcessors'];
const eventProcessor = eventProcessors.find(processor => processor.id === 'LocalVariables');
Expand DownExpand Up@@ -253,11 +253,11 @@ describeIf(NODE_VERSION.major >= 18)('LocalVariables', () => {
const options = getDefaultNodeClientOptions({
stackParser: defaultStackParser,
includeLocalVariables: true,
integrations: [localVariables],
integrations: [],
});

const client = new NodeClient(options);
client.setupIntegrations(true);
client.addIntegration(localVariables);

await session.runPause(exceptionEvent100Frames);

Expand All@@ -278,11 +278,11 @@ describeIf(NODE_VERSION.major >= 18)('LocalVariables', () => {
const options = getDefaultNodeClientOptions({
stackParser: defaultStackParser,
includeLocalVariables: true,
integrations: [localVariables],
integrations: [],
});

const client = new NodeClient(options);
client.setupIntegrations(true);
client.addIntegration(localVariables);

const nonExceptionEvent = {
method: exceptionEvent.method,
Expand All@@ -299,11 +299,11 @@ describeIf(NODE_VERSION.major >= 18)('LocalVariables', () => {
const localVariables = new LocalVariablesSync({}, session);
const options = getDefaultNodeClientOptions({
stackParser: defaultStackParser,
integrations: [localVariables],
integrations: [],
});

const client = new NodeClient(options);
client.setupIntegrations(true);
client.addIntegration(localVariables);

const eventProcessors = client['_eventProcessors'];
const eventProcessor = eventProcessors.find(processor => processor.id === 'LocalVariables');
Expand All@@ -315,11 +315,11 @@ describeIf(NODE_VERSION.major >= 18)('LocalVariables', () => {
const localVariables = new LocalVariablesSync({}, undefined);
const options = getDefaultNodeClientOptions({
stackParser: defaultStackParser,
integrations: [localVariables],
integrations: [],
});

const client = new NodeClient(options);
client.setupIntegrations(true);
client.addIntegration(localVariables);

const eventProcessors = client['_eventProcessors'];
const eventProcessor = eventProcessors.find(processor => processor.id === 'LocalVariables');
Expand All@@ -336,11 +336,11 @@ describeIf(NODE_VERSION.major >= 18)('LocalVariables', () => {
const options = getDefaultNodeClientOptions({
stackParser: defaultStackParser,
includeLocalVariables: true,
integrations: [localVariables],
integrations: [],
});

const client = new NodeClient(options);
client.setupIntegrations(true);
client.addIntegration(localVariables);

await session.runPause(exceptionEvent);
await session.runPause(exceptionEvent);
Expand Down
11 changes: 10 additions & 1 deletion packages/types/src/client.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -151,9 +151,18 @@ export interface Client<O extends ClientOptions = ClientOptions> {
* */
addIntegration?(integration: Integration): void;

/** This is an internal function to setup all integrations that should run on the client */
/**
* This is an internal function to setup all integrations that should run on the client.
* @deprecated Use `client.init()` instead.
*/
setupIntegrations(forceInitialize?: boolean): void;

/**
* Initialize this client.
* Call this after the client was set on a scope.
*/
init?(): void;

/** Creates an {@link Event} from all inputs to `captureException` and non-primitive inputs to `captureMessage`. */
// eslint-disable-next-line @typescript-eslint/no-explicit-any
eventFromException(exception: any, hint?: EventHint): PromiseLike<Event>;
Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions MIGRATION.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -8,6 +8,10 @@ npx @sentry/migr8@latest

This will let you select which updates to run, and automatically update your code. Make sure to still review all code changes!

## Deprecate `client.setupIntegrations()`

Instead, use the new `client.init()` method. You should probably not use this directly and instead use `Sentry.init()`, which calls this under the hood. But if you have a special use case that requires that, you can call `client.init()` instead now.

## Deprecate `scope.getSpan()` and `scope.setSpan()`

Instead, you can get the currently active span via `Sentry.getActiveSpan()`.
Expand Down
2 changes: 1 addition & 1 deletion packages/browser/test/unit/sdk.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -42,7 +42,7 @@ jest.mock('@sentry/core', () => {
return new Scope();
},
bindClient(client: Client): boolean {
client.setupIntegrations();
client.init!();
return true;
},
};
Expand Down
20 changes: 17 additions & 3 deletions packages/core/src/baseclient.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -314,12 +314,19 @@ export abstract class BaseClient<O extends ClientOptions> implements Client<O> {
}

/**
* Sets up the integrations
* This is an internal function to setup all integrations that should run on the client.
* @deprecated Use `client.init()` instead.
*/
public setupIntegrations(forceInitialize?: boolean): void {
if ((forceInitialize && !this._integrationsInitialized) || (this._isEnabled() && !this._integrationsInitialized)) {
this._integrations = setupIntegrations(this, this._options.integrations);
this._integrationsInitialized = true;
this._setupIntegrations();
}
}

/** @inheritdoc */
public init(): void {
if (this._isEnabled()) {
this._setupIntegrations();
}
}

Expand DownExpand Up@@ -512,6 +519,13 @@ export abstract class BaseClient<O extends ClientOptions> implements Client<O> {

/* eslint-enable @typescript-eslint/unified-signatures */

/** Setup integrations for this client. */
protected _setupIntegrations(): void {
this._integrations = setupIntegrations(this, this._options.integrations);
// TODO v8: We don't need this flag anymore
this._integrationsInitialized = true;
}

/** Updates existing session based on the provided event */
protected _updateSessionFromEvent(session: Session, event: Event): void {
let crashed = false;
Expand Down
2 changes: 2 additions & 0 deletions packages/core/src/hub.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -167,7 +167,9 @@ export class Hub implements HubInterface {
const top = this.getStackTop();
top.client = client;
top.scope.setClient(client);
// eslint-disable-next-line deprecation/deprecation
if (client && client.setupIntegrations) {
// eslint-disable-next-line deprecation/deprecation
client.setupIntegrations();
}
}
Expand Down
74 changes: 69 additions & 5 deletions packages/core/test/lib/base.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -671,7 +671,7 @@ describe('BaseClient', () => {
test('adds installed integrations to sdk info', () => {
const options = getDefaultTestClientOptions({ dsn: PUBLIC_DSN, integrations: [new TestIntegration()] });
const client = new TestClient(options);
client.setupIntegrations();
client.init();

client.captureEvent({ message: 'message' });

Expand All@@ -685,7 +685,7 @@ describe('BaseClient', () => {

const options = getDefaultTestClientOptions({ dsn: PUBLIC_DSN, integrations: [new TestIntegration()] });
const client = new TestClient(options);
client.setupIntegrations();
client.init();
client.addIntegration(new AdHocIntegration());

client.captureException(new Error('test exception'));
Expand All@@ -706,7 +706,7 @@ describe('BaseClient', () => {
integrations: [new TestIntegration(), null, undefined],
});
const client = new TestClient(options);
client.setupIntegrations();
client.init();

client.captureEvent({ message: 'message' });

Expand DownExpand Up@@ -1482,24 +1482,48 @@ describe('BaseClient', () => {

const options = getDefaultTestClientOptions({ dsn: PUBLIC_DSN, integrations: [new TestIntegration()] });
const client = new TestClient(options);
// eslint-disable-next-line deprecation/deprecation
client.setupIntegrations();

expect(Object.keys((client as any)._integrations).length).toEqual(1);
expect(client.getIntegration(TestIntegration)).toBeTruthy();
});

test('skips installation if DSN is not provided', () => {
test('sets up each integration on `init` call', () => {
expect.assertions(2);

const options = getDefaultTestClientOptions({ dsn: PUBLIC_DSN, integrations: [new TestIntegration()] });
const client = new TestClient(options);
client.init();

expect(Object.keys((client as any)._integrations).length).toEqual(1);
expect(client.getIntegration(TestIntegration)).toBeTruthy();
});

test('skips installation for `setupIntegrations()` if DSN is not provided', () => {
expect.assertions(2);

const options = getDefaultTestClientOptions({ integrations: [new TestIntegration()] });
const client = new TestClient(options);
// eslint-disable-next-line deprecation/deprecation
client.setupIntegrations();

expect(Object.keys((client as any)._integrations).length).toEqual(0);
expect(client.getIntegration(TestIntegration)).toBeFalsy();
});

test('skips installation if `enabled` is set to `false`', () => {
test('skips installation for `init()` if DSN is not provided', () => {
expect.assertions(2);

const options = getDefaultTestClientOptions({ integrations: [new TestIntegration()] });
const client = new TestClient(options);
client.init();

expect(Object.keys((client as any)._integrations).length).toEqual(0);
expect(client.getIntegration(TestIntegration)).toBeFalsy();
});

test('skips installation for `setupIntegrations()` if `enabled` is set to `false`', () => {
expect.assertions(2);

const options = getDefaultTestClientOptions({
Expand All@@ -1508,12 +1532,28 @@ describe('BaseClient', () => {
integrations: [new TestIntegration()],
});
const client = new TestClient(options);
// eslint-disable-next-line deprecation/deprecation
client.setupIntegrations();

expect(Object.keys((client as any)._integrations).length).toEqual(0);
expect(client.getIntegration(TestIntegration)).toBeFalsy();
});

test('skips installation for `init()` if `enabled` is set to `false`', () => {
expect.assertions(2);

const options = getDefaultTestClientOptions({
dsn: PUBLIC_DSN,
enabled: false,
integrations: [new TestIntegration()],
});
const client = new TestClient(options);
client.init();

expect(Object.keys((client as any)._integrations).length).toEqual(0);
expect(client.getIntegration(TestIntegration)).toBeFalsy();
});

test('skips installation if integrations are already installed', () => {
expect.assertions(4);

Expand All@@ -1523,17 +1563,41 @@ describe('BaseClient', () => {
const setupIntegrationsHelper = jest.spyOn(integrationModule, 'setupIntegrations');

// it should install the first time, because integrations aren't yet installed...
// eslint-disable-next-line deprecation/deprecation
client.setupIntegrations();

expect(Object.keys((client as any)._integrations).length).toEqual(1);
expect(client.getIntegration(TestIntegration)).toBeTruthy();
expect(setupIntegrationsHelper).toHaveBeenCalledTimes(1);

// ...but it shouldn't try to install a second time
// eslint-disable-next-line deprecation/deprecation
client.setupIntegrations();

expect(setupIntegrationsHelper).toHaveBeenCalledTimes(1);
});

test('does not add integrations twice when calling `init` multiple times', () => {
const options = getDefaultTestClientOptions({ dsn: PUBLIC_DSN, integrations: [new TestIntegration()] });
const client = new TestClient(options);
// note: not the `Client` method `setupIntegrations`, but the free-standing function which that method calls
const setupIntegrationsHelper = jest.spyOn(integrationModule, 'setupIntegrations');

// it should install the first time, because integrations aren't yet installed...
client.init();

expect(Object.keys((client as any)._integrations).length).toEqual(1);
expect(client.getIntegration(TestIntegration)).toBeTruthy();
expect(setupIntegrationsHelper).toHaveBeenCalledTimes(1);

client.init();

// is called again...
expect(setupIntegrationsHelper).toHaveBeenCalledTimes(2);

// but integrations are only added once anyhow!
expect(client['_integrations']).toEqual({ TestIntegration: expect.any(TestIntegration) });
});
});

describe('flush/close', () => {
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -37,7 +37,7 @@ function createInboundFiltersEventProcessor(
}),
);

client.setupIntegrations();
client.init();

const eventProcessors = client['_eventProcessors'];
const eventProcessor = eventProcessors.find(processor => processor.id === 'InboundFilters');
Expand Down
16 changes: 13 additions & 3 deletions packages/node-experimental/src/sdk/init.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -6,7 +6,7 @@ import {
getSentryRelease,
makeNodeTransport,
} from '@sentry/node';
import type { Integration } from '@sentry/types';
import type { Client, Integration } from '@sentry/types';
import {
consoleSandbox,
dropUndefinedKeys,
Expand DownExpand Up@@ -67,7 +67,9 @@ export function init(options: NodeExperimentalOptions | undefined = {}): void {
// unless somebody specifically sets a different one on a scope/isolations cope
getGlobalScope().setClient(client);

client.setupIntegrations();
if (isEnabled(client)) {
client.init();
}

if (options.autoSessionTracking) {
startSessionTracking();
Expand All@@ -79,7 +81,11 @@ export function init(options: NodeExperimentalOptions | undefined = {}): void {
const client = getClient();
if (client.addIntegration) {
// force integrations to be setup even if no DSN was set
client.setupIntegrations(true);
// If they have already been added before, they will be ignored anyhow
const integrations = client.getOptions().integrations;
for (const integration of integrations) {
client.addIntegration(integration);
}
client.addIntegration(
new Integrations.Spotlight({
sidecarUrl: typeof options.spotlight === 'string' ? options.spotlight : undefined,
Expand DownExpand Up@@ -213,3 +219,7 @@ function startSessionTracking(): void {
}
});
}

function isEnabled(client: Client): boolean {
return client.getOptions().enabled !== false && client.getTransport() !== undefined;
}
6 changes: 5 additions & 1 deletion packages/node/src/sdk.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -183,7 +183,11 @@ export function init(options: NodeOptions = {}): void {
const client = getClient();
if (client && client.addIntegration) {
// force integrations to be setup even if no DSN was set
client.setupIntegrations(true);
// If they have already been added before, they will be ignored anyhow
const integrations = client.getOptions().integrations;
for (const integration of integrations) {
client.addIntegration(integration);
}
client.addIntegration(
new Spotlight({ sidecarUrl: typeof options.spotlight === 'string' ? options.spotlight : undefined }),
);
Expand Down
24 changes: 12 additions & 12 deletions packages/node/test/integrations/localvariables.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -162,11 +162,11 @@ describeIf(NODE_VERSION.major >= 18)('LocalVariables', () => {
const options = getDefaultNodeClientOptions({
stackParser: defaultStackParser,
includeLocalVariables: true,
integrations: [localVariables],
integrations: [],
});

const client = new NodeClient(options);
client.setupIntegrations(true);
client.addIntegration(localVariables);

const eventProcessors = client['_eventProcessors'];
const eventProcessor = eventProcessors.find(processor => processor.id === 'LocalVariables');
Expand DownExpand Up@@ -253,11 +253,11 @@ describeIf(NODE_VERSION.major >= 18)('LocalVariables', () => {
const options = getDefaultNodeClientOptions({
stackParser: defaultStackParser,
includeLocalVariables: true,
integrations: [localVariables],
integrations: [],
});

const client = new NodeClient(options);
client.setupIntegrations(true);
client.addIntegration(localVariables);

await session.runPause(exceptionEvent100Frames);

Expand All@@ -278,11 +278,11 @@ describeIf(NODE_VERSION.major >= 18)('LocalVariables', () => {
const options = getDefaultNodeClientOptions({
stackParser: defaultStackParser,
includeLocalVariables: true,
integrations: [localVariables],
integrations: [],
});

const client = new NodeClient(options);
client.setupIntegrations(true);
client.addIntegration(localVariables);

const nonExceptionEvent = {
method: exceptionEvent.method,
Expand All@@ -299,11 +299,11 @@ describeIf(NODE_VERSION.major >= 18)('LocalVariables', () => {
const localVariables = new LocalVariablesSync({}, session);
const options = getDefaultNodeClientOptions({
stackParser: defaultStackParser,
integrations: [localVariables],
integrations: [],
});

const client = new NodeClient(options);
client.setupIntegrations(true);
client.addIntegration(localVariables);

const eventProcessors = client['_eventProcessors'];
const eventProcessor = eventProcessors.find(processor => processor.id === 'LocalVariables');
Expand All@@ -315,11 +315,11 @@ describeIf(NODE_VERSION.major >= 18)('LocalVariables', () => {
const localVariables = new LocalVariablesSync({}, undefined);
const options = getDefaultNodeClientOptions({
stackParser: defaultStackParser,
integrations: [localVariables],
integrations: [],
});

const client = new NodeClient(options);
client.setupIntegrations(true);
client.addIntegration(localVariables);

const eventProcessors = client['_eventProcessors'];
const eventProcessor = eventProcessors.find(processor => processor.id === 'LocalVariables');
Expand All@@ -336,11 +336,11 @@ describeIf(NODE_VERSION.major >= 18)('LocalVariables', () => {
const options = getDefaultNodeClientOptions({
stackParser: defaultStackParser,
includeLocalVariables: true,
integrations: [localVariables],
integrations: [],
});

const client = new NodeClient(options);
client.setupIntegrations(true);
client.addIntegration(localVariables);

await session.runPause(exceptionEvent);
await session.runPause(exceptionEvent);
Expand Down
11 changes: 10 additions & 1 deletion packages/types/src/client.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -151,9 +151,18 @@ export interface Client<O extends ClientOptions = ClientOptions> {
* */
addIntegration?(integration: Integration): void;

/** This is an internal function to setup all integrations that should run on the client */
/**
* This is an internal function to setup all integrations that should run on the client.
* @deprecated Use `client.init()` instead.
*/
setupIntegrations(forceInitialize?: boolean): void;

/**
* Initialize this client.
* Call this after the client was set on a scope.
*/
init?(): void;

/** Creates an {@link Event} from all inputs to `captureException` and non-primitive inputs to `captureMessage`. */
// eslint-disable-next-line @typescript-eslint/no-explicit-any
eventFromException(exception: any, hint?: EventHint): PromiseLike<Event>;
Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions MIGRATION.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -8,6 +8,10 @@ npx @sentry/migr8@latest

This will let you select which updates to run, and automatically update your code. Make sure to still review all code changes!

## Deprecate `client.setupIntegrations()`

Instead, use the new `client.init()` method. You should probably not use this directly and instead use `Sentry.init()`, which calls this under the hood. But if you have a special use case that requires that, you can call `client.init()` instead now.

## Deprecate `scope.getSpan()` and `scope.setSpan()`

Instead, you can get the currently active span via `Sentry.getActiveSpan()`.
Expand Down
2 changes: 1 addition & 1 deletion packages/browser/test/unit/sdk.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -42,7 +42,7 @@ jest.mock('@sentry/core', () => {
return new Scope();
},
bindClient(client: Client): boolean {
client.setupIntegrations();
client.init!();
return true;
},
};
Expand Down
20 changes: 17 additions & 3 deletions packages/core/src/baseclient.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -314,12 +314,19 @@ export abstract class BaseClient<O extends ClientOptions> implements Client<O> {
}

/**
* Sets up the integrations
* This is an internal function to setup all integrations that should run on the client.
* @deprecated Use `client.init()` instead.
*/
public setupIntegrations(forceInitialize?: boolean): void {
if ((forceInitialize && !this._integrationsInitialized) || (this._isEnabled() && !this._integrationsInitialized)) {
this._integrations = setupIntegrations(this, this._options.integrations);
this._integrationsInitialized = true;
this._setupIntegrations();
}
}

/** @inheritdoc */
public init(): void {
if (this._isEnabled()) {
this._setupIntegrations();
}
}

Expand DownExpand Up@@ -512,6 +519,13 @@ export abstract class BaseClient<O extends ClientOptions> implements Client<O> {

/* eslint-enable @typescript-eslint/unified-signatures */

/** Setup integrations for this client. */
protected _setupIntegrations(): void {
this._integrations = setupIntegrations(this, this._options.integrations);
// TODO v8: We don't need this flag anymore
this._integrationsInitialized = true;
}

/** Updates existing session based on the provided event */
protected _updateSessionFromEvent(session: Session, event: Event): void {
let crashed = false;
Expand Down
2 changes: 2 additions & 0 deletions packages/core/src/hub.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -167,7 +167,9 @@ export class Hub implements HubInterface {
const top = this.getStackTop();
top.client = client;
top.scope.setClient(client);
// eslint-disable-next-line deprecation/deprecation
if (client && client.setupIntegrations) {
// eslint-disable-next-line deprecation/deprecation
client.setupIntegrations();
}
}
Expand Down
74 changes: 69 additions & 5 deletions packages/core/test/lib/base.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -671,7 +671,7 @@ describe('BaseClient', () => {
test('adds installed integrations to sdk info', () => {
const options = getDefaultTestClientOptions({ dsn: PUBLIC_DSN, integrations: [new TestIntegration()] });
const client = new TestClient(options);
client.setupIntegrations();
client.init();

client.captureEvent({ message: 'message' });

Expand All@@ -685,7 +685,7 @@ describe('BaseClient', () => {

const options = getDefaultTestClientOptions({ dsn: PUBLIC_DSN, integrations: [new TestIntegration()] });
const client = new TestClient(options);
client.setupIntegrations();
client.init();
client.addIntegration(new AdHocIntegration());

client.captureException(new Error('test exception'));
Expand All@@ -706,7 +706,7 @@ describe('BaseClient', () => {
integrations: [new TestIntegration(), null, undefined],
});
const client = new TestClient(options);
client.setupIntegrations();
client.init();

client.captureEvent({ message: 'message' });

Expand DownExpand Up@@ -1482,24 +1482,48 @@ describe('BaseClient', () => {

const options = getDefaultTestClientOptions({ dsn: PUBLIC_DSN, integrations: [new TestIntegration()] });
const client = new TestClient(options);
// eslint-disable-next-line deprecation/deprecation
client.setupIntegrations();

expect(Object.keys((client as any)._integrations).length).toEqual(1);
expect(client.getIntegration(TestIntegration)).toBeTruthy();
});

test('skips installation if DSN is not provided', () => {
test('sets up each integration on `init` call', () => {
expect.assertions(2);

const options = getDefaultTestClientOptions({ dsn: PUBLIC_DSN, integrations: [new TestIntegration()] });
const client = new TestClient(options);
client.init();

expect(Object.keys((client as any)._integrations).length).toEqual(1);
expect(client.getIntegration(TestIntegration)).toBeTruthy();
});

test('skips installation for `setupIntegrations()` if DSN is not provided', () => {
expect.assertions(2);

const options = getDefaultTestClientOptions({ integrations: [new TestIntegration()] });
const client = new TestClient(options);
// eslint-disable-next-line deprecation/deprecation
client.setupIntegrations();

expect(Object.keys((client as any)._integrations).length).toEqual(0);
expect(client.getIntegration(TestIntegration)).toBeFalsy();
});

test('skips installation if `enabled` is set to `false`', () => {
test('skips installation for `init()` if DSN is not provided', () => {
expect.assertions(2);

const options = getDefaultTestClientOptions({ integrations: [new TestIntegration()] });
const client = new TestClient(options);
client.init();

expect(Object.keys((client as any)._integrations).length).toEqual(0);
expect(client.getIntegration(TestIntegration)).toBeFalsy();
});

test('skips installation for `setupIntegrations()` if `enabled` is set to `false`', () => {
expect.assertions(2);

const options = getDefaultTestClientOptions({
Expand All@@ -1508,12 +1532,28 @@ describe('BaseClient', () => {
integrations: [new TestIntegration()],
});
const client = new TestClient(options);
// eslint-disable-next-line deprecation/deprecation
client.setupIntegrations();

expect(Object.keys((client as any)._integrations).length).toEqual(0);
expect(client.getIntegration(TestIntegration)).toBeFalsy();
});

test('skips installation for `init()` if `enabled` is set to `false`', () => {
expect.assertions(2);

const options = getDefaultTestClientOptions({
dsn: PUBLIC_DSN,
enabled: false,
integrations: [new TestIntegration()],
});
const client = new TestClient(options);
client.init();

expect(Object.keys((client as any)._integrations).length).toEqual(0);
expect(client.getIntegration(TestIntegration)).toBeFalsy();
});

test('skips installation if integrations are already installed', () => {
expect.assertions(4);

Expand All@@ -1523,17 +1563,41 @@ describe('BaseClient', () => {
const setupIntegrationsHelper = jest.spyOn(integrationModule, 'setupIntegrations');

// it should install the first time, because integrations aren't yet installed...
// eslint-disable-next-line deprecation/deprecation
client.setupIntegrations();

expect(Object.keys((client as any)._integrations).length).toEqual(1);
expect(client.getIntegration(TestIntegration)).toBeTruthy();
expect(setupIntegrationsHelper).toHaveBeenCalledTimes(1);

// ...but it shouldn't try to install a second time
// eslint-disable-next-line deprecation/deprecation
client.setupIntegrations();

expect(setupIntegrationsHelper).toHaveBeenCalledTimes(1);
});

test('does not add integrations twice when calling `init` multiple times', () => {
const options = getDefaultTestClientOptions({ dsn: PUBLIC_DSN, integrations: [new TestIntegration()] });
const client = new TestClient(options);
// note: not the `Client` method `setupIntegrations`, but the free-standing function which that method calls
const setupIntegrationsHelper = jest.spyOn(integrationModule, 'setupIntegrations');

// it should install the first time, because integrations aren't yet installed...
client.init();

expect(Object.keys((client as any)._integrations).length).toEqual(1);
expect(client.getIntegration(TestIntegration)).toBeTruthy();
expect(setupIntegrationsHelper).toHaveBeenCalledTimes(1);

client.init();

// is called again...
expect(setupIntegrationsHelper).toHaveBeenCalledTimes(2);

// but integrations are only added once anyhow!
expect(client['_integrations']).toEqual({ TestIntegration: expect.any(TestIntegration) });
});
});

describe('flush/close', () => {
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -37,7 +37,7 @@ function createInboundFiltersEventProcessor(
}),
);

client.setupIntegrations();
client.init();

const eventProcessors = client['_eventProcessors'];
const eventProcessor = eventProcessors.find(processor => processor.id === 'InboundFilters');
Expand Down
16 changes: 13 additions & 3 deletions packages/node-experimental/src/sdk/init.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -6,7 +6,7 @@ import {
getSentryRelease,
makeNodeTransport,
} from '@sentry/node';
import type { Integration } from '@sentry/types';
import type { Client, Integration } from '@sentry/types';
import {
consoleSandbox,
dropUndefinedKeys,
Expand DownExpand Up@@ -67,7 +67,9 @@ export function init(options: NodeExperimentalOptions | undefined = {}): void {
// unless somebody specifically sets a different one on a scope/isolations cope
getGlobalScope().setClient(client);

client.setupIntegrations();
if (isEnabled(client)) {
client.init();
}

if (options.autoSessionTracking) {
startSessionTracking();
Expand All@@ -79,7 +81,11 @@ export function init(options: NodeExperimentalOptions | undefined = {}): void {
const client = getClient();
if (client.addIntegration) {
// force integrations to be setup even if no DSN was set
client.setupIntegrations(true);
// If they have already been added before, they will be ignored anyhow
const integrations = client.getOptions().integrations;
for (const integration of integrations) {
client.addIntegration(integration);
}
client.addIntegration(
new Integrations.Spotlight({
sidecarUrl: typeof options.spotlight === 'string' ? options.spotlight : undefined,
Expand DownExpand Up@@ -213,3 +219,7 @@ function startSessionTracking(): void {
}
});
}

function isEnabled(client: Client): boolean {
return client.getOptions().enabled !== false && client.getTransport() !== undefined;
}
6 changes: 5 additions & 1 deletion packages/node/src/sdk.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -183,7 +183,11 @@ export function init(options: NodeOptions = {}): void {
const client = getClient();
if (client && client.addIntegration) {
// force integrations to be setup even if no DSN was set
client.setupIntegrations(true);
// If they have already been added before, they will be ignored anyhow
const integrations = client.getOptions().integrations;
for (const integration of integrations) {
client.addIntegration(integration);
}
client.addIntegration(
new Spotlight({ sidecarUrl: typeof options.spotlight === 'string' ? options.spotlight : undefined }),
);
Expand Down
24 changes: 12 additions & 12 deletions packages/node/test/integrations/localvariables.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -162,11 +162,11 @@ describeIf(NODE_VERSION.major >= 18)('LocalVariables', () => {
const options = getDefaultNodeClientOptions({
stackParser: defaultStackParser,
includeLocalVariables: true,
integrations: [localVariables],
integrations: [],
});

const client = new NodeClient(options);
client.setupIntegrations(true);
client.addIntegration(localVariables);

const eventProcessors = client['_eventProcessors'];
const eventProcessor = eventProcessors.find(processor => processor.id === 'LocalVariables');
Expand DownExpand Up@@ -253,11 +253,11 @@ describeIf(NODE_VERSION.major >= 18)('LocalVariables', () => {
const options = getDefaultNodeClientOptions({
stackParser: defaultStackParser,
includeLocalVariables: true,
integrations: [localVariables],
integrations: [],
});

const client = new NodeClient(options);
client.setupIntegrations(true);
client.addIntegration(localVariables);

await session.runPause(exceptionEvent100Frames);

Expand All@@ -278,11 +278,11 @@ describeIf(NODE_VERSION.major >= 18)('LocalVariables', () => {
const options = getDefaultNodeClientOptions({
stackParser: defaultStackParser,
includeLocalVariables: true,
integrations: [localVariables],
integrations: [],
});

const client = new NodeClient(options);
client.setupIntegrations(true);
client.addIntegration(localVariables);

const nonExceptionEvent = {
method: exceptionEvent.method,
Expand All@@ -299,11 +299,11 @@ describeIf(NODE_VERSION.major >= 18)('LocalVariables', () => {
const localVariables = new LocalVariablesSync({}, session);
const options = getDefaultNodeClientOptions({
stackParser: defaultStackParser,
integrations: [localVariables],
integrations: [],
});

const client = new NodeClient(options);
client.setupIntegrations(true);
client.addIntegration(localVariables);

const eventProcessors = client['_eventProcessors'];
const eventProcessor = eventProcessors.find(processor => processor.id === 'LocalVariables');
Expand All@@ -315,11 +315,11 @@ describeIf(NODE_VERSION.major >= 18)('LocalVariables', () => {
const localVariables = new LocalVariablesSync({}, undefined);
const options = getDefaultNodeClientOptions({
stackParser: defaultStackParser,
integrations: [localVariables],
integrations: [],
});

const client = new NodeClient(options);
client.setupIntegrations(true);
client.addIntegration(localVariables);

const eventProcessors = client['_eventProcessors'];
const eventProcessor = eventProcessors.find(processor => processor.id === 'LocalVariables');
Expand All@@ -336,11 +336,11 @@ describeIf(NODE_VERSION.major >= 18)('LocalVariables', () => {
const options = getDefaultNodeClientOptions({
stackParser: defaultStackParser,
includeLocalVariables: true,
integrations: [localVariables],
integrations: [],
});

const client = new NodeClient(options);
client.setupIntegrations(true);
client.addIntegration(localVariables);

await session.runPause(exceptionEvent);
await session.runPause(exceptionEvent);
Expand Down
11 changes: 10 additions & 1 deletion packages/types/src/client.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -151,9 +151,18 @@ export interface Client<O extends ClientOptions = ClientOptions> {
* */
addIntegration?(integration: Integration): void;

/** This is an internal function to setup all integrations that should run on the client */
/**
* This is an internal function to setup all integrations that should run on the client.
* @deprecated Use `client.init()` instead.
*/
setupIntegrations(forceInitialize?: boolean): void;

/**
* Initialize this client.
* Call this after the client was set on a scope.
*/
init?(): void;

/** Creates an {@link Event} from all inputs to `captureException` and non-primitive inputs to `captureMessage`. */
// eslint-disable-next-line @typescript-eslint/no-explicit-any
eventFromException(exception: any, hint?: EventHint): PromiseLike<Event>;
Expand Down
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions MIGRATION.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -8,6 +8,10 @@ npx @sentry/migr8@latest

This will let you select which updates to run, and automatically update your code. Make sure to still review all code changes!

## Deprecate `client.setupIntegrations()`

Instead, use the new `client.init()` method. You should probably not use this directly and instead use `Sentry.init()`, which calls this under the hood. But if you have a special use case that requires that, you can call `client.init()` instead now.

## Deprecate `scope.getSpan()` and `scope.setSpan()`

Instead, you can get the currently active span via `Sentry.getActiveSpan()`.
Expand Down
2 changes: 1 addition & 1 deletion packages/browser/test/unit/sdk.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -42,7 +42,7 @@ jest.mock('@sentry/core', () => {
return new Scope();
},
bindClient(client: Client): boolean {
client.setupIntegrations();
client.init!();
return true;
},
};
Expand Down
20 changes: 17 additions & 3 deletions packages/core/src/baseclient.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -314,12 +314,19 @@ export abstract class BaseClient<O extends ClientOptions> implements Client<O> {
}

/**
* Sets up the integrations
* This is an internal function to setup all integrations that should run on the client.
* @deprecated Use `client.init()` instead.
*/
public setupIntegrations(forceInitialize?: boolean): void {
if ((forceInitialize && !this._integrationsInitialized) || (this._isEnabled() && !this._integrationsInitialized)) {
this._integrations = setupIntegrations(this, this._options.integrations);
this._integrationsInitialized = true;
this._setupIntegrations();
}
}

/** @inheritdoc */
public init(): void {
if (this._isEnabled()) {
this._setupIntegrations();
}
}

Expand DownExpand Up@@ -512,6 +519,13 @@ export abstract class BaseClient<O extends ClientOptions> implements Client<O> {

/* eslint-enable @typescript-eslint/unified-signatures */

/** Setup integrations for this client. */
protected _setupIntegrations(): void {
this._integrations = setupIntegrations(this, this._options.integrations);
// TODO v8: We don't need this flag anymore
this._integrationsInitialized = true;
}

/** Updates existing session based on the provided event */
protected _updateSessionFromEvent(session: Session, event: Event): void {
let crashed = false;
Expand Down
2 changes: 2 additions & 0 deletions packages/core/src/hub.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -167,7 +167,9 @@ export class Hub implements HubInterface {
const top = this.getStackTop();
top.client = client;
top.scope.setClient(client);
// eslint-disable-next-line deprecation/deprecation
if (client && client.setupIntegrations) {
// eslint-disable-next-line deprecation/deprecation
client.setupIntegrations();
}
}
Expand Down
74 changes: 69 additions & 5 deletions packages/core/test/lib/base.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -671,7 +671,7 @@ describe('BaseClient', () => {
test('adds installed integrations to sdk info', () => {
const options = getDefaultTestClientOptions({ dsn: PUBLIC_DSN, integrations: [new TestIntegration()] });
const client = new TestClient(options);
client.setupIntegrations();
client.init();

client.captureEvent({ message: 'message' });

Expand All@@ -685,7 +685,7 @@ describe('BaseClient', () => {

const options = getDefaultTestClientOptions({ dsn: PUBLIC_DSN, integrations: [new TestIntegration()] });
const client = new TestClient(options);
client.setupIntegrations();
client.init();
client.addIntegration(new AdHocIntegration());

client.captureException(new Error('test exception'));
Expand All@@ -706,7 +706,7 @@ describe('BaseClient', () => {
integrations: [new TestIntegration(), null, undefined],
});
const client = new TestClient(options);
client.setupIntegrations();
client.init();

client.captureEvent({ message: 'message' });

Expand DownExpand Up@@ -1482,24 +1482,48 @@ describe('BaseClient', () => {

const options = getDefaultTestClientOptions({ dsn: PUBLIC_DSN, integrations: [new TestIntegration()] });
const client = new TestClient(options);
// eslint-disable-next-line deprecation/deprecation
client.setupIntegrations();

expect(Object.keys((client as any)._integrations).length).toEqual(1);
expect(client.getIntegration(TestIntegration)).toBeTruthy();
});

test('skips installation if DSN is not provided', () => {
test('sets up each integration on `init` call', () => {
expect.assertions(2);

const options = getDefaultTestClientOptions({ dsn: PUBLIC_DSN, integrations: [new TestIntegration()] });
const client = new TestClient(options);
client.init();

expect(Object.keys((client as any)._integrations).length).toEqual(1);
expect(client.getIntegration(TestIntegration)).toBeTruthy();
});

test('skips installation for `setupIntegrations()` if DSN is not provided', () => {
expect.assertions(2);

const options = getDefaultTestClientOptions({ integrations: [new TestIntegration()] });
const client = new TestClient(options);
// eslint-disable-next-line deprecation/deprecation
client.setupIntegrations();

expect(Object.keys((client as any)._integrations).length).toEqual(0);
expect(client.getIntegration(TestIntegration)).toBeFalsy();
});

test('skips installation if `enabled` is set to `false`', () => {
test('skips installation for `init()` if DSN is not provided', () => {
expect.assertions(2);

const options = getDefaultTestClientOptions({ integrations: [new TestIntegration()] });
const client = new TestClient(options);
client.init();

expect(Object.keys((client as any)._integrations).length).toEqual(0);
expect(client.getIntegration(TestIntegration)).toBeFalsy();
});

test('skips installation for `setupIntegrations()` if `enabled` is set to `false`', () => {
expect.assertions(2);

const options = getDefaultTestClientOptions({
Expand All@@ -1508,12 +1532,28 @@ describe('BaseClient', () => {
integrations: [new TestIntegration()],
});
const client = new TestClient(options);
// eslint-disable-next-line deprecation/deprecation
client.setupIntegrations();

expect(Object.keys((client as any)._integrations).length).toEqual(0);
expect(client.getIntegration(TestIntegration)).toBeFalsy();
});

test('skips installation for `init()` if `enabled` is set to `false`', () => {
expect.assertions(2);

const options = getDefaultTestClientOptions({
dsn: PUBLIC_DSN,
enabled: false,
integrations: [new TestIntegration()],
});
const client = new TestClient(options);
client.init();

expect(Object.keys((client as any)._integrations).length).toEqual(0);
expect(client.getIntegration(TestIntegration)).toBeFalsy();
});

test('skips installation if integrations are already installed', () => {
expect.assertions(4);

Expand All@@ -1523,17 +1563,41 @@ describe('BaseClient', () => {
const setupIntegrationsHelper = jest.spyOn(integrationModule, 'setupIntegrations');

// it should install the first time, because integrations aren't yet installed...
// eslint-disable-next-line deprecation/deprecation
client.setupIntegrations();

expect(Object.keys((client as any)._integrations).length).toEqual(1);
expect(client.getIntegration(TestIntegration)).toBeTruthy();
expect(setupIntegrationsHelper).toHaveBeenCalledTimes(1);

// ...but it shouldn't try to install a second time
// eslint-disable-next-line deprecation/deprecation
client.setupIntegrations();

expect(setupIntegrationsHelper).toHaveBeenCalledTimes(1);
});

test('does not add integrations twice when calling `init` multiple times', () => {
const options = getDefaultTestClientOptions({ dsn: PUBLIC_DSN, integrations: [new TestIntegration()] });
const client = new TestClient(options);
// note: not the `Client` method `setupIntegrations`, but the free-standing function which that method calls
const setupIntegrationsHelper = jest.spyOn(integrationModule, 'setupIntegrations');

// it should install the first time, because integrations aren't yet installed...
client.init();

expect(Object.keys((client as any)._integrations).length).toEqual(1);
expect(client.getIntegration(TestIntegration)).toBeTruthy();
expect(setupIntegrationsHelper).toHaveBeenCalledTimes(1);

client.init();

// is called again...
expect(setupIntegrationsHelper).toHaveBeenCalledTimes(2);

// but integrations are only added once anyhow!
expect(client['_integrations']).toEqual({ TestIntegration: expect.any(TestIntegration) });
});
});

describe('flush/close', () => {
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -37,7 +37,7 @@ function createInboundFiltersEventProcessor(
}),
);

client.setupIntegrations();
client.init();

const eventProcessors = client['_eventProcessors'];
const eventProcessor = eventProcessors.find(processor => processor.id === 'InboundFilters');
Expand Down
16 changes: 13 additions & 3 deletions packages/node-experimental/src/sdk/init.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -6,7 +6,7 @@ import {
getSentryRelease,
makeNodeTransport,
} from '@sentry/node';
import type { Integration } from '@sentry/types';
import type { Client, Integration } from '@sentry/types';
import {
consoleSandbox,
dropUndefinedKeys,
Expand DownExpand Up@@ -67,7 +67,9 @@ export function init(options: NodeExperimentalOptions | undefined = {}): void {
// unless somebody specifically sets a different one on a scope/isolations cope
getGlobalScope().setClient(client);

client.setupIntegrations();
if (isEnabled(client)) {
client.init();
}

if (options.autoSessionTracking) {
startSessionTracking();
Expand All@@ -79,7 +81,11 @@ export function init(options: NodeExperimentalOptions | undefined = {}): void {
const client = getClient();
if (client.addIntegration) {
// force integrations to be setup even if no DSN was set
client.setupIntegrations(true);
// If they have already been added before, they will be ignored anyhow
const integrations = client.getOptions().integrations;
for (const integration of integrations) {
client.addIntegration(integration);
}
client.addIntegration(
new Integrations.Spotlight({
sidecarUrl: typeof options.spotlight === 'string' ? options.spotlight : undefined,
Expand DownExpand Up@@ -213,3 +219,7 @@ function startSessionTracking(): void {
}
});
}

function isEnabled(client: Client): boolean {
return client.getOptions().enabled !== false && client.getTransport() !== undefined;
}
6 changes: 5 additions & 1 deletion packages/node/src/sdk.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -183,7 +183,11 @@ export function init(options: NodeOptions = {}): void {
const client = getClient();
if (client && client.addIntegration) {
// force integrations to be setup even if no DSN was set
client.setupIntegrations(true);
// If they have already been added before, they will be ignored anyhow
const integrations = client.getOptions().integrations;
for (const integration of integrations) {
client.addIntegration(integration);
}
client.addIntegration(
new Spotlight({ sidecarUrl: typeof options.spotlight === 'string' ? options.spotlight : undefined }),
);
Expand Down
24 changes: 12 additions & 12 deletions packages/node/test/integrations/localvariables.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -162,11 +162,11 @@ describeIf(NODE_VERSION.major >= 18)('LocalVariables', () => {
const options = getDefaultNodeClientOptions({
stackParser: defaultStackParser,
includeLocalVariables: true,
integrations: [localVariables],
integrations: [],
});

const client = new NodeClient(options);
client.setupIntegrations(true);
client.addIntegration(localVariables);

const eventProcessors = client['_eventProcessors'];
const eventProcessor = eventProcessors.find(processor => processor.id === 'LocalVariables');
Expand DownExpand Up@@ -253,11 +253,11 @@ describeIf(NODE_VERSION.major >= 18)('LocalVariables', () => {
const options = getDefaultNodeClientOptions({
stackParser: defaultStackParser,
includeLocalVariables: true,
integrations: [localVariables],
integrations: [],
});

const client = new NodeClient(options);
client.setupIntegrations(true);
client.addIntegration(localVariables);

await session.runPause(exceptionEvent100Frames);

Expand All@@ -278,11 +278,11 @@ describeIf(NODE_VERSION.major >= 18)('LocalVariables', () => {
const options = getDefaultNodeClientOptions({
stackParser: defaultStackParser,
includeLocalVariables: true,
integrations: [localVariables],
integrations: [],
});

const client = new NodeClient(options);
client.setupIntegrations(true);
client.addIntegration(localVariables);

const nonExceptionEvent = {
method: exceptionEvent.method,
Expand All@@ -299,11 +299,11 @@ describeIf(NODE_VERSION.major >= 18)('LocalVariables', () => {
const localVariables = new LocalVariablesSync({}, session);
const options = getDefaultNodeClientOptions({
stackParser: defaultStackParser,
integrations: [localVariables],
integrations: [],
});

const client = new NodeClient(options);
client.setupIntegrations(true);
client.addIntegration(localVariables);

const eventProcessors = client['_eventProcessors'];
const eventProcessor = eventProcessors.find(processor => processor.id === 'LocalVariables');
Expand All@@ -315,11 +315,11 @@ describeIf(NODE_VERSION.major >= 18)('LocalVariables', () => {
const localVariables = new LocalVariablesSync({}, undefined);
const options = getDefaultNodeClientOptions({
stackParser: defaultStackParser,
integrations: [localVariables],
integrations: [],
});

const client = new NodeClient(options);
client.setupIntegrations(true);
client.addIntegration(localVariables);

const eventProcessors = client['_eventProcessors'];
const eventProcessor = eventProcessors.find(processor => processor.id === 'LocalVariables');
Expand All@@ -336,11 +336,11 @@ describeIf(NODE_VERSION.major >= 18)('LocalVariables', () => {
const options = getDefaultNodeClientOptions({
stackParser: defaultStackParser,
includeLocalVariables: true,
integrations: [localVariables],
integrations: [],
});

const client = new NodeClient(options);
client.setupIntegrations(true);
client.addIntegration(localVariables);

await session.runPause(exceptionEvent);
await session.runPause(exceptionEvent);
Expand Down
11 changes: 10 additions & 1 deletion packages/types/src/client.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -151,9 +151,18 @@ export interface Client<O extends ClientOptions = ClientOptions> {
* */
addIntegration?(integration: Integration): void;

/** This is an internal function to setup all integrations that should run on the client */
/**
* This is an internal function to setup all integrations that should run on the client.
* @deprecated Use `client.init()` instead.
*/
setupIntegrations(forceInitialize?: boolean): void;

/**
* Initialize this client.
* Call this after the client was set on a scope.
*/
init?(): void;

/** Creates an {@link Event} from all inputs to `captureException` and non-primitive inputs to `captureMessage`. */
// eslint-disable-next-line @typescript-eslint/no-explicit-any
eventFromException(exception: any, hint?: EventHint): PromiseLike<Event>;
Expand Down