From fe8393acf0ca0918bbb31419e8e7b1eaf6966521 Mon Sep 17 00:00:00 2001 From: s1gr1d Date: Wed, 22 Oct 2025 17:23:32 +0200 Subject: [PATCH 1/3] create types for commit options --- .../buildTimeOptionsBase.ts | 63 ++++++++++--------- 1 file changed, 32 insertions(+), 31 deletions(-) diff --git a/packages/core/src/build-time-plugins/buildTimeOptionsBase.ts b/packages/core/src/build-time-plugins/buildTimeOptionsBase.ts index e43160cc03ab..eafbd101e0f5 100644 --- a/packages/core/src/build-time-plugins/buildTimeOptionsBase.ts +++ b/packages/core/src/build-time-plugins/buildTimeOptionsBase.ts @@ -243,6 +243,37 @@ interface SourceMapsOptions { filesToDeleteAfterUpload?: string | Array; } +type AutoSetCommitsOptions = { + /** + * Automatically sets `commit` and `previousCommit`. Sets `commit` to `HEAD` + * and `previousCommit` as described in the option's documentation. + * + * If you set this to `true`, manually specified `commit` and `previousCommit` + * options will be overridden. It is best to not specify them at all if you + * set this option to `true`. + */ + auto: true; + repo?: undefined; + commit?: undefined; +}; + +type ManualSetCommitsOptions = { + auto?: false | undefined; + /** + * The full repo name as defined in Sentry. + * + * Required if the `auto` option is not set to `true`. + */ + repo: string; + + /** + * The current (last) commit in the release. + * + * Required if the `auto` option is not set to `true`. + */ + commit: string; +}; + interface ReleaseOptions { /** * Unique identifier for the release you want to create. @@ -300,37 +331,7 @@ interface ReleaseOptions { /** * Configuration for associating the release with its commits in Sentry. */ - setCommits?: ( - | { - /** - * Automatically sets `commit` and `previousCommit`. Sets `commit` to `HEAD` - * and `previousCommit` as described in the option's documentation. - * - * If you set this to `true`, manually specified `commit` and `previousCommit` - * options will be overridden. It is best to not specify them at all if you - * set this option to `true`. - */ - auto: true; - repo?: undefined; - commit?: undefined; - } - | { - auto?: false | undefined; - /** - * The full repo name as defined in Sentry. - * - * Required if the `auto` option is not set to `true`. - */ - repo: string; - - /** - * The current (last) commit in the release. - * - * Required if the `auto` option is not set to `true`. - */ - commit: string; - } - ) & { + setCommits?: (AutoSetCommitsOptions | ManualSetCommitsOptions) & { /** * The commit before the beginning of this release (in other words, * the last commit of the previous release). From b3d44bef992e9a0f05d0fd98d9e3940cfe78c041 Mon Sep 17 00:00:00 2001 From: s1gr1d Date: Thu, 23 Oct 2025 14:55:03 +0200 Subject: [PATCH 2/3] feat(react-router): Align options with shared build time options type --- .../buildTimeOptionsBase.ts | 76 +++++---- packages/react-router/.eslintrc.js | 2 +- .../src/vite/buildEnd/handleOnBuildEnd.ts | 33 +++- packages/react-router/src/vite/plugin.ts | 4 +- packages/react-router/src/vite/types.ts | 156 ++++-------------- .../test/client/tracingIntegration.test.ts | 1 + .../server/createSentryHandleRequest.test.ts | 7 +- .../instrumentation/reactRouterServer.test.ts | 3 + .../vite/buildEnd/handleOnBuildEnd.test.ts | 13 ++ .../react-router/test/vite/types.test-d.ts | 114 +++++++++++++ packages/react-router/tsconfig.test.json | 2 +- packages/react-router/tsconfig.vite.json | 9 + packages/react-router/vite.config.ts | 4 + 13 files changed, 250 insertions(+), 174 deletions(-) create mode 100644 packages/react-router/test/vite/types.test-d.ts create mode 100644 packages/react-router/tsconfig.vite.json diff --git a/packages/core/src/build-time-plugins/buildTimeOptionsBase.ts b/packages/core/src/build-time-plugins/buildTimeOptionsBase.ts index eafbd101e0f5..29e606781786 100644 --- a/packages/core/src/build-time-plugins/buildTimeOptionsBase.ts +++ b/packages/core/src/build-time-plugins/buildTimeOptionsBase.ts @@ -330,8 +330,12 @@ interface ReleaseOptions { /** * Configuration for associating the release with its commits in Sentry. + * + * Set to `false` to disable commit association. + * + * @default { auto: true } */ - setCommits?: (AutoSetCommitsOptions | ManualSetCommitsOptions) & { + setCommits?: false | (AutoSetCommitsOptions | ManualSetCommitsOptions) & { /** * The commit before the beginning of this release (in other words, * the last commit of the previous release). @@ -362,39 +366,43 @@ interface ReleaseOptions { /** * Configuration for adding deployment information to the release in Sentry. - */ - deploy?: { - /** - * Environment for this release. Values that make sense here would - * be `production` or `staging`. - */ - env: string; - - /** - * Deployment start time in Unix timestamp (in seconds) or ISO 8601 format. - */ - started?: number | string; - - /** - * Deployment finish time in Unix timestamp (in seconds) or ISO 8601 format. - */ - finished?: number | string; - - /** - * Deployment duration (in seconds). Can be used instead of started and finished. - */ - time?: number; - - /** - * Human-readable name for the deployment. - */ - name?: string; - - /** - * URL that points to the deployment. - */ - url?: string; - }; + * + * Set to `false` to disable automatic deployment detection and creation. + */ + deploy?: + | false + | { + /** + * Environment for this release. Values that make sense here would + * be `production` or `staging`. + */ + env: string; + + /** + * Deployment start time in Unix timestamp (in seconds) or ISO 8601 format. + */ + started?: number | string; + + /** + * Deployment finish time in Unix timestamp (in seconds) or ISO 8601 format. + */ + finished?: number | string; + + /** + * Deployment duration (in seconds). Can be used instead of started and finished. + */ + time?: number; + + /** + * Human-readable name for the deployment. + */ + name?: string; + + /** + * URL that points to the deployment. + */ + url?: string; + }; } interface BundleSizeOptimizationsOptions { diff --git a/packages/react-router/.eslintrc.js b/packages/react-router/.eslintrc.js index a22f9710cf6b..e6ea40d78d05 100644 --- a/packages/react-router/.eslintrc.js +++ b/packages/react-router/.eslintrc.js @@ -7,7 +7,7 @@ module.exports = { { files: ['vite.config.ts'], parserOptions: { - project: ['tsconfig.test.json'], + project: ['tsconfig.vite.json'], }, }, ], diff --git a/packages/react-router/src/vite/buildEnd/handleOnBuildEnd.ts b/packages/react-router/src/vite/buildEnd/handleOnBuildEnd.ts index 959578b6d644..a3d1e78cb285 100644 --- a/packages/react-router/src/vite/buildEnd/handleOnBuildEnd.ts +++ b/packages/react-router/src/vite/buildEnd/handleOnBuildEnd.ts @@ -1,6 +1,7 @@ import { rm } from 'node:fs/promises'; import type { Config } from '@react-router/dev/config'; import SentryCli from '@sentry/cli'; +import type { SentryVitePluginOptions } from '@sentry/vite-plugin'; import { glob } from 'glob'; import type { SentryReactRouterBuildOptions } from '../types'; @@ -23,17 +24,31 @@ function getSentryConfig(viteConfig: unknown): SentryReactRouterBuildOptions { export const sentryOnBuildEnd: BuildEndHook = async ({ reactRouterConfig, viteConfig }) => { const sentryConfig = getSentryConfig(viteConfig); + // todo(v11): Remove deprecated sourceMapsUploadOptions support (no need for spread/pick anymore) + const { + sourceMapsUploadOptions, // extract to exclude from rest config + ...sentryConfigWithoutDeprecatedSourceMapOption + } = sentryConfig; + const { authToken, org, project, release, - sourceMapsUploadOptions = { enabled: true }, + sourcemaps = { disable: false }, debug = false, - unstable_sentryVitePluginOptions, - }: SentryReactRouterBuildOptions = { + }: Omit & + // Pick 'sourcemaps' from Vite plugin options as the types allow more (e.g. Promise values for `deleteFilesAfterUpload`) + Pick = { ...sentryConfig.unstable_sentryVitePluginOptions, - ...sentryConfig, + ...sentryConfigWithoutDeprecatedSourceMapOption, // spread in the config without the deprecated sourceMapsUploadOptions + sourcemaps: { + ...sentryConfig.unstable_sentryVitePluginOptions?.sourcemaps, + ...sentryConfig.sourcemaps, + ...sourceMapsUploadOptions, + // eslint-disable-next-line deprecation/deprecation + disable: sourceMapsUploadOptions?.enabled === false ? true : sentryConfig.sourcemaps?.disable, + }, release: { ...sentryConfig.unstable_sentryVitePluginOptions?.release, ...sentryConfig.release, @@ -44,8 +59,9 @@ export const sentryOnBuildEnd: BuildEndHook = async ({ reactRouterConfig, viteCo authToken, org, project, - ...unstable_sentryVitePluginOptions, + ...sentryConfig.unstable_sentryVitePluginOptions, }); + // check if release should be created if (release?.name) { try { @@ -56,7 +72,7 @@ export const sentryOnBuildEnd: BuildEndHook = async ({ reactRouterConfig, viteCo } } - if (sourceMapsUploadOptions?.enabled ?? (true && viteConfig.build.sourcemap !== false)) { + if (!sourcemaps?.disable && viteConfig.build.sourcemap !== false) { // inject debugIds try { await cliInstance.execute( @@ -84,9 +100,10 @@ export const sentryOnBuildEnd: BuildEndHook = async ({ reactRouterConfig, viteCo } } // delete sourcemaps after upload - let updatedFilesToDeleteAfterUpload = sourceMapsUploadOptions?.filesToDeleteAfterUpload; + let updatedFilesToDeleteAfterUpload = await sourcemaps?.filesToDeleteAfterUpload; + // set a default value no option was set - if (typeof sourceMapsUploadOptions?.filesToDeleteAfterUpload === 'undefined') { + if (typeof updatedFilesToDeleteAfterUpload === 'undefined') { updatedFilesToDeleteAfterUpload = [`${reactRouterConfig.buildDirectory}/**/*.map`]; debug && // eslint-disable-next-line no-console diff --git a/packages/react-router/src/vite/plugin.ts b/packages/react-router/src/vite/plugin.ts index 98405771ee1b..8163ee4c6a1b 100644 --- a/packages/react-router/src/vite/plugin.ts +++ b/packages/react-router/src/vite/plugin.ts @@ -14,13 +14,13 @@ import type { SentryReactRouterBuildOptions } from './types'; */ export async function sentryReactRouter( options: SentryReactRouterBuildOptions = {}, - config: ConfigEnv, + viteConfig: ConfigEnv, ): Promise { const plugins: Plugin[] = []; plugins.push(makeConfigInjectorPlugin(options)); - if (process.env.NODE_ENV !== 'development' && config.command === 'build' && config.mode !== 'development') { + if (process.env.NODE_ENV !== 'development' && viteConfig.command === 'build' && viteConfig.mode !== 'development') { plugins.push(makeEnableSourceMapsPlugin(options)); plugins.push(...(await makeCustomSentryVitePlugins(options))); } diff --git a/packages/react-router/src/vite/types.ts b/packages/react-router/src/vite/types.ts index fb488d2ca8bc..c7555630c4fa 100644 --- a/packages/react-router/src/vite/types.ts +++ b/packages/react-router/src/vite/types.ts @@ -1,3 +1,4 @@ +import type { BuildTimeOptionsBase, UnstableVitePluginOptions } from '@sentry/core'; import type { SentryVitePluginOptions } from '@sentry/vite-plugin'; type SourceMapsOptions = { @@ -6,6 +7,7 @@ type SourceMapsOptions = { * automatically generate and upload source maps to Sentry during a production build. * * @default true + * @deprecated Use `sourcemaps.disable` option instead of `sourceMapsUploadOptions.enabled`. */ enabled?: boolean; @@ -16,6 +18,8 @@ type SourceMapsOptions = { * @default [] - By default no files are deleted. * * The globbing patterns follow the implementation of the glob package. (https://www.npmjs.com/package/glob) + * + * @deprecated Use `sourcemaps.filesToDeleteAfterUpload` option instead of `sourceMapsUploadOptions.filesToDeleteAfterUpload`. */ filesToDeleteAfterUpload?: string | Array; @@ -23,7 +27,10 @@ type SourceMapsOptions = { * Options related to managing the Sentry releases for a build. * * More info: https://docs.sentry.io/product/releases/ + * + * @deprecated Use the `release` option at the root of `SentryVitePluginOptions` instead. */ + // todo(v11): Remove this option (currently it's not in use either, but it's kept to not cause a breaking change) release?: { /** * Unique identifier for the release you want to create. @@ -40,136 +47,31 @@ type SourceMapsOptions = { }; }; -type BundleSizeOptimizationOptions = { - /** - * If set to `true`, the plugin will attempt to tree-shake (remove) any debugging code within the Sentry SDK. - * Note that the success of this depends on tree shaking being enabled in your build tooling. - * - * Setting this option to `true` will disable features like the SDK's `debug` option. - */ - excludeDebugStatements?: boolean; - - /** - * If set to true, the plugin will try to tree-shake tracing statements out. - * Note that the success of this depends on tree shaking generally being enabled in your build. - * Attention: DO NOT enable this when you're using any performance monitoring-related SDK features (e.g. Sentry.startSpan()). - */ - excludeTracing?: boolean; - - /** - * If set to `true`, the plugin will attempt to tree-shake (remove) code related to the Sentry SDK's Session Replay Shadow DOM recording functionality. - * Note that the success of this depends on tree shaking being enabled in your build tooling. - * - * This option is safe to be used when you do not want to capture any Shadow DOM activity via Sentry Session Replay. - */ - excludeReplayShadowDom?: boolean; - - /** - * If set to `true`, the plugin will attempt to tree-shake (remove) code related to the Sentry SDK's Session Replay `iframe` recording functionality. - * Note that the success of this depends on tree shaking being enabled in your build tooling. - * - * You can safely do this when you do not want to capture any `iframe` activity via Sentry Session Replay. - */ - excludeReplayIframe?: boolean; - - /** - * If set to `true`, the plugin will attempt to tree-shake (remove) code related to the Sentry SDK's Session Replay's Compression Web Worker. - * Note that the success of this depends on tree shaking being enabled in your build tooling. - * - * **Notice:** You should only do use this option if you manually host a compression worker and configure it in your Sentry Session Replay integration config via the `workerUrl` option. - */ - excludeReplayWorker?: boolean; -}; - -export type SentryReactRouterBuildOptions = { - /** - * Options for configuring the Sentry release. - */ - release?: { - /** - * The name of the release to create in Sentry - */ - name?: string; - }; - - /** - * The auth token to use when uploading source maps to Sentry. - * - * Instead of specifying this option, you can also set the `SENTRY_AUTH_TOKEN` environment variable. - * - * To create an auth token, follow this guide: - * @see https://docs.sentry.io/product/accounts/auth-tokens/#organization-auth-tokens - */ - authToken?: string; - - /** - * The organization slug of your Sentry organization. - * Instead of specifying this option, you can also set the `SENTRY_ORG` environment variable. - */ - org?: string; - - /** - * The project slug of your Sentry project. - * Instead of specifying this option, you can also set the `SENTRY_PROJECT` environment variable. - */ - project?: string; - - /** - * Options for the Sentry Vite plugin to customize bundle size optimizations. - */ - bundleSizeOptimizations?: BundleSizeOptimizationOptions; - - /** - * If this flag is `true`, Sentry will log debug information during build time. - * @default false. - */ - debug?: boolean; - - /** - * Options related to react component name annotations. - * Disabled by default, unless a value is set for this option. - * When enabled, your app's DOM will automatically be annotated during build-time with their respective component names. - * This will unlock the capability to search for Replays in Sentry by component name, as well as see component names in breadcrumbs and performance monitoring. - * Please note that this feature is not currently supported by the esbuild bundler plugins, and will only annotate React components - */ - reactComponentAnnotation?: { +export type SentryReactRouterBuildOptions = BuildTimeOptionsBase & + UnstableVitePluginOptions> & { /** - * Whether the component name annotate plugin should be enabled or not. + * Options related to react component name annotations. + * Disabled by default, unless a value is set for this option. + * When enabled, your app's DOM will automatically be annotated during build-time with their respective component names. + * This will unlock the capability to search for Replays in Sentry by component name, as well as see component names in breadcrumbs and performance monitoring. + * Please note that this feature is not currently supported by the esbuild bundler plugins, and will only annotate React components */ - enabled?: boolean; + reactComponentAnnotation?: { + /** + * Whether the component name annotate plugin should be enabled or not. + */ + enabled?: boolean; + + /** + * A list of strings representing the names of components to ignore. The plugin will not apply `data-sentry` annotations on the DOM element for these components. + */ + ignoredComponents?: string[]; + }; /** - * A list of strings representing the names of components to ignore. The plugin will not apply `data-sentry` annotations on the DOM element for these components. + * Options for the Sentry Vite plugin to customize the source maps upload process. + * */ - ignoredComponents?: string[]; + sourceMapsUploadOptions?: SourceMapsOptions; + // todo(v11): Remove this option (all options already exist in BuildTimeOptionsBase) }; - - /** - * Options for the Sentry Vite plugin to customize the source maps upload process. - * - */ - sourceMapsUploadOptions?: SourceMapsOptions; - - /** - * If this flag is `true`, the Sentry plugin will collect some telemetry data and send it to Sentry. - * It will not collect any sensitive or user-specific data. - * - * @default true - */ - telemetry?: boolean; - - /** - * Options to further customize the Sentry Vite Plugin (@sentry/vite-plugin) behavior directly. - * Options specified in this object take precedence over the options specified in - * the `sourcemaps` and `release` objects. - * - * @see https://www.npmjs.com/package/@sentry/vite-plugin/v/2.22.2#options which lists all available options. - * - * Warning: Options within this object are subject to change at any time. - * We DO NOT guarantee semantic versioning for these options, meaning breaking - * changes can occur at any time within a major SDK version. - * - * Furthermore, some options are untested with SvelteKit specifically. Use with caution. - */ - unstable_sentryVitePluginOptions?: Partial; -}; diff --git a/packages/react-router/test/client/tracingIntegration.test.ts b/packages/react-router/test/client/tracingIntegration.test.ts index 9d511b4c6bde..2469c9b29db6 100644 --- a/packages/react-router/test/client/tracingIntegration.test.ts +++ b/packages/react-router/test/client/tracingIntegration.test.ts @@ -17,6 +17,7 @@ describe('reactRouterTracingIntegration', () => { it('calls instrumentHydratedRouter and browserTracingIntegrationInstance.afterAllSetup in afterAllSetup', () => { const browserTracingSpy = vi.spyOn(sentryBrowser, 'browserTracingIntegration').mockImplementation(() => ({ + setup: vi.fn(), afterAllSetup: vi.fn(), name: 'BrowserTracing', })); diff --git a/packages/react-router/test/server/createSentryHandleRequest.test.ts b/packages/react-router/test/server/createSentryHandleRequest.test.ts index 19e6d9542cbb..f87de2f3b0ea 100644 --- a/packages/react-router/test/server/createSentryHandleRequest.test.ts +++ b/packages/react-router/test/server/createSentryHandleRequest.test.ts @@ -42,8 +42,13 @@ describe('createSentryHandleRequest', () => { url: '/test', version: '1.0.0', }, + ssr: true, + routeDiscovery: { + mode: 'lazy', + manifestPath: '/path/to/manifest', + }, routeModules: {}, - future: {}, + future: { unstable_subResourceIntegrity: false, v8_middleware: false }, isSpaMode: false, staticHandlerContext: { matches: [ diff --git a/packages/react-router/test/server/instrumentation/reactRouterServer.test.ts b/packages/react-router/test/server/instrumentation/reactRouterServer.test.ts index 473ad1272ca4..fb5141f8830d 100644 --- a/packages/react-router/test/server/instrumentation/reactRouterServer.test.ts +++ b/packages/react-router/test/server/instrumentation/reactRouterServer.test.ts @@ -88,10 +88,13 @@ describe('ReactRouterInstrumentation', () => { it('should start a span for data requests with active root span', async () => { vi.spyOn(Util, 'isDataRequest').mockReturnValue(true); + // @ts-expect-error MockSpan just for testing vi.spyOn(SentryCore, 'getActiveSpan').mockReturnValue(mockSpan as Span); + // @ts-expect-error MockSpan just for testing vi.spyOn(SentryCore, 'getRootSpan').mockReturnValue(mockSpan as Span); vi.spyOn(SentryCore, 'spanToJSON').mockReturnValue({ data: {} } as SpanJSON); vi.spyOn(Util, 'getSpanName').mockImplementation((pathname, method) => `span:${pathname}:${method}`); + // @ts-expect-error MockSpan just for testing vi.spyOn(SentryCore, 'startSpan').mockImplementation((_opts, fn) => fn(mockSpan as Span)); const proxy = (instrumentation as any)._createPatchedModuleProxy(mockModule); diff --git a/packages/react-router/test/vite/buildEnd/handleOnBuildEnd.test.ts b/packages/react-router/test/vite/buildEnd/handleOnBuildEnd.test.ts index 29bb5c0527d6..8be1d7764219 100644 --- a/packages/react-router/test/vite/buildEnd/handleOnBuildEnd.test.ts +++ b/packages/react-router/test/vite/buildEnd/handleOnBuildEnd.test.ts @@ -81,6 +81,7 @@ describe('sentryOnBuildEnd', () => { } as unknown as TestConfig, }; + // @ts-expect-error - mocking the React config await sentryOnBuildEnd(config); expect(mockSentryCliInstance.releases.new).toHaveBeenCalledWith('v1.0.0'); @@ -102,6 +103,7 @@ describe('sentryOnBuildEnd', () => { } as unknown as TestConfig, }; + // @ts-expect-error - mocking the React config await sentryOnBuildEnd(config); expect(mockSentryCliInstance.releases.new).toHaveBeenCalledWith('v1.0.0-unstable'); @@ -126,6 +128,7 @@ describe('sentryOnBuildEnd', () => { } as unknown as TestConfig, }; + // @ts-expect-error - mocking the React config await sentryOnBuildEnd(config); expect(mockSentryCliInstance.releases.new).toHaveBeenCalledWith('v1.0.0'); @@ -145,6 +148,7 @@ describe('sentryOnBuildEnd', () => { } as unknown as TestConfig, }; + // @ts-expect-error - mocking the React config await sentryOnBuildEnd(config); expect(mockSentryCliInstance.releases.uploadSourceMaps).toHaveBeenCalledTimes(1); @@ -168,12 +172,14 @@ describe('sentryOnBuildEnd', () => { } as unknown as TestConfig, }; + // @ts-expect-error - mocking the React config await sentryOnBuildEnd(config); expect(mockSentryCliInstance.releases.uploadSourceMaps).not.toHaveBeenCalled(); }); it('should delete source maps after upload with default pattern', async () => { + // @ts-expect-error - mocking the React config await sentryOnBuildEnd(defaultConfig); expect(glob).toHaveBeenCalledWith(['/build/**/*.map'], { @@ -196,6 +202,7 @@ describe('sentryOnBuildEnd', () => { } as unknown as TestConfig, }; + // @ts-expect-error - mocking the React config await sentryOnBuildEnd(config); expect(glob).toHaveBeenCalledWith('/custom/**/*.map', { @@ -221,6 +228,7 @@ describe('sentryOnBuildEnd', () => { } as unknown as TestConfig, }; + // @ts-expect-error - mocking the React config await sentryOnBuildEnd(config); expect(consoleSpy).toHaveBeenCalledWith('[Sentry] Could not create release', expect.any(Error)); @@ -241,6 +249,7 @@ describe('sentryOnBuildEnd', () => { } as unknown as TestConfig, }; + // @ts-expect-error - mocking the React config await sentryOnBuildEnd(config); expect(mockSentryCliInstance.execute).toHaveBeenCalledWith(['sourcemaps', 'inject', '/build'], false); @@ -250,6 +259,7 @@ describe('sentryOnBuildEnd', () => { const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {}); mockSentryCliInstance.execute.mockRejectedValueOnce(new Error('Injection failed')); + // @ts-expect-error - mocking the React config await sentryOnBuildEnd(defaultConfig); expect(mockSentryCliInstance.execute).toHaveBeenCalledTimes(1); expect(mockSentryCliInstance.execute).toHaveBeenCalledWith(['sourcemaps', 'inject', '/build'], false); @@ -262,6 +272,7 @@ describe('sentryOnBuildEnd', () => { const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {}); mockSentryCliInstance.releases.uploadSourceMaps.mockRejectedValueOnce(new Error('Upload failed')); + // @ts-expect-error - mocking the React config await sentryOnBuildEnd(defaultConfig); expect(consoleSpy).toHaveBeenCalledWith('[Sentry] Could not upload sourcemaps', expect.any(Error)); @@ -282,6 +293,7 @@ describe('sentryOnBuildEnd', () => { } as unknown as TestConfig, }; + // @ts-expect-error - mocking the React config await sentryOnBuildEnd(config); expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining('[Sentry] Automatically setting')); @@ -312,6 +324,7 @@ describe('sentryOnBuildEnd', () => { } as unknown as TestConfig, }; + // @ts-expect-error - mocking the React config await sentryOnBuildEnd(config); expect(SentryCli).toHaveBeenCalledWith(null, expect.objectContaining(customOptions)); diff --git a/packages/react-router/test/vite/types.test-d.ts b/packages/react-router/test/vite/types.test-d.ts new file mode 100644 index 000000000000..c6a50e92b275 --- /dev/null +++ b/packages/react-router/test/vite/types.test-d.ts @@ -0,0 +1,114 @@ +import { describe, expectTypeOf, it } from 'vitest'; +import type { SentryReactRouterBuildOptions } from '../../src/vite/types'; + +describe('Sentry React-Router build-time options type', () => { + it('includes all options based on type BuildTimeOptionsBase', () => { + const completeOptions: SentryReactRouterBuildOptions = { + // --- BuildTimeOptionsBase options --- + org: 'test-org', + project: 'test-project', + authToken: 'test-auth-token', + sentryUrl: 'https://sentry.io', + headers: { Authorization: ' Bearer test-auth-token' }, + telemetry: true, + silent: false, + // eslint-disable-next-line no-console + errorHandler: (err: Error) => console.warn(err), + debug: false, + sourcemaps: { + disable: false, + assets: ['./dist/**/*'], + ignore: ['./dist/*.map'], + filesToDeleteAfterUpload: ['./dist/*.map'], + }, + release: { + name: 'test-release-1.0.0', + create: true, + finalize: true, + dist: 'test-dist', + vcsRemote: 'origin', + setCommits: { + auto: false, + repo: 'test/repo', + commit: 'abc123', + previousCommit: 'def456', + ignoreMissing: false, + ignoreEmpty: false, + }, + deploy: { + env: 'production', + started: 1234567890, + finished: 1234567900, + time: 10, + name: 'deployment-name', + url: 'https://example.com', + }, + }, + bundleSizeOptimizations: { + excludeDebugStatements: true, + excludeTracing: false, + excludeReplayShadowDom: true, + excludeReplayIframe: true, + excludeReplayWorker: true, + }, + + // --- SentryReactRouterBuildOptions specific options --- + reactComponentAnnotation: { enabled: true, ignoredComponents: ['IgnoredComponent1', 'IgnoredComponent2'] }, + + unstable_sentryVitePluginOptions: { + // Rollup plugin options + bundleSizeOptimizations: { + excludeDebugStatements: true, + }, + // Vite plugin options + sourcemaps: { + assets: './dist/**/*', + }, + }, + }; + + expectTypeOf(completeOptions).toEqualTypeOf(); + }); + + it('includes all deprecated options', () => { + const completeOptions: SentryReactRouterBuildOptions = { + // SentryNuxtModuleOptions specific options + reactComponentAnnotation: { enabled: true, ignoredComponents: ['IgnoredComponent1', 'IgnoredComponent2'] }, + + unstable_sentryVitePluginOptions: { + // Rollup plugin options + bundleSizeOptimizations: { + excludeDebugStatements: true, + }, + // Vite plugin options + sourcemaps: { + assets: './dist/**/*', + }, + }, + + // Deprecated sourceMapsUploadOptions + sourceMapsUploadOptions: { + release: { + name: 'deprecated-release', + }, + enabled: true, + filesToDeleteAfterUpload: ['./build/*.map'], + }, + }; + + expectTypeOf(completeOptions).toEqualTypeOf(); + }); + + it('allows partial configuration', () => { + const minimalOptions: SentryReactRouterBuildOptions = { reactComponentAnnotation: { enabled: true } }; + + expectTypeOf(minimalOptions).toEqualTypeOf(); + + const partialOptions: SentryReactRouterBuildOptions = { + reactComponentAnnotation: { enabled: true }, + debug: false, + }; + + expectTypeOf(partialOptions).toEqualTypeOf(); + }); +}); diff --git a/packages/react-router/tsconfig.test.json b/packages/react-router/tsconfig.test.json index 508cf3ea381b..0bb16039ac48 100644 --- a/packages/react-router/tsconfig.test.json +++ b/packages/react-router/tsconfig.test.json @@ -1,7 +1,7 @@ { "extends": "./tsconfig.json", - "include": ["test/**/*", "vite.config.ts"], + "include": ["test/**/*"], "compilerOptions": { "types": ["node"] diff --git a/packages/react-router/tsconfig.vite.json b/packages/react-router/tsconfig.vite.json new file mode 100644 index 000000000000..3e2d75a55e61 --- /dev/null +++ b/packages/react-router/tsconfig.vite.json @@ -0,0 +1,9 @@ +{ + "extends": "./tsconfig.json", + + "include": ["vite.config.ts"], + + "compilerOptions": { + "types": ["node"] + } +} diff --git a/packages/react-router/vite.config.ts b/packages/react-router/vite.config.ts index 1094fe0d79da..d05c71037c75 100644 --- a/packages/react-router/vite.config.ts +++ b/packages/react-router/vite.config.ts @@ -5,5 +5,9 @@ export default { test: { ...baseConfig.test, environment: 'jsdom', + typecheck: { + enabled: true, + tsconfig: './tsconfig.test.json', + }, }, }; From ed69d0e2bf2ddc6d0639de4f07a8ed872a58979f Mon Sep 17 00:00:00 2001 From: s1gr1d Date: Thu, 23 Oct 2025 17:01:27 +0200 Subject: [PATCH 3/3] fix formatting --- .../buildTimeOptionsBase.ts | 58 ++++++++++--------- 1 file changed, 30 insertions(+), 28 deletions(-) diff --git a/packages/core/src/build-time-plugins/buildTimeOptionsBase.ts b/packages/core/src/build-time-plugins/buildTimeOptionsBase.ts index 29e606781786..67f74f696dcf 100644 --- a/packages/core/src/build-time-plugins/buildTimeOptionsBase.ts +++ b/packages/core/src/build-time-plugins/buildTimeOptionsBase.ts @@ -335,34 +335,36 @@ interface ReleaseOptions { * * @default { auto: true } */ - setCommits?: false | (AutoSetCommitsOptions | ManualSetCommitsOptions) & { - /** - * The commit before the beginning of this release (in other words, - * the last commit of the previous release). - * - * Defaults to the last commit of the previous release in Sentry. - * - * If there was no previous release, the last 10 commits will be used. - */ - previousCommit?: string; - - /** - * If the flag is to `true` and the previous release commit was not found - * in the repository, the plugin creates a release with the default commits - * count instead of failing the command. - * - * @default false - */ - ignoreMissing?: boolean; - - /** - * If this flag is set, the setCommits step will not fail and just exit - * silently if no new commits for a given release have been found. - * - * @default false - */ - ignoreEmpty?: boolean; - }; + setCommits?: + | false + | ((AutoSetCommitsOptions | ManualSetCommitsOptions) & { + /** + * The commit before the beginning of this release (in other words, + * the last commit of the previous release). + * + * Defaults to the last commit of the previous release in Sentry. + * + * If there was no previous release, the last 10 commits will be used. + */ + previousCommit?: string; + + /** + * If the flag is to `true` and the previous release commit was not found + * in the repository, the plugin creates a release with the default commits + * count instead of failing the command. + * + * @default false + */ + ignoreMissing?: boolean; + + /** + * If this flag is set, the setCommits step will not fail and just exit + * silently if no new commits for a given release have been found. + * + * @default false + */ + ignoreEmpty?: boolean; + }); /** * Configuration for adding deployment information to the release in Sentry.