Skip to content

Commit ee4e37e

Browse files
authored
fix(sveltekit): Only instrument SvelteKit fetch if the SDK client is valid (#8381)
In the client-side SvelteKit fetch instrumentation, our previous type cast when retrieving the SDK client was wrong, causing us to not guard the fetch instrumentation correctly if the client was undefined. This fix adds an undefined check. fixes #8290
1 parent da2487e commit ee4e37e

File tree

2 files changed

+48
-11
lines changed

2 files changed

+48
-11
lines changed

packages/sveltekit/src/client/load.ts

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import type { BaseClient } from '@sentry/core';
33
import { getCurrentHub, trace } from '@sentry/core';
44
import type { Breadcrumbs, BrowserTracing } from '@sentry/svelte';
55
import { captureException } from '@sentry/svelte';
6-
import type { ClientOptions, SanitizedRequestData } from '@sentry/types';
6+
import type { Client, ClientOptions, SanitizedRequestData } from '@sentry/types';
77
import {
88
addExceptionMechanism,
99
addNonEnumerableProperty,
@@ -122,12 +122,14 @@ type SvelteKitFetch = LoadEvent['fetch'];
122122
* @returns a proxy of SvelteKit's fetch implementation
123123
*/
124124
function instrumentSvelteKitFetch(originalFetch: SvelteKitFetch): SvelteKitFetch {
125-
const client = getCurrentHub().getClient() as BaseClient<ClientOptions>;
125+
const client = getCurrentHub().getClient();
126126

127-
const browserTracingIntegration =
128-
client.getIntegrationById && (client.getIntegrationById('BrowserTracing') as BrowserTracing | undefined);
129-
const breadcrumbsIntegration =
130-
client.getIntegrationById && (client.getIntegrationById('Breadcrumbs') as Breadcrumbs | undefined);
127+
if (!isValidClient(client)) {
128+
return originalFetch;
129+
}
130+
131+
const browserTracingIntegration = client.getIntegrationById('BrowserTracing') as BrowserTracing | undefined;
132+
const breadcrumbsIntegration = client.getIntegrationById('Breadcrumbs') as Breadcrumbs | undefined;
131133

132134
const browserTracingOptions = browserTracingIntegration && browserTracingIntegration.options;
133135

@@ -270,3 +272,14 @@ function addFetchBreadcrumb(
270272
},
271273
);
272274
}
275+
276+
type MaybeClientWithGetIntegrationsById =
277+
| (Client & { getIntegrationById?: BaseClient<ClientOptions>['getIntegrationById'] })
278+
| undefined;
279+
280+
type ClientWithGetIntegrationById = Required<MaybeClientWithGetIntegrationsById> &
281+
Exclude<MaybeClientWithGetIntegrationsById, undefined>;
282+
283+
function isValidClient(client: MaybeClientWithGetIntegrationsById): client is ClientWithGetIntegrationById {
284+
return !!client && typeof client.getIntegrationById === 'function';
285+
}

packages/sveltekit/test/client/load.test.ts

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,12 @@ const mockedGetIntegrationById = vi.fn(id => {
5252
return undefined;
5353
});
5454

55+
const mockedGetClient = vi.fn(() => {
56+
return {
57+
getIntegrationById: mockedGetIntegrationById,
58+
};
59+
});
60+
5561
vi.mock('@sentry/core', async () => {
5662
const original = (await vi.importActual('@sentry/core')) as any;
5763
return {
@@ -62,11 +68,7 @@ vi.mock('@sentry/core', async () => {
6268
},
6369
getCurrentHub: () => {
6470
return {
65-
getClient: () => {
66-
return {
67-
getIntegrationById: mockedGetIntegrationById,
68-
};
69-
},
71+
getClient: mockedGetClient,
7072
getScope: () => {
7173
return {
7274
getSpan: () => {
@@ -427,6 +429,28 @@ describe('wrapLoadWithSentry', () => {
427429
});
428430
});
429431

432+
it.each([
433+
['is undefined', undefined],
434+
["doesn't have a `getClientById` method", {}],
435+
])("doesn't instrument fetch if the client %s", async (_, client) => {
436+
// @ts-expect-error: we're mocking the client
437+
mockedGetClient.mockImplementationOnce(() => client);
438+
439+
async function load(_event: Parameters<Load>[0]): Promise<ReturnType<Load>> {
440+
return {
441+
msg: 'hi',
442+
};
443+
}
444+
const wrappedLoad = wrapLoadWithSentry(load);
445+
446+
const originalFetch = MOCK_LOAD_ARGS.fetch;
447+
await wrappedLoad(MOCK_LOAD_ARGS);
448+
449+
expect(MOCK_LOAD_ARGS.fetch).toStrictEqual(originalFetch);
450+
451+
expect(mockTrace).toHaveBeenCalledTimes(1);
452+
});
453+
430454
it('adds an exception mechanism', async () => {
431455
const addEventProcessorSpy = vi.spyOn(mockScope, 'addEventProcessor').mockImplementationOnce(callback => {
432456
void callback({}, { event_id: 'fake-event-id' });

0 commit comments

Comments
 (0)