diff --git a/packages/astro/src/integration/index.ts b/packages/astro/src/integration/index.ts index 303251b9a933..34841a838983 100644 --- a/packages/astro/src/integration/index.ts +++ b/packages/astro/src/integration/index.ts @@ -24,9 +24,14 @@ export const sentryAstro = (options: SentryOptions = {}): AstroIntegration => { // Will revisit this later. const env = process.env; - const uploadOptions = options.sourceMapsUploadOptions || {}; + const sdkEnabled = { + client: typeof options.enabled === 'boolean' ? options.enabled : options.enabled?.client ?? true, + server: typeof options.enabled === 'boolean' ? options.enabled : options.enabled?.server ?? true, + }; - const shouldUploadSourcemaps = uploadOptions?.enabled ?? true; + const sourceMapsNeeded = sdkEnabled.client || sdkEnabled.server; + const uploadOptions = options.sourceMapsUploadOptions || {}; + const shouldUploadSourcemaps = (sourceMapsNeeded && uploadOptions?.enabled) ?? true; // We don't need to check for AUTH_TOKEN here, because the plugin will pick it up from the env if (shouldUploadSourcemaps && command !== 'dev') { @@ -51,31 +56,35 @@ export const sentryAstro = (options: SentryOptions = {}): AstroIntegration => { }); } - const pathToClientInit = options.clientInitPath - ? path.resolve(options.clientInitPath) - : findDefaultSdkInitFile('client'); - const pathToServerInit = options.serverInitPath - ? path.resolve(options.serverInitPath) - : findDefaultSdkInitFile('server'); - - if (pathToClientInit) { - options.debug && console.log(`[sentry-astro] Using ${pathToClientInit} for client init.`); - injectScript('page', buildSdkInitFileImportSnippet(pathToClientInit)); - } else { - options.debug && console.log('[sentry-astro] Using default client init.'); - injectScript('page', buildClientSnippet(options || {})); + if (sdkEnabled.client) { + const pathToClientInit = options.clientInitPath + ? path.resolve(options.clientInitPath) + : findDefaultSdkInitFile('client'); + + if (pathToClientInit) { + options.debug && console.log(`[sentry-astro] Using ${pathToClientInit} for client init.`); + injectScript('page', buildSdkInitFileImportSnippet(pathToClientInit)); + } else { + options.debug && console.log('[sentry-astro] Using default client init.'); + injectScript('page', buildClientSnippet(options || {})); + } } - if (pathToServerInit) { - options.debug && console.log(`[sentry-astro] Using ${pathToServerInit} for server init.`); - injectScript('page-ssr', buildSdkInitFileImportSnippet(pathToServerInit)); - } else { - options.debug && console.log('[sentry-astro] Using default server init.'); - injectScript('page-ssr', buildServerSnippet(options || {})); + if (sdkEnabled.server) { + const pathToServerInit = options.serverInitPath + ? path.resolve(options.serverInitPath) + : findDefaultSdkInitFile('server'); + if (pathToServerInit) { + options.debug && console.log(`[sentry-astro] Using ${pathToServerInit} for server init.`); + injectScript('page-ssr', buildSdkInitFileImportSnippet(pathToServerInit)); + } else { + options.debug && console.log('[sentry-astro] Using default server init.'); + injectScript('page-ssr', buildServerSnippet(options || {})); + } } const isSSR = config && (config.output === 'server' || config.output === 'hybrid'); - const shouldAddMiddleware = options.autoInstrumentation?.requestHandler !== false; + const shouldAddMiddleware = sdkEnabled.server && options.autoInstrumentation?.requestHandler !== false; // Guarding calling the addMiddleware function because it was only introduced in astro@3.5.0 // Users on older versions of astro will need to add the middleware manually. diff --git a/packages/astro/src/integration/types.ts b/packages/astro/src/integration/types.ts index 8c069a2516a7..6f182427ee47 100644 --- a/packages/astro/src/integration/types.ts +++ b/packages/astro/src/integration/types.ts @@ -106,6 +106,26 @@ type InstrumentationOptions = { }; }; +type SdkEnabledOptions = { + /** + * Controls if the Sentry SDK is enabled or not. + * + * You can either set a boolean value to enable/disable the SDK for both client and server, + * or pass an object with `client` and `server` properties to enable/disable the SDK. + * + * If the SDK is disabled, no data will be caught or sent to Sentry. In this case, also no + * Sentry code will be added to your bundle. + * + * @default true - the SDK is enabled by default for both, client and server. + */ + enabled?: + | boolean + | { + client?: boolean; + server?: boolean; + }; +}; + /** * A subset of Sentry SDK options that can be set via the `sentryAstro` integration. * Some options (e.g. integrations) are set by default and cannot be changed here. @@ -119,4 +139,5 @@ export type SentryOptions = SdkInitPaths & Pick & Pick & SourceMapsOptions & - InstrumentationOptions; + InstrumentationOptions & + SdkEnabledOptions; diff --git a/packages/astro/test/integration/index.test.ts b/packages/astro/test/integration/index.test.ts index 5b8be17496c0..3e95c0c932f0 100644 --- a/packages/astro/test/integration/index.test.ts +++ b/packages/astro/test/integration/index.test.ts @@ -168,8 +168,21 @@ describe('sentryAstro integration', () => { expect(sentryVitePluginSpy).toHaveBeenCalledTimes(0); }); - it('injects client and server init scripts', async () => { - const integration = sentryAstro({}); + it("doesn't add the plugin or enable source maps if the SDK is disabled", async () => { + const integration = sentryAstro({ + enabled: false, + }); + + expect(integration.hooks['astro:config:setup']).toBeDefined(); + // @ts-expect-error - the hook exists and we only need to pass what we actually use + await integration.hooks['astro:config:setup']({ updateConfig, injectScript, config }); + + expect(updateConfig).toHaveBeenCalledTimes(0); + expect(sentryVitePluginSpy).toHaveBeenCalledTimes(0); + }); + + it.each([{}, { enabled: true }])('injects client and server init scripts', async options => { + const integration = sentryAstro(options); expect(integration.hooks['astro:config:setup']).toBeDefined(); // @ts-expect-error - the hook exists and we only need to pass what we actually use @@ -180,6 +193,41 @@ describe('sentryAstro integration', () => { expect(injectScript).toHaveBeenCalledWith('page-ssr', expect.stringContaining('Sentry.init')); }); + it("doesn't inject client init script if `enabled.client` is `false`", async () => { + const integration = sentryAstro({ enabled: { client: false } }); + + expect(integration.hooks['astro:config:setup']).toBeDefined(); + // @ts-expect-error - the hook exists and we only need to pass what we actually use + await integration.hooks['astro:config:setup']({ updateConfig, injectScript, config }); + + expect(injectScript).toHaveBeenCalledTimes(1); + expect(injectScript).toHaveBeenCalledWith('page-ssr', expect.stringContaining('Sentry.init')); + }); + + it("doesn't inject server init script if `enabled.server` is `false`", async () => { + const integration = sentryAstro({ enabled: { server: false } }); + + expect(integration.hooks['astro:config:setup']).toBeDefined(); + // @ts-expect-error - the hook exists and we only need to pass what we actually use + await integration.hooks['astro:config:setup']({ updateConfig, injectScript, config }); + + expect(injectScript).toHaveBeenCalledTimes(1); + expect(injectScript).toHaveBeenCalledWith('page', expect.stringContaining('Sentry.init')); + }); + + it.each([false, { client: false, server: false }])( + "doesn't inject any init script if `enabled` is generally false (`%s`)", + async enabled => { + const integration = sentryAstro({ enabled }); + + expect(integration.hooks['astro:config:setup']).toBeDefined(); + // @ts-expect-error - the hook exists and we only need to pass what we actually use + await integration.hooks['astro:config:setup']({ updateConfig, injectScript, config }); + + expect(injectScript).toHaveBeenCalledTimes(0); + }, + ); + it('injects client and server init scripts from custom paths', async () => { const integration = sentryAstro({ clientInitPath: 'my-client-init-path.js', @@ -278,4 +326,23 @@ describe('sentryAstro integration', () => { expect(updateConfig).toHaveBeenCalledTimes(1); expect(injectScript).toHaveBeenCalledTimes(2); }); + + it("doesn't add middleware if the SDK is disabled", () => { + const integration = sentryAstro({ enabled: false }); + const addMiddleware = vi.fn(); + const updateConfig = vi.fn(); + const injectScript = vi.fn(); + + expect(integration.hooks['astro:config:setup']).toBeDefined(); + // @ts-expect-error - the hook exists and we only need to pass what we actually use + integration.hooks['astro:config:setup']({ + // @ts-expect-error - we only need to pass what we actually use + config: { output: 'server' }, + addMiddleware, + updateConfig, + injectScript, + }); + + expect(addMiddleware).toHaveBeenCalledTimes(0); + }); });