Skip to content

fix(bun): Includes correct sdk metadata #15459

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Feb 20, 2025
Merged
Show file tree
Hide file tree
Changes from 3 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
5 changes: 1 addition & 4 deletions packages/bun/src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,7 @@ import { ServerRuntimeClient, applySdkMetadata } from '@sentry/core';
import type { BunClientOptions } from './types';

/**
* The Sentry Bun SDK Client.
*
* @see BunClientOptions for documentation on configuration options.
* @see SentryClient for usage documentation.
* @deprecated This client is no longer used in v9.
*/
export class BunClient extends ServerRuntimeClient<BunClientOptions> {
/**
Expand Down
1 change: 1 addition & 0 deletions packages/bun/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ export {

export type { BunOptions } from './types';

// eslint-disable-next-line deprecation/deprecation
export { BunClient } from './client';
export { getDefaultIntegrations, init } from './sdk';
export { bunServerIntegration } from './integrations/bunserver';
Expand Down
15 changes: 12 additions & 3 deletions packages/bun/src/sdk.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {
applySdkMetadata,
functionToStringIntegration,
inboundFiltersIntegration,
linkedErrorsIntegration,
Expand All @@ -17,8 +18,8 @@ import {
onUncaughtExceptionIntegration,
onUnhandledRejectionIntegration,
} from '@sentry/node';
import * as os from 'node:os';

import { BunClient } from './client';
import { bunServerIntegration } from './integrations/bunserver';
import { makeFetchTransport } from './transports';
import type { BunOptions } from './types';
Expand Down Expand Up @@ -92,8 +93,16 @@ export function getDefaultIntegrations(_options: Options): Integration[] {
*
* @see {@link BunOptions} for documentation on configuration options.
*/
export function init(options: BunOptions = {}): NodeClient | undefined {
options.clientClass = BunClient;
export function init(userOptions: BunOptions = {}): NodeClient | undefined {
applySdkMetadata(userOptions, 'bun');

const options = {
...userOptions,
platform: 'javascript',
runtime: { name: 'bun', version: Bun.version },
serverName: userOptions.serverName || global.process.env.SENTRY_NAME || os.hostname(),
};

options.transport = options.transport || makeFetchTransport;

if (options.defaultIntegrations === undefined) {
Expand Down
9 changes: 0 additions & 9 deletions packages/bun/src/types.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import type { ClientOptions, Options, TracePropagationTargets } from '@sentry/core';

import type { BunClient } from './client';
import type { BunTransportOptions } from './transports';

export interface BaseBunOptions {
Expand All @@ -25,14 +24,6 @@ export interface BaseBunOptions {
/** Sets an optional server name (device name) */
serverName?: string;

/**
* Specify a custom BunClient to be used. Must extend BunClient!
* This is not a public, supported API, but used internally only.
*
* @hidden
* */
clientClass?: typeof BunClient;

/** Callback that is executed when a fatal global error occurs. */
onFatalError?(this: void, error: Error): void;
}
Expand Down
21 changes: 10 additions & 11 deletions packages/bun/test/integrations/bunserver.test.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { afterEach, beforeAll, beforeEach, describe, expect, test } from 'bun:test';
import type { Span } from '@sentry/core';
import { getDynamicSamplingContextFromSpan, setCurrentClient, spanIsSampled, spanToJSON } from '@sentry/core';
import { getDynamicSamplingContextFromSpan, spanIsSampled, spanToJSON } from '@sentry/core';

import { BunClient } from '../../src/client';
import { init } from '../../src';
import type { NodeClient } from '../../src';
import { instrumentBunServe } from '../../src/integrations/bunserver';
import { getDefaultBunClientOptions } from '../helpers';

describe('Bun Serve Integration', () => {
let client: BunClient;
let client: NodeClient | undefined;
// Fun fact: Bun = 2 21 14 :)
let port: number = 22114;

Expand All @@ -17,9 +18,7 @@ describe('Bun Serve Integration', () => {

beforeEach(() => {
const options = getDefaultBunClientOptions({ tracesSampleRate: 1 });
client = new BunClient(options);
setCurrentClient(client);
client.init();
client = init(options);
});

afterEach(() => {
Expand All @@ -31,7 +30,7 @@ describe('Bun Serve Integration', () => {
test('generates a transaction around a request', async () => {
let generatedSpan: Span | undefined;

client.on('spanEnd', span => {
client?.on('spanEnd', span => {
generatedSpan = span;
});

Expand Down Expand Up @@ -66,7 +65,7 @@ describe('Bun Serve Integration', () => {
test('generates a post transaction', async () => {
let generatedSpan: Span | undefined;

client.on('spanEnd', span => {
client?.on('spanEnd', span => {
generatedSpan = span;
});

Expand Down Expand Up @@ -103,7 +102,7 @@ describe('Bun Serve Integration', () => {

let generatedSpan: Span | undefined;

client.on('spanEnd', span => {
client?.on('spanEnd', span => {
generatedSpan = span;
});

Expand Down Expand Up @@ -139,7 +138,7 @@ describe('Bun Serve Integration', () => {
test('does not create transactions for OPTIONS or HEAD requests', async () => {
let generatedSpan: Span | undefined;

client.on('spanEnd', span => {
client?.on('spanEnd', span => {
generatedSpan = span;
});

Expand All @@ -165,7 +164,7 @@ describe('Bun Serve Integration', () => {

test('intruments the server again if it is reloaded', async () => {
let serverWasInstrumented = false;
client.on('spanEnd', () => {
client?.on('spanEnd', () => {
serverWasInstrumented = true;
});

Expand Down
41 changes: 36 additions & 5 deletions packages/bun/test/sdk.test.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,51 @@
import { describe, expect, test } from 'bun:test';

import type { NodeClient } from '../src/index';
import { init } from '../src/index';
import type { BaseTransportOptions, Envelope, Transport, TransportMakeRequestResponse, Event } from '@sentry/core';

const envelopes: Envelope[] = [];

function testTransport(_options: BaseTransportOptions): Transport {
return {
send(request: Envelope): Promise<TransportMakeRequestResponse> {
envelopes.push(request);
return Promise.resolve({ statusCode: 200 });
},
flush(): PromiseLike<boolean> {
return new Promise(resolve => setTimeout(() => resolve(true), 100));
},
};
}

describe('Bun SDK', () => {
const initOptions = {
dsn: 'https://[email protected]/0000000',
tracesSampleRate: 1,
transport: testTransport,
};

test("calling init shouldn't fail", () => {
test('SDK works as expected', async () => {
let client: NodeClient | undefined;
expect(() => {
init(initOptions);
client = init(initOptions);
}).not.toThrow();
});

test('should return client from init', () => {
expect(init(initOptions)).not.toBeUndefined();
expect(client).not.toBeUndefined();

client?.captureException(new Error('test'));
client?.flush();

await new Promise(resolve => setTimeout(resolve, 1000));

expect(envelopes.length).toBe(1);

const envelope = envelopes[0];
const event = envelope?.[1][0][1] as Event;

expect(event.sdk?.name).toBe('sentry.javascript.bun');

expect(event.exception?.values?.[0]?.type).toBe('Error');
expect(event.exception?.values?.[0]?.value).toBe('test');
});
});
Loading