From 79d923189e4419087ecda1f5104ab737ea54462b Mon Sep 17 00:00:00 2001 From: Charly Gomez Date: Mon, 11 May 2026 13:32:56 +0200 Subject: [PATCH] add application key top level --- .../src/config/getBuildPluginOptions.ts | 1 + .../turbopack/constructTurbopackConfig.ts | 3 +- packages/nextjs/src/config/types.ts | 16 ++++++++- .../test/config/getBuildPluginOptions.test.ts | 15 +++++++++ .../constructTurbopackConfig.test.ts | 33 +++++++++++++++++++ 5 files changed, 66 insertions(+), 2 deletions(-) diff --git a/packages/nextjs/src/config/getBuildPluginOptions.ts b/packages/nextjs/src/config/getBuildPluginOptions.ts index 5018e1b4b196..e616c49263af 100644 --- a/packages/nextjs/src/config/getBuildPluginOptions.ts +++ b/packages/nextjs/src/config/getBuildPluginOptions.ts @@ -309,6 +309,7 @@ export function getBuildPluginOptions({ const skipSourcemapsUpload = shouldSkipSourcemapUpload(buildTool, useRunAfterProductionCompileHook); return { + applicationKey: sentryBuildOptions.applicationKey, authToken: sentryBuildOptions.authToken, headers: sentryBuildOptions.headers, org: sentryBuildOptions.org, diff --git a/packages/nextjs/src/config/turbopack/constructTurbopackConfig.ts b/packages/nextjs/src/config/turbopack/constructTurbopackConfig.ts index 31530f07c042..bf919e644754 100644 --- a/packages/nextjs/src/config/turbopack/constructTurbopackConfig.ts +++ b/packages/nextjs/src/config/turbopack/constructTurbopackConfig.ts @@ -66,7 +66,8 @@ export function constructTurbopackConfig({ // so it is safe even for node_modules with strict initialization order. // We only exclude Next.js build polyfills which contain non-standard syntax that causes // parse errors when any code is prepended (Turbopack re-parses the loader output). - const applicationKey = userSentryOptions?._experimental?.turbopackApplicationKey; + // eslint-disable-next-line deprecation/deprecation + const applicationKey = userSentryOptions?.applicationKey ?? userSentryOptions?._experimental?.turbopackApplicationKey; if (applicationKey && nextJsVersion && supportsTurbopackRuleCondition(nextJsVersion)) { newConfig.rules = safelyAddTurbopackRule(newConfig.rules, { matcher: '*.{ts,tsx,js,jsx,mjs,cjs}', diff --git a/packages/nextjs/src/config/types.ts b/packages/nextjs/src/config/types.ts index 86068841e773..722c3f58f570 100644 --- a/packages/nextjs/src/config/types.ts +++ b/packages/nextjs/src/config/types.ts @@ -463,6 +463,18 @@ export type SentryBuildOptions = { }; }; + /** + * A key that is used to identify the application in the Sentry bundler plugins. + * This key is used by the `thirdPartyErrorFilterIntegration` to filter out errors + * originating from third-party scripts. + * + * For webpack builds, this is forwarded to the `@sentry/webpack-plugin`. + * For Turbopack builds, this injects module metadata via a custom loader. + * + * @see https://docs.sentry.io/platforms/javascript/configuration/filtering/#using-thirdpartyerrorfilterintegration + */ + applicationKey?: string; + /** * Options to configure various bundle size optimizations related to the Sentry SDK. */ @@ -738,8 +750,10 @@ export type SentryBuildOptions = { * webpack builds via its `moduleMetadata` / `applicationKey` option. * * Requires Next.js 16+ + * + * @deprecated Use the top-level `applicationKey` option instead, which works for both webpack and Turbopack builds. */ - turbopackApplicationKey?: string; + turbopackApplicationKey?: string; // TODO(v11): remove this option /** * Options for React component name annotation in Turbopack builds. * When enabled, JSX elements are annotated with `data-sentry-component`, diff --git a/packages/nextjs/test/config/getBuildPluginOptions.test.ts b/packages/nextjs/test/config/getBuildPluginOptions.test.ts index c67135a5d8d3..0b8a729e5942 100644 --- a/packages/nextjs/test/config/getBuildPluginOptions.test.ts +++ b/packages/nextjs/test/config/getBuildPluginOptions.test.ts @@ -61,6 +61,21 @@ describe('getBuildPluginOptions', () => { }); }); + it('forwards applicationKey to plugin options', () => { + const sentryBuildOptions: SentryBuildOptions = { + applicationKey: 'my-app-key', + }; + + const result = getBuildPluginOptions({ + sentryBuildOptions, + releaseName: mockReleaseName, + distDirAbsPath: mockDistDirAbsPath, + buildTool: 'after-production-compile-webpack', + }); + + expect(result.applicationKey).toBe('my-app-key'); + }); + it('normalizes Windows paths to posix for glob patterns in after-production-compile builds', () => { const windowsPath = 'C:\\Users\\test\\.next'; const sentryBuildOptions: SentryBuildOptions = { diff --git a/packages/nextjs/test/config/turbopack/constructTurbopackConfig.test.ts b/packages/nextjs/test/config/turbopack/constructTurbopackConfig.test.ts index 663317a8bd69..242174f015de 100644 --- a/packages/nextjs/test/config/turbopack/constructTurbopackConfig.test.ts +++ b/packages/nextjs/test/config/turbopack/constructTurbopackConfig.test.ts @@ -977,6 +977,39 @@ describe('moduleMetadataInjection with applicationKey', () => { }); }); + it('should add metadata loader rule when top-level applicationKey is set and Next.js >= 16', () => { + const userNextConfig: NextConfigObject = {}; + + const result = constructTurbopackConfig({ + userNextConfig, + userSentryOptions: { applicationKey: 'my-top-level-key' }, + nextJsVersion: '16.0.0', + }); + + const rule = result.rules!['*.{ts,tsx,js,jsx,mjs,cjs}'] as { + loaders: Array<{ loader: string; options: { applicationKey: string } }>; + }; + expect(rule.loaders[0]!.options.applicationKey).toBe('my-top-level-key'); + }); + + it('should prefer top-level applicationKey over deprecated _experimental.turbopackApplicationKey', () => { + const userNextConfig: NextConfigObject = {}; + + const result = constructTurbopackConfig({ + userNextConfig, + userSentryOptions: { + applicationKey: 'top-level-key', + _experimental: { turbopackApplicationKey: 'deprecated-key' }, + }, + nextJsVersion: '16.0.0', + }); + + const rule = result.rules!['*.{ts,tsx,js,jsx,mjs,cjs}'] as { + loaders: Array<{ loader: string; options: { applicationKey: string } }>; + }; + expect(rule.loaders[0]!.options.applicationKey).toBe('top-level-key'); + }); + it('should only exclude Next.js polyfills, not all foreign modules', () => { const userNextConfig: NextConfigObject = {};