Skip to content

Commit b2aa011

Browse files
authored
feat(hono): Add warning in Bun for double init (#21195)
Reference #21176
1 parent 02cd482 commit b2aa011

2 files changed

Lines changed: 60 additions & 2 deletions

File tree

packages/hono/src/bun/sdk.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { Client } from '@sentry/core';
2-
import { applySdkMetadata } from '@sentry/core';
2+
import { applySdkMetadata, consoleSandbox, getClient } from '@sentry/core';
33
import { init as initBun } from '@sentry/bun';
44
import type { HonoBunOptions } from './middleware';
55
import { buildFilteredIntegrations } from '../shared/buildFilteredIntegrations';
@@ -12,6 +12,15 @@ import { buildFilteredIntegrations } from '../shared/buildFilteredIntegrations';
1212
* When manually calling `init`, add the `honoIntegration` to the `integrations` array to set up the Hono integration.
1313
*/
1414
export function init(options: HonoBunOptions): Client | undefined {
15+
if (getClient()) {
16+
consoleSandbox(() => {
17+
// eslint-disable-next-line no-console
18+
console.warn(
19+
'[Sentry] Sentry is already initialized. Sentry should only be initialized once, through the `sentry()` middleware. Remove the `Sentry.init()` call, if one exists.',
20+
);
21+
});
22+
}
23+
1524
applySdkMetadata(options, 'hono', ['hono', 'bun']);
1625

1726
// Remove Hono from the SDK defaults to prevent double instrumentation: @sentry/bun

packages/hono/test/bun/middleware.test.ts

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { SDK_VERSION } from '@sentry/core';
33
import { Hono } from 'hono';
44
import { beforeEach, describe, expect, it, type Mock, vi } from 'vitest';
55
import { sentry } from '../../src/bun/middleware';
6+
import { init } from '../../src/bun/sdk';
67

78
vi.mock('@sentry/bun', () => ({
89
init: vi.fn(),
@@ -18,10 +19,14 @@ vi.mock('@sentry/core', async () => {
1819
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
1920
// @ts-ignore
2021
applySdkMetadata: vi.fn(actual.applySdkMetadata),
22+
getClient: vi.fn(() => undefined),
23+
// Pass-through so console.warn calls inside consoleSandbox are observable in tests
24+
consoleSandbox: vi.fn((cb: () => unknown) => cb()),
2125
};
2226
});
2327

2428
const applySdkMetadataMock = SentryCore.applySdkMetadata as Mock;
29+
const getClientMock = SentryCore.getClient as Mock;
2530

2631
describe('Hono Bun Middleware', () => {
2732
beforeEach(() => {
@@ -51,7 +56,8 @@ describe('Hono Bun Middleware', () => {
5156
expect(applySdkMetadataMock).toHaveBeenCalledWith(options, 'hono', ['hono', 'bun']);
5257
});
5358

54-
it('calls init from @sentry/bun', () => {
59+
it('calls init from @sentry/bun when no client exists yet', () => {
60+
getClientMock.mockReturnValue(undefined);
5561
const app = new Hono();
5662
const options = {
5763
dsn: 'https://public@dsn.ingest.sentry.io/1337',
@@ -156,4 +162,47 @@ describe('Hono Bun Middleware', () => {
156162
);
157163
});
158164
});
165+
166+
describe('double-init guard', () => {
167+
it('still calls init even when Sentry is already initialized', () => {
168+
const fakeClient = { getOptions: () => ({}) };
169+
getClientMock.mockReturnValue(fakeClient as unknown as SentryCore.Client);
170+
171+
const app = new Hono();
172+
sentry(app, { dsn: 'https://public@dsn.ingest.sentry.io/1337' });
173+
174+
expect(initBunMock).toHaveBeenCalledTimes(1);
175+
});
176+
177+
it('emits a console.warn directing to remove the duplicate init call when Sentry is already initialized', () => {
178+
const warnSpy = vi.spyOn(console, 'warn');
179+
const fakeClient = { getOptions: () => ({}) };
180+
getClientMock.mockReturnValue(fakeClient as unknown as SentryCore.Client);
181+
182+
const app = new Hono();
183+
sentry(app, { dsn: 'https://public@dsn.ingest.sentry.io/1337' });
184+
185+
expect(warnSpy).toHaveBeenCalledTimes(1);
186+
expect(warnSpy).toHaveBeenCalledWith(expect.stringContaining('Sentry is already initialized'));
187+
expect(warnSpy).toHaveBeenCalledWith(expect.stringContaining('Remove the `Sentry.init()` call'));
188+
});
189+
190+
it('does not emit a console.warn when no client exists yet', () => {
191+
const warnSpy = vi.spyOn(console, 'warn');
192+
getClientMock.mockReturnValue(undefined);
193+
194+
const app = new Hono();
195+
sentry(app, { dsn: 'https://public@dsn.ingest.sentry.io/1337' });
196+
197+
expect(warnSpy).not.toHaveBeenCalled();
198+
});
199+
200+
it('always calls init regardless of whether a client already exists', () => {
201+
getClientMock.mockReturnValue(undefined);
202+
203+
init({ dsn: 'https://public@dsn.ingest.sentry.io/1337' });
204+
205+
expect(initBunMock).toHaveBeenCalledTimes(1);
206+
});
207+
});
159208
});

0 commit comments

Comments
 (0)