From 51cc2152b63d443f663bca4122fc0485d69806e7 Mon Sep 17 00:00:00 2001 From: s1gr1d <32902192+s1gr1d@users.noreply.github.com> Date: Wed, 7 Oct 2026 16:27:11 +0200 Subject: [PATCH 1/2] feat(nuxt): Detect the server API with `@nuxt/kit` 4.6 --- packages/nuxt/package.json | 5 +- packages/nuxt/src/module.ts | 108 ++------------- packages/nuxt/src/vite/addServerConfig.ts | 4 +- packages/nuxt/src/vite/databaseConfig.ts | 6 +- packages/nuxt/src/vite/nitroServer.ts | 124 ++++++++++++++++++ packages/nuxt/src/vite/storageConfig.ts | 6 +- packages/nuxt/src/vite/utils.ts | 46 ++----- .../nuxt/test/vite/addServerConfig.test.ts | 23 +++- .../nuxt/test/vite/databaseConfig.test.ts | 2 +- packages/nuxt/test/vite/nitroServer.test.ts | 100 ++++++++++++++ packages/nuxt/test/vite/nitroVersion.test.ts | 107 --------------- packages/nuxt/test/vite/serverApi.test.ts | 67 ++++++++++ yarn.lock | 108 ++++++++------- 13 files changed, 401 insertions(+), 305 deletions(-) create mode 100644 packages/nuxt/src/vite/nitroServer.ts create mode 100644 packages/nuxt/test/vite/nitroServer.test.ts delete mode 100644 packages/nuxt/test/vite/nitroVersion.test.ts create mode 100644 packages/nuxt/test/vite/serverApi.test.ts diff --git a/packages/nuxt/package.json b/packages/nuxt/package.json index abba941409eb..80b911753bfd 100644 --- a/packages/nuxt/package.json +++ b/packages/nuxt/package.json @@ -53,7 +53,7 @@ } }, "dependencies": { - "@nuxt/kit": "^4.5.2", + "@nuxt/kit": "^4.6.0", "@sentry/browser": "11.5.0", "@sentry/cloudflare": "11.5.0", "@sentry/conventions": "^0.26.0", @@ -62,8 +62,7 @@ "@sentry/bundler-plugins": "11.5.0", "@sentry/server-runtime-injection": "11.5.0", "@sentry/server-utils": "11.5.0", - "@sentry/vue": "11.5.0", - "local-pkg": "^1.1.2" + "@sentry/vue": "11.5.0" }, "devDependencies": { "@nuxt/nitro-server": "^3.21.11", diff --git a/packages/nuxt/src/module.ts b/packages/nuxt/src/module.ts index bea829d335fe..f1cd456b84c6 100644 --- a/packages/nuxt/src/module.ts +++ b/packages/nuxt/src/module.ts @@ -1,31 +1,13 @@ -import { - addPlugin, - addPluginTemplate, - addServerPlugin, - addTemplate, - addVitePlugin, - createResolver, - defineNuxtModule, -} from '@nuxt/kit'; +import { addPlugin, addPluginTemplate, addTemplate, addVitePlugin, createResolver, defineNuxtModule } from '@nuxt/kit'; // Needed to make TS evaluate the augmentation of Nitro types (https://github.com/nuxt/nuxt/pull/34039) import type {} from '@nuxt/nitro-server'; -import { consoleSandbox } from '@sentry/core'; import * as path from 'path'; import type { SentryNuxtModuleOptions } from './common/types'; -import { - addDynamicImportEntryFileWrapper, - addServerConfigShimWithWarning, - addSentryTopImport, - addServerConfigPlugin, - addServerConfigToBuild, -} from './vite/addServerConfig'; -import { addDatabaseInstrumentation } from './vite/databaseConfig'; -import { addMiddlewareImports, addMiddlewareInstrumentation } from './vite/middlewareConfig'; +import { setupNitroServer } from './vite/nitroServer'; import { setupOrchestrion } from './vite/orchestrion'; import { setupSourceMaps } from './vite/sourceMaps'; -import { addStorageInstrumentation } from './vite/storageConfig'; -import { addOTelCommonJSImportAlias, findDefaultSdkInitFile, getNitroMajorVersion } from './vite/utils'; +import { addOTelCommonJSImportAlias, findDefaultSdkInitFile, resolveServerApi } from './vite/utils'; export type ModuleOptions = SentryNuxtModuleOptions; type NuxtPageSubset = { file?: string; path: string }; @@ -44,6 +26,8 @@ export default defineNuxtModule({ return; } + const serverApi = resolveServerApi(); + const moduleOptions = { ...moduleOptionsParam, // oxlint-disable-next-line typescript/no-deprecated -- supported until removal @@ -91,7 +75,6 @@ export default defineNuxtModule({ } const serverConfigFile = await findDefaultSdkInitFile('server', nuxt, moduleOptions); - const isNitroV3 = (await getNitroMajorVersion(nuxt.options.rootDir)) >= 3; const nuxtMajor = parseInt((nuxt as unknown as { _version: string })._version?.split('.')[0] ?? '3', 10); const isMinNuxtV4 = nuxtMajor >= 4; @@ -100,43 +83,21 @@ export default defineNuxtModule({ // Cloudflare detection happens inside, keyed off the resolved Nitro preset. setupOrchestrion(nuxt, !!serverConfigFile, moduleOptions.buildTimeInstrumentation); - // The deprecated inject modes replace the default in-bundle initialization until their removal - const usesDeprecatedInjectMode = - moduleOptions.autoInjectServerSentry === 'top-level-import' || - moduleOptions.autoInjectServerSentry === 'experimental_dynamic-import'; - if (serverConfigFile) { - if (!usesDeprecatedInjectMode) { - addServerConfigPlugin(nuxt, serverConfigFile, !isNitroV3); - } - - if (isNitroV3) { - addServerPlugin(moduleDirResolver.resolve('./runtime/plugins/handler.server')); - addServerPlugin(moduleDirResolver.resolve('./runtime/plugins/update-route-name.server')); - } else { - addServerPlugin(moduleDirResolver.resolve('./runtime/plugins/handler-legacy.server')); - addServerPlugin(moduleDirResolver.resolve('./runtime/plugins/update-route-name-legacy.server')); - } - - addServerPlugin(moduleDirResolver.resolve('./runtime/plugins/sentry.server')); + setupNitroServer(nuxt, serverApi, serverConfigFile, moduleOptions); if (isMinNuxtV4) { addPlugin({ src: moduleDirResolver.resolve('./runtime/plugins/route-detector.server'), mode: 'server' }); } else { addPlugin({ src: moduleDirResolver.resolve('./runtime/plugins/route-detector-legacy.server'), mode: 'server' }); } - - // Preps the middleware instrumentation module. - addMiddlewareImports(); - addStorageInstrumentation(nuxt, !isNitroV3); - addDatabaseInstrumentation(nuxt.options.nitro, !isNitroV3, moduleOptions); } if (clientConfigFile || serverConfigFile) { setupSourceMaps(moduleOptions, nuxt, addVitePlugin); } - addOTelCommonJSImportAlias(nuxt, isNitroV3); + addOTelCommonJSImportAlias(nuxt, serverApi === 'nitro3'); let pagesData: NuxtPageSubset[] = []; @@ -155,8 +116,8 @@ export default defineNuxtModule({ // Vite virtual plugin (for the Vite SSR build, where addPlugin mode:'server' plugins are bundled) addVitePlugin({ name: 'sentry-nuxt-pages-data-virtual', - resolveId: id => (id === pagesDataVirtualModuleId ? `\0${pagesDataVirtualModuleId}` : null), - load: id => + resolveId: (id: string) => (id === pagesDataVirtualModuleId ? `\0${pagesDataVirtualModuleId}` : null), + load: (id: string) => id === `\0${pagesDataVirtualModuleId}` ? `export default ${JSON.stringify(pagesData, null, 2)};` : undefined, }); } else { @@ -186,56 +147,5 @@ export default defineNuxtModule({ tsConfig.include.push(relativePath); } }); - - nuxt.hooks.hook('nitro:init', nitro => { - if (nuxt.options?._prepare) { - return; - } - - if (serverConfigFile) { - addMiddlewareInstrumentation(nitro, isNitroV3); - - if (!usesDeprecatedInjectMode) { - addServerConfigShimWithWarning(nitro); - - if (moduleOptions.debug) { - consoleSandbox(() => { - // eslint-disable-next-line no-console - console.log( - `[Sentry] Bundled \`${serverConfigFile}\` into the Nitro server build. The SDK initializes itself at server startup — no \`node --import\` preload needed.`, - ); - }); - } - } else { - consoleSandbox(() => { - // eslint-disable-next-line no-console - console.warn( - `[Sentry] \`autoInjectServerSentry: '${moduleOptions.autoInjectServerSentry}'\` is deprecated and will be removed in a future major version. The Sentry server config is bundled into the Nitro server build by default now. Remove the option to use the default behavior.`, - ); - }); - - if (moduleOptions.autoInjectServerSentry === 'top-level-import') { - // Nitro 3 (in Nuxt 5) is not bundled in dev mode, so there is no build to emit into. - if (!(isNitroV3 && nitro.options.dev)) { - addServerConfigToBuild(moduleOptions, nitro, serverConfigFile); - } - addSentryTopImport(moduleOptions, nitro); - } - - if (moduleOptions.autoInjectServerSentry === 'experimental_dynamic-import') { - addDynamicImportEntryFileWrapper(nitro, serverConfigFile, moduleOptions); - - if (moduleOptions.debug) { - consoleSandbox(() => { - // eslint-disable-next-line no-console - console.log( - '[Sentry] Wrapping the server entry file with a dynamic `import()`, so Sentry can be preloaded before the server initializes.', - ); - }); - } - } - } - } - }); }, }); diff --git a/packages/nuxt/src/vite/addServerConfig.ts b/packages/nuxt/src/vite/addServerConfig.ts index 7b90d568216c..7b0970ef3f6d 100644 --- a/packages/nuxt/src/vite/addServerConfig.ts +++ b/packages/nuxt/src/vite/addServerConfig.ts @@ -1,7 +1,7 @@ import { existsSync } from 'node:fs'; import { basename } from 'node:path'; import { pathToFileURL } from 'node:url'; -import { addServerPlugin, addTemplate, createResolver } from '@nuxt/kit'; +import { addNitroPlugin, addTemplate, createResolver } from '@nuxt/kit'; import type { Nuxt } from '@nuxt/schema'; import { consoleSandbox, debug } from '@sentry/core'; import * as fs from 'fs'; @@ -132,7 +132,7 @@ export function addServerConfigPlugin(nuxt: Nuxt, serverConfigFile: string, isLe `import ${JSON.stringify(runtimeFlagsTemplate.dst)};\nimport ${JSON.stringify(configPath)};\nexport default () => {};\n`, }); - addServerPlugin(configPluginTemplate.dst); + addNitroPlugin(configPluginTemplate.dst); // Nitro v2 treeshakes side-effect-only imports outside its runtime dir, which would silently drop // the top-level `Sentry.init` and the flag assignments. diff --git a/packages/nuxt/src/vite/databaseConfig.ts b/packages/nuxt/src/vite/databaseConfig.ts index b025157339b3..54f83943191f 100644 --- a/packages/nuxt/src/vite/databaseConfig.ts +++ b/packages/nuxt/src/vite/databaseConfig.ts @@ -1,4 +1,4 @@ -import { addServerPlugin, createResolver } from '@nuxt/kit'; +import { addNitroPlugin, createResolver } from '@nuxt/kit'; import { consoleSandbox } from '@sentry/core'; import type { NitroConfig } from 'nitropack/types'; import type { SentryNuxtModuleOptions } from '../common/types'; @@ -43,8 +43,8 @@ export function addDatabaseInstrumentation( }); if (isLegacyNitro) { - addServerPlugin(createResolver(import.meta.url).resolve('./runtime/plugins/database-legacy.server')); + addNitroPlugin(createResolver(import.meta.url).resolve('./runtime/plugins/database-legacy.server')); } else { - addServerPlugin(createResolver(import.meta.url).resolve('./runtime/plugins/database.server')); + addNitroPlugin(createResolver(import.meta.url).resolve('./runtime/plugins/database.server')); } } diff --git a/packages/nuxt/src/vite/nitroServer.ts b/packages/nuxt/src/vite/nitroServer.ts new file mode 100644 index 000000000000..c999b29cd186 --- /dev/null +++ b/packages/nuxt/src/vite/nitroServer.ts @@ -0,0 +1,124 @@ +import { addNitroPlugin, createResolver } from '@nuxt/kit'; +import type { Nuxt } from '@nuxt/schema'; +import { consoleSandbox } from '@sentry/core'; +import type { Nitro } from 'nitropack/types'; +import type { SentryNuxtModuleOptions } from '../common/types'; +import { + addDynamicImportEntryFileWrapper, + addSentryTopImport, + addServerConfigPlugin, + addServerConfigShimWithWarning, + addServerConfigToBuild, +} from './addServerConfig'; +import { addDatabaseInstrumentation } from './databaseConfig'; +import { addMiddlewareImports, addMiddlewareInstrumentation } from './middlewareConfig'; +import { addStorageInstrumentation } from './storageConfig'; +import type { ServerApi } from './utils'; + +type NitroModuleOptions = Omit & + Required>; + +/** + * Sets up the server SDK on the Nitro side: the server config plugin, the server plugins, and the + * middleware, storage and database instrumentation. + * + * A host on the `nuxt` server API runs no Nitro, so it gets none of this. Kit would skip each + * Nitro-only registration there with a `NUXT_B8024` warning. + */ +export function setupNitroServer( + nuxt: Nuxt, + serverApi: ServerApi, + serverConfigFile: string, + moduleOptions: NitroModuleOptions, +): void { + if (serverApi === 'nuxt') { + return; + } + + const isNitroV3 = serverApi === 'nitro3'; + const moduleDirResolver = createResolver(import.meta.url); + // oxlint-disable-next-line typescript/no-deprecated -- supported until removal + const injectMode = moduleOptions.autoInjectServerSentry; + // The deprecated inject modes replace the default in-bundle initialization until their removal + const deprecatedInjectMode = + injectMode === 'top-level-import' || injectMode === 'experimental_dynamic-import' ? injectMode : undefined; + + if (!deprecatedInjectMode) { + addServerConfigPlugin(nuxt, serverConfigFile, !isNitroV3); + } + + if (isNitroV3) { + addNitroPlugin(moduleDirResolver.resolve('./runtime/plugins/handler.server')); + addNitroPlugin(moduleDirResolver.resolve('./runtime/plugins/update-route-name.server')); + } else { + addNitroPlugin(moduleDirResolver.resolve('./runtime/plugins/handler-legacy.server')); + addNitroPlugin(moduleDirResolver.resolve('./runtime/plugins/update-route-name-legacy.server')); + } + + addNitroPlugin(moduleDirResolver.resolve('./runtime/plugins/sentry.server')); + + // Preps the middleware instrumentation module. + addMiddlewareImports(); + addStorageInstrumentation(nuxt, !isNitroV3); + addDatabaseInstrumentation(nuxt.options.nitro, !isNitroV3, moduleOptions); + + nuxt.hooks.hook('nitro:init', nitro => { + if (nuxt.options?._prepare) { + return; + } + + addMiddlewareInstrumentation(nitro, isNitroV3); + + if (deprecatedInjectMode) { + setupDeprecatedInjectMode(nitro, deprecatedInjectMode, isNitroV3, serverConfigFile, moduleOptions); + return; + } + + addServerConfigShimWithWarning(nitro); + + if (moduleOptions.debug) { + consoleSandbox(() => { + // eslint-disable-next-line no-console + console.log( + `[Sentry] Bundled \`${serverConfigFile}\` into the Nitro server build. The SDK initializes itself at server startup — no \`node --import\` preload needed.`, + ); + }); + } + }); +} + +function setupDeprecatedInjectMode( + nitro: Nitro, + injectMode: 'top-level-import' | 'experimental_dynamic-import', + isNitroV3: boolean, + serverConfigFile: string, + moduleOptions: NitroModuleOptions, +): void { + consoleSandbox(() => { + // eslint-disable-next-line no-console + console.warn( + `[Sentry] \`autoInjectServerSentry: '${injectMode}'\` is deprecated and will be removed in a future major version. The Sentry server config is bundled into the Nitro server build by default now. Remove the option to use the default behavior.`, + ); + }); + + if (injectMode === 'top-level-import') { + // Nitro 3 (in Nuxt 5) is not bundled in dev mode, so there is no build to emit into. + if (!(isNitroV3 && nitro.options.dev)) { + addServerConfigToBuild(moduleOptions, nitro, serverConfigFile); + } + addSentryTopImport(moduleOptions, nitro); + } + + if (injectMode === 'experimental_dynamic-import') { + addDynamicImportEntryFileWrapper(nitro, serverConfigFile, moduleOptions); + + if (moduleOptions.debug) { + consoleSandbox(() => { + // eslint-disable-next-line no-console + console.log( + '[Sentry] Wrapping the server entry file with a dynamic `import()`, so Sentry can be preloaded before the server initializes.', + ); + }); + } + } +} diff --git a/packages/nuxt/src/vite/storageConfig.ts b/packages/nuxt/src/vite/storageConfig.ts index 393f8b12e59b..517c7884e36c 100644 --- a/packages/nuxt/src/vite/storageConfig.ts +++ b/packages/nuxt/src/vite/storageConfig.ts @@ -1,4 +1,4 @@ -import { addServerPlugin, createResolver } from '@nuxt/kit'; +import { addNitroPlugin, createResolver } from '@nuxt/kit'; import type { Nuxt } from '@nuxt/schema'; import { addServerTemplate } from '../vendor/server-template'; @@ -18,8 +18,8 @@ export function addStorageInstrumentation(nuxt: Nuxt, isLegacyNitro: boolean): v }); if (isLegacyNitro) { - addServerPlugin(moduleDirResolver.resolve('./runtime/plugins/storage-legacy.server')); + addNitroPlugin(moduleDirResolver.resolve('./runtime/plugins/storage-legacy.server')); } else { - addServerPlugin(moduleDirResolver.resolve('./runtime/plugins/storage.server')); + addNitroPlugin(moduleDirResolver.resolve('./runtime/plugins/storage.server')); } } diff --git a/packages/nuxt/src/vite/utils.ts b/packages/nuxt/src/vite/utils.ts index 4c95658e48b3..cab39bc95f19 100644 --- a/packages/nuxt/src/vite/utils.ts +++ b/packages/nuxt/src/vite/utils.ts @@ -4,45 +4,19 @@ import * as fs from 'fs'; import * as path from 'path'; import { fileURLToPath } from 'node:url'; import type { SentryNuxtModuleOptions } from '../common/types'; -import { resolvePath } from '@nuxt/kit'; +import { resolvePath, resolveServerVariant } from '@nuxt/kit'; -/** - * Gets the major version of the Nitro package used by the app's Nuxt installation. - * Returns 2 as the default if the version cannot be determined. - * - * Nitro v2 is published as `nitropack`, v3 as `nitro`. Resolving `nitro` directly is - * unreliable: module resolution walks up the directory tree, so in a monorepo an - * unrelated `nitro` v3 above the app wins even when the app's Nuxt uses `nitropack` v2. - * Instead, follow the dependency chain Nuxt itself imports Nitro through: - * `nuxt` -> (`@nuxt/nitro-server` ->) `nitro` | `nitropack`. - */ -export async function getNitroMajorVersion(rootDir: string): Promise { - try { - const { getPackageInfo } = await import('local-pkg'); - - // `paths` entries must point at a file: for a bare directory, resolution starts at the - // directory's parent and skips the directory's own `node_modules`, so a hoisted copy higher - // up the tree (e.g. a monorepo root) wins over the app's actual dependency. - const fromPackage = (dir: string): { paths: string[] } => ({ paths: [path.join(dir, 'package.json')] }); - - // The package that declares the Nitro dependency: `nuxt` itself, or `@nuxt/nitro-server` (Nuxt >= 3.21) when nuxt delegates to it - let provider = await getPackageInfo('nuxt', fromPackage(rootDir)); - if (provider?.packageJson.dependencies?.['@nuxt/nitro-server']) { - provider = (await getPackageInfo('@nuxt/nitro-server', fromPackage(provider.rootPath))) ?? provider; - } +const SERVER_API_VARIANTS = { nitro2: 'nitro2', nitro3: 'nitro3', nuxt: 'nuxt' } as const; - if (!provider?.packageJson.dependencies?.nitro) { - return 2; - } +/** The upstream server API the host runs. `nuxt` means the host runs no Nitro, for example the Vite server. */ +export type ServerApi = keyof typeof SERVER_API_VARIANTS; - const info = await getPackageInfo('nitro', fromPackage(provider.rootPath)); - const major = parseInt(info?.version?.split('.')[0] ?? '', 10); - // The provider imports `nitro` (not `nitropack`), so it is at least v3 even if the version is unreadable - return isNaN(major) ? 3 : major; - } catch { - // If local-pkg is unavailable or resolution fails, default to v2 - return 2; - } +/** + * Resolves the server API of the current Nuxt host. Call it once in the module setup and pass the result on. + */ +export function resolveServerApi(): ServerApi { + // Kit returns `undefined` only when the host runs none of the given keys, and every host runs one of these. + return resolveServerVariant(SERVER_API_VARIANTS) ?? 'nitro2'; } /** diff --git a/packages/nuxt/test/vite/addServerConfig.test.ts b/packages/nuxt/test/vite/addServerConfig.test.ts index 655c5b96ccb3..d73e66af2530 100644 --- a/packages/nuxt/test/vite/addServerConfig.test.ts +++ b/packages/nuxt/test/vite/addServerConfig.test.ts @@ -114,11 +114,11 @@ describe('wrapEntryWithDynamicImport', () => { }); const addTemplateMock = vi.hoisted(() => vi.fn()); -const addServerPluginMock = vi.hoisted(() => vi.fn()); +const addNitroPluginMock = vi.hoisted(() => vi.fn()); vi.mock('@nuxt/kit', () => ({ addTemplate: addTemplateMock, - addServerPlugin: addServerPluginMock, + addNitroPlugin: addNitroPluginMock, // `@nuxt/kit` resolves rather than joins, which is what lets an absolute layer path win over the base. createResolver: (base: string) => ({ resolve: (input: string) => path.resolve(base, input) }), })); @@ -167,7 +167,7 @@ describe('addServerConfigPlugin', () => { expect(templateContents('sentry-server-config-plugin.mjs')).toBe( `import ${JSON.stringify(flagsDst)};\nimport ${JSON.stringify(APP_CONFIG)};\nexport default () => {};\n`, ); - expect(addServerPluginMock).toHaveBeenCalledWith(pluginDst); + expect(addNitroPluginMock).toHaveBeenCalledWith(pluginDst); }); it('derives the runtime flags from the build-time `import.meta` values', () => { @@ -256,6 +256,23 @@ describe('addServerConfigPlugin', () => { consoleWarnSpy.mockRestore(); }); + it('removes the plugin on `nitro:init` when Nuxt adds the server plugins after `nitro:config` (Nuxt >= 4.6)', () => { + const consoleWarnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {}); + const { nuxt, hooks } = createFakeNuxt(); + const serverPlugins: string[] = []; + addNitroPluginMock.mockImplementationOnce((plugin: string) => serverPlugins.push(plugin)); + addServerConfigPlugin(nuxt, APP_CONFIG, true); + const nitroConfig: NitroConfig = { preset: 'cloudflare_module', plugins: ['other-plugin.mjs'] }; + + hooks['nitro:config']!(nitroConfig); + // Nuxt's `collectServerRegistrations` runs after `nitro:config`, so the early filter cannot see the plugin + const nitro = { options: { preset: 'cloudflare_module', plugins: [...nitroConfig.plugins!, ...serverPlugins] } }; + hooks['nitro:init']!(nitro as never); + + expect(nitro.options.plugins).toEqual(['other-plugin.mjs']); + consoleWarnSpy.mockRestore(); + }); + it('keeps the plugin when the resolved preset is not Cloudflare', () => { const { nuxt, hooks } = createFakeNuxt(); addServerConfigPlugin(nuxt, APP_CONFIG, true); diff --git a/packages/nuxt/test/vite/databaseConfig.test.ts b/packages/nuxt/test/vite/databaseConfig.test.ts index e987ab3984a5..df66e7f180c3 100644 --- a/packages/nuxt/test/vite/databaseConfig.test.ts +++ b/packages/nuxt/test/vite/databaseConfig.test.ts @@ -8,7 +8,7 @@ vi.mock('@sentry/core', () => ({ })); vi.mock('@nuxt/kit', () => ({ - addServerPlugin: vi.fn(), + addNitroPlugin: vi.fn(), createResolver: vi.fn(() => ({ resolve: vi.fn((path: string) => path), })), diff --git a/packages/nuxt/test/vite/nitroServer.test.ts b/packages/nuxt/test/vite/nitroServer.test.ts new file mode 100644 index 000000000000..a1ab7e7d40e2 --- /dev/null +++ b/packages/nuxt/test/vite/nitroServer.test.ts @@ -0,0 +1,100 @@ +import type { Nuxt } from '@nuxt/schema'; +import { beforeEach, describe, expect, it, vi } from 'vitest'; +import { setupNitroServer } from '../../src/vite/nitroServer'; + +const addNitroPluginMock = vi.hoisted(() => vi.fn()); +const addServerImportsMock = vi.hoisted(() => vi.fn()); +const addTemplateMock = vi.hoisted(() => vi.fn()); +const addServerTemplateMock = vi.hoisted(() => vi.fn()); + +vi.mock('@nuxt/kit', () => ({ + addNitroPlugin: addNitroPluginMock, + addServerImports: addServerImportsMock, + addTemplate: addTemplateMock, + createResolver: () => ({ resolve: (input: string) => input }), +})); + +vi.mock('../../src/vendor/server-template', () => ({ + addServerTemplate: addServerTemplateMock, +})); + +const APP_ROOT = '/my/app'; +const SERVER_CONFIG = `${APP_ROOT}/sentry.server.config.ts`; +const MODULE_OPTIONS = { experimental_entrypointWrappedFunctions: ['default', 'handler', 'server'] }; + +type HookCallback = (arg: unknown) => void; + +function createFakeNuxt(): { + nuxt: Nuxt; + hook: ReturnType; + callHook: (name: string, arg: unknown) => void; +} { + const callbacks = new Map(); + const hook = vi.fn((name: string, callback: HookCallback) => { + callbacks.set(name, [...(callbacks.get(name) ?? []), callback]); + }); + const nuxt = { + options: { rootDir: APP_ROOT, buildDir: `${APP_ROOT}/.nuxt`, nitro: {} }, + hook, + hooks: { hook }, + } as unknown as Nuxt; + + return { nuxt, hook, callHook: (name, arg) => callbacks.get(name)?.forEach(callback => callback(arg)) }; +} + +describe('setupNitroServer', () => { + beforeEach(() => { + vi.clearAllMocks(); + addTemplateMock.mockImplementation((opts: { filename: string }) => ({ dst: `${APP_ROOT}/.nuxt/${opts.filename}` })); + }); + + it('registers nothing on a host without Nitro', () => { + const { nuxt, hook } = createFakeNuxt(); + + setupNitroServer(nuxt, 'nuxt', SERVER_CONFIG, MODULE_OPTIONS); + + expect(addNitroPluginMock).not.toHaveBeenCalled(); + expect(addServerImportsMock).not.toHaveBeenCalled(); + expect(addTemplateMock).not.toHaveBeenCalled(); + expect(addServerTemplateMock).not.toHaveBeenCalled(); + expect(hook).not.toHaveBeenCalled(); + }); + + it.each([ + { + serverApi: 'nitro2', + handler: 'handler-legacy.server', + updateRouteName: 'update-route-name-legacy.server', + storage: 'storage-legacy.server', + }, + { + serverApi: 'nitro3', + handler: 'handler.server', + updateRouteName: 'update-route-name.server', + storage: 'storage.server', + }, + ] as const)('registers the $handler plugins on $serverApi', ({ serverApi, handler, updateRouteName, storage }) => { + const { nuxt } = createFakeNuxt(); + + setupNitroServer(nuxt, serverApi, SERVER_CONFIG, MODULE_OPTIONS); + + expect(addNitroPluginMock).toHaveBeenCalledTimes(5); + expect(addNitroPluginMock).toHaveBeenNthCalledWith(1, `${APP_ROOT}/.nuxt/sentry-server-config-plugin.mjs`); + expect(addNitroPluginMock).toHaveBeenNthCalledWith(2, `./runtime/plugins/${handler}`); + expect(addNitroPluginMock).toHaveBeenNthCalledWith(3, `./runtime/plugins/${updateRouteName}`); + expect(addNitroPluginMock).toHaveBeenNthCalledWith(4, './runtime/plugins/sentry.server'); + expect(addNitroPluginMock).toHaveBeenNthCalledWith(5, `./runtime/plugins/${storage}`); + }); + + it('instruments the middleware and adds the config shim once Nitro initializes', () => { + const { nuxt, callHook } = createFakeNuxt(); + const nitro = { options: { preset: 'node-server', plugins: [] }, hooks: { hook: vi.fn() } }; + setupNitroServer(nuxt, 'nitro2', SERVER_CONFIG, MODULE_OPTIONS); + + callHook('nitro:init', nitro); + + expect(nitro.hooks.hook).toHaveBeenCalledTimes(2); + expect(nitro.hooks.hook).toHaveBeenCalledWith('rollup:before', expect.any(Function)); + expect(nitro.hooks.hook).toHaveBeenCalledWith('close', expect.any(Function)); + }); +}); diff --git a/packages/nuxt/test/vite/nitroVersion.test.ts b/packages/nuxt/test/vite/nitroVersion.test.ts deleted file mode 100644 index a9228231d395..000000000000 --- a/packages/nuxt/test/vite/nitroVersion.test.ts +++ /dev/null @@ -1,107 +0,0 @@ -import * as fs from 'fs'; -import * as os from 'os'; -import * as path from 'path'; -import { afterAll, beforeAll, describe, expect, it } from 'vitest'; -import { getNitroMajorVersion } from '../../src/vite/utils'; - -// Real filesystem fixtures instead of mocks: the bug this guards against lives in -// module resolution walking up the directory tree, which mocks cannot reproduce. -let monorepoRoot: string; - -function writePackage(dir: string, packageJson: Record): void { - fs.mkdirSync(dir, { recursive: true }); - fs.writeFileSync(path.join(dir, 'package.json'), JSON.stringify({ main: 'index.js', ...packageJson })); - fs.writeFileSync(path.join(dir, 'index.js'), ''); -} - -function createApp(appName: string, packages: Record>): string { - const appDir = path.join(monorepoRoot, 'apps', appName); - fs.mkdirSync(appDir, { recursive: true }); - for (const [name, packageJson] of Object.entries(packages)) { - writePackage(path.join(appDir, 'node_modules', name), packageJson); - } - return appDir; -} - -beforeAll(() => { - monorepoRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'sentry-nitro-version-')); - // An unrelated Nitro v3 above the apps, like a monorepo root devDependency - writePackage(path.join(monorepoRoot, 'node_modules', 'nitro'), { name: 'nitro', version: '3.0.0-beta.1' }); -}); - -afterAll(() => { - fs.rmSync(monorepoRoot, { recursive: true, force: true }); -}); - -describe('getNitroMajorVersion', () => { - it('detects v2 when nuxt depends on nitropack directly (Nuxt 3 / <=4.1), ignoring a nitro v3 higher up the tree', async () => { - const appDir = createApp('nuxt-4-old', { - nuxt: { name: 'nuxt', version: '4.1.0', dependencies: { nitropack: '^2.12.0' } }, - nitropack: { name: 'nitropack', version: '2.12.0' }, - }); - - await expect(getNitroMajorVersion(appDir)).resolves.toBe(2); - }); - - it('detects v2 through @nuxt/nitro-server when it depends on nitropack (Nuxt >=3.21 stable)', async () => { - const appDir = createApp('nuxt-4-stable', { - nuxt: { name: 'nuxt', version: '4.5.2', dependencies: { '@nuxt/nitro-server': '4.5.2' } }, - '@nuxt/nitro-server': { name: '@nuxt/nitro-server', version: '4.5.2', dependencies: { nitropack: '^2.13.4' } }, - nitropack: { name: 'nitropack', version: '2.13.4' }, - }); - - await expect(getNitroMajorVersion(appDir)).resolves.toBe(2); - }); - - it('detects v3 through @nuxt/nitro-server when it depends on nitro (Nuxt 5)', async () => { - const appDir = createApp('nuxt-5', { - nuxt: { - name: 'nuxt', - version: '5.0.0', - dependencies: { '@nuxt/nitro-server': 'npm:@nuxt/nitro-server-nightly' }, - }, - '@nuxt/nitro-server': { - name: '@nuxt/nitro-server-nightly', - version: '5.0.0-nightly', - dependencies: { nitro: '^3.0.0-beta' }, - }, - nitro: { name: 'nitro', version: '3.0.0-beta.2' }, - }); - - await expect(getNitroMajorVersion(appDir)).resolves.toBe(3); - }); - - it('detects v3 when nuxt depends on nitro directly, without @nuxt/nitro-server', async () => { - const appDir = createApp('nuxt-direct-nitro', { - nuxt: { name: 'nuxt', version: '5.1.0', dependencies: { nitro: '^3.1.0' } }, - nitro: { name: 'nitro', version: '3.1.0' }, - }); - - await expect(getNitroMajorVersion(appDir)).resolves.toBe(3); - }); - - it('falls back to v3 when the declared nitro package has no readable version (stub package)', async () => { - const appDir = createApp('nuxt-5-stub', { - nuxt: { - name: 'nuxt', - version: '5.0.0', - dependencies: { '@nuxt/nitro-server': 'npm:@nuxt/nitro-server-nightly' }, - }, - '@nuxt/nitro-server': { - name: '@nuxt/nitro-server-nightly', - version: '5.0.0-nightly', - dependencies: { nitro: '^3.0.0-beta' }, - }, - nitro: { name: 'nitro' }, - }); - - await expect(getNitroMajorVersion(appDir)).resolves.toBe(3); - }); - - it('defaults to v2 when nuxt cannot be resolved', async () => { - const appDir = path.join(monorepoRoot, 'apps', 'no-nuxt'); - fs.mkdirSync(appDir, { recursive: true }); - - await expect(getNitroMajorVersion(appDir)).resolves.toBe(2); - }); -}); diff --git a/packages/nuxt/test/vite/serverApi.test.ts b/packages/nuxt/test/vite/serverApi.test.ts new file mode 100644 index 000000000000..db453a699025 --- /dev/null +++ b/packages/nuxt/test/vite/serverApi.test.ts @@ -0,0 +1,67 @@ +import { runWithNuxtContext } from '@nuxt/kit'; +import type { Nuxt } from '@nuxt/schema'; +import * as fs from 'fs'; +import * as os from 'os'; +import * as path from 'path'; +import { afterAll, beforeAll, describe, expect, it } from 'vitest'; +import { resolveServerApi } from '../../src/vite/utils'; + +// The real kit, not a mock: on older hosts kit resolves `nitropack` from the project, so the +// fixture gives it a project with only `nitropack` installed. A temp dir has nothing hoisted above it. +let rootDir: string; + +beforeAll(() => { + rootDir = fs.mkdtempSync(path.join(os.tmpdir(), 'sentry-nuxt-server-api-')); + const nitropackDir = path.join(rootDir, 'node_modules', 'nitropack'); + fs.mkdirSync(nitropackDir, { recursive: true }); + fs.writeFileSync( + path.join(nitropackDir, 'package.json'), + JSON.stringify({ name: 'nitropack', version: '2.13.4', main: 'index.js' }), + ); + fs.writeFileSync(path.join(nitropackDir, 'index.js'), ''); +}); + +afterAll(() => { + fs.rmSync(rootDir, { recursive: true, force: true }); +}); + +function resolveForHost(version: string, options: Record): ReturnType { + const nuxt = { + _version: version, + options: { rootDir, modulesDir: [path.join(rootDir, 'node_modules')], ...options }, + } as unknown as Nuxt; + + return runWithNuxtContext(nuxt, resolveServerApi); +} + +describe('resolveServerApi', () => { + it.each([ + { host: 'Nuxt 3.7', version: '3.7.0', options: {} }, + { + host: 'Nuxt 4.2 to 4.5', + version: '4.5.2', + options: { server: { builder: '@nuxt/nitro-server' } }, + }, + ])( + 'resolves `nitro2` from the installed `nitropack` on $host, which declares no Nitro major', + ({ version, options }) => { + expect(resolveForHost(version, options)).toBe('nitro2'); + }, + ); + + it('resolves `nitro2` when the host declares Nitro v2 (Nuxt 4.6)', () => { + expect(resolveForHost('4.6.0', { server: { builder: '@nuxt/nitro-server' }, _nitroMajor: 2 })).toBe('nitro2'); + }); + + it('resolves `nitro3` when the host declares Nitro v3 (Nuxt 5)', () => { + expect(resolveForHost('5.0.0', { server: { builder: '@nuxt/nitro-server' }, _nitroMajor: 3 })).toBe('nitro3'); + }); + + it('resolves `nuxt` for the Vite server builder', () => { + expect(resolveForHost('4.6.0', { server: { builder: '@nuxt/vite-server' }, _nitroMajor: 2 })).toBe('nuxt'); + }); + + it('resolves `nuxt` for a custom builder object', () => { + expect(resolveForHost('4.6.0', { server: { builder: { bundle() {} } }, _nitroMajor: 2 })).toBe('nuxt'); + }); +}); diff --git a/yarn.lock b/yarn.lock index c07d28325713..c75f14c1a06a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5996,32 +5996,29 @@ unctx "^2.5.0" untyped "^2.0.0" -"@nuxt/kit@^4.5.1", "@nuxt/kit@^4.5.2": - version "4.5.2" - resolved "https://registry.yarnpkg.com/@nuxt/kit/-/kit-4.5.2.tgz#fa338b169d14d9e66f973ded551d2376edb72398" - integrity sha512-l66LU9DcJYjmNwqwAj2I5UGRrUbnG2DOKGChnN70zIGtn0eq/z87gi/FRgha6eMb9/FmB1PFHgtx6PWVml1C2Q== +"@nuxt/kit@^4.5.1", "@nuxt/kit@^4.6.0": + version "4.6.0" + resolved "https://sfw.security.sentry.io/npm/@nuxt/kit/-/kit-4.6.0.tgz#bc2d003484d800398927976fa50c104aa9a76f45" + integrity sha512-UXTajJ+MFJgwV9UL1CTNNd2PSw5PC3Pjb2rM7FsSYcr92ySQKXEslBnUKbvnXT+gG3NbZ/EF70+WenoNIHX2tw== dependencies: - c12 "^3.3.4" consola "^3.4.2" defu "^6.1.7" destr "^2.0.5" - errx "^0.1.2" - exsolve "^1.1.1" - ignore "^7.0.6" - jiti "^2.7.0" + errx "^0.2.2" + exsolve "^1.1.3" + ignore "^7.0.12" klona "^2.0.6" - mlly "^1.8.2" - nostics "^1.2.0" - ohash "^2.0.11" + microdiff "^1.6.0" + nostics "^1.3.0" + package-manager-detector "^1.8.0" pathe "^2.0.3" - pkg-types "^2.3.1" - rc9 "^3.0.1" + rc9 "^3.1.0" scule "^1.3.0" + std-env "^4.3.0" + tinyexec "^1.3.1" tinyglobby "^0.2.17" - ufo "^1.6.4" - unctx "^3.0.0" - untyped "^2.0.0" - verkit "^0.3.1" + unctx "^3.0.1" + verkit "^0.5.0" "@nuxt/nitro-server@3.21.11", "@nuxt/nitro-server@^3.21.11": version "3.21.11" @@ -14485,6 +14482,11 @@ errx@^0.1.2: resolved "https://registry.yarnpkg.com/errx/-/errx-0.1.2.tgz#cd870178afe9072700d8486af4eb3c358892f40c" integrity sha512-chfpPHmCerdo/rXr/nNvPZRkV4WwDRwzwnsJ0Uzz3tVi8Z41tDctRjduYy1138ii77AFlts1qvWtX3g/Acg91Q== +errx@^0.2.2: + version "0.2.2" + resolved "https://sfw.security.sentry.io/npm/errx/-/errx-0.2.2.tgz#33a094dc8238e13b2182d20e8d406572a09ae86b" + integrity sha512-HaPN6cxm6iZ9bIbQQ5orChcw7SY5smUzM08ZMc6OtV4UQhrrc3Ms1G8Ww2n/9lXkWqiioNTssF8bCvchrSbFEQ== + es-abstract@^1.23.2, es-abstract@^1.23.5, es-abstract@^1.23.9, es-abstract@^1.24.0: version "1.24.0" resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.24.0.tgz#c44732d2beb0acc1ed60df840869e3106e7af328" @@ -15547,10 +15549,10 @@ express@^4.17.3, express@^4.21.2: utils-merge "1.0.1" vary "~1.1.2" -exsolve@^1.0.7, exsolve@^1.0.8, exsolve@^1.1.0, exsolve@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/exsolve/-/exsolve-1.1.1.tgz#c055418255459b6ecde4e59de0060a3e97bc7572" - integrity sha512-9U/jZUgjnSGyntRr6y5Muu1MJcwFl6kPu7k8qLF0IMNfLqvw0NZ4nnVDq0RVoZ0RvCyumib4Ez3KYrVfilrw+g== +exsolve@^1.0.7, exsolve@^1.0.8, exsolve@^1.1.0, exsolve@^1.1.1, exsolve@^1.1.3: + version "1.1.3" + resolved "https://sfw.security.sentry.io/npm/exsolve/-/exsolve-1.1.3.tgz#175a6336d6cb1c9cfee822a092665ee0b79e716d" + integrity sha512-kuzL9zherLQoqDeQaS55AiiIg1kb4KYXaSusTtgZTPlvKP2gGCI82LNmBNh5RjDVUXIcmgx+/Mx7vPwRzBbhJA== extend-shallow@^2.0.1: version "2.0.1" @@ -17404,10 +17406,10 @@ ignore@^5.0.4, ignore@^5.2.0, ignore@^5.2.4: resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.2.tgz#3cd40e729f3643fd87cb04e50bf0eb722bc596f5" integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g== -ignore@^7.0.5, ignore@^7.0.6: - version "7.0.6" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-7.0.6.tgz#6a57aaef4c90df27ac3590875d29e8f11988c88e" - integrity sha512-BAg6QkE8W+TuQLrrw0Ugr7HegXduRuuj8/ti2kSOc+jz1dmx8/WNcjr6XGnq5YpDWxFwwaavqD0+jIUOKelTsw== +ignore@^7.0.12, ignore@^7.0.5, ignore@^7.0.6: + version "7.0.12" + resolved "https://sfw.security.sentry.io/npm/ignore/-/ignore-7.0.12.tgz#36048ce2e8d8e0f97fd87863a1cb595ea0a5c69f" + integrity sha512-/8UvqAPU9DGTI9k4mxtf49U37Isfwr8Uts96+SBHIkFxPJnHS0Ew4f00sM4Scd8V8EjM0jUNtVDdv1kPdt35lg== image-meta@^0.2.2: version "0.2.2" @@ -19580,6 +19582,11 @@ methods@^1.1.2, methods@~1.1.2: resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= +microdiff@^1.6.0: + version "1.6.0" + resolved "https://sfw.security.sentry.io/npm/microdiff/-/microdiff-1.6.0.tgz#5a205ff44ab63c2eea7761b1578b6c0e2d4d119b" + integrity sha512-w7JWt8Bno6I8h0rEqlxr4lNG4UbT1FVtWo42wWosIiaJ+rP3pXh7shCYDnyqBrYx36LJ1CZ64p8A62aVp0sJpQ== + micromark-core-commonmark@^2.0.0: version "2.0.3" resolved "https://registry.yarnpkg.com/micromark-core-commonmark/-/micromark-core-commonmark-2.0.3.tgz#c691630e485021a68cf28dbc2b2ca27ebf678cd4" @@ -20810,10 +20817,10 @@ normalize-path@^3.0.0, normalize-path@~3.0.0: resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== -nostics@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/nostics/-/nostics-1.2.0.tgz#1362df6de2ca8456b521914501abf6c52c4d7fb5" - integrity sha512-FGqEfhQjrvo1lL8KFifdTQiNwwQHJxC1jtYE1Rc54qF/jxONUNL+kC9gS1krX8Q65PgrQ5fCqH/I4NhWBvdSqg== +nostics@^1.3.0: + version "1.3.0" + resolved "https://sfw.security.sentry.io/npm/nostics/-/nostics-1.3.0.tgz#e1d538463acb0207f9a0ef9ec551b075930559c4" + integrity sha512-wzRsrJwNlFbqIRQt8aCeL2WE8USip/uuvGSOZV1D02CxX8ABTMbw8IywKjH7yWHETMXbWJI4OBpihg9rmz2Vyg== npm-bundled@^1.1.1: version "1.1.2" @@ -21815,6 +21822,11 @@ package-json-from-dist@^1.0.0, package-json-from-dist@^1.0.1: resolved "https://registry.yarnpkg.com/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz#4f1471a010827a86f94cfd9b0727e36d267de505" integrity sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw== +package-manager-detector@^1.8.0: + version "1.9.0" + resolved "https://sfw.security.sentry.io/npm/package-manager-detector/-/package-manager-detector-1.9.0.tgz#217ed03645bfeb563e9efce4c5bbbfbb652754ab" + integrity sha512-zAMfbta9nPA8AKkA4WdmNAT8R8s6Dk0/xwPsqNnRidMFcLo1YkLuPDTgs2f64XdzS8vbLNnoJ+uUIkgbz7oRHA== + package-name-regex@^2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/package-name-regex/-/package-name-regex-2.0.6.tgz#b54bcb04d950e38082b7bb38fa558e01c1679334" @@ -23375,12 +23387,12 @@ rc9@^2.1.2: defu "^6.1.4" destr "^2.0.3" -rc9@^3.0.0, rc9@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/rc9/-/rc9-3.0.1.tgz#3895e5834a2b5c2d8fb76d93e802fbcbc2579bc7" - integrity sha512-gMDyleLWVE+i6Sgtc0QbbY6pEKqYs97NGi6isHQPqYlLemPoO8dxQ3uGi0f4NiP98c+jMW6cG1Kx9dDwfvqARQ== +rc9@^3.0.0, rc9@^3.0.1, rc9@^3.1.0: + version "3.1.0" + resolved "https://sfw.security.sentry.io/npm/rc9/-/rc9-3.1.0.tgz#383f44c0f0bdefcf411c1ce9403c528064a8bd1a" + integrity sha512-ufjkNVzbRHKcCOmTahZkmVsyc3W+MSk3jY03m+a7tGHkIsdVMG9l10/3HvFbWkkKzY5VFp3pkRsIo/UYgmFL7Q== dependencies: - defu "^6.1.6" + defu "^6.1.7" destr "^2.0.5" rc@^1.2.8: @@ -25509,10 +25521,10 @@ std-env@^3.7.0: resolved "https://registry.yarnpkg.com/std-env/-/std-env-3.10.0.tgz#d810b27e3a073047b2b5e40034881f5ea6f9c83b" integrity sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg== -std-env@^4.0.0, std-env@^4.0.0-rc.1, std-env@^4.1.0, std-env@^4.2.0: - version "4.2.0" - resolved "https://sfw.security.sentry.io/npm/std-env/-/std-env-4.2.0.tgz#8ebe0ec60485668ab47227b312f4254cdf80c9d3" - integrity sha512-oCUKSupKTHX53EyjDtuZQ64pjLJ6yYCtpmEw0goYxtjG9KpbRe8KAsl2tBUGU9DyMcJ0RwJ8GqJAFzMXcXW1Rw== +std-env@^4.0.0, std-env@^4.0.0-rc.1, std-env@^4.1.0, std-env@^4.2.0, std-env@^4.3.0: + version "4.3.0" + resolved "https://sfw.security.sentry.io/npm/std-env/-/std-env-4.3.0.tgz#4e7231b61fd83219aa7f76f71fa8818b07e41321" + integrity sha512-OtU/EgQ1kIm5KwqQpBC6ZEMXrZRui11w8zgfTWp8cdO9B8OaPsbA8bTHO2P+HNo1VlUTGMVBwPhydu6poeXiag== stdin-discarder@^0.2.2: version "0.2.2" @@ -26196,7 +26208,7 @@ tinyexec@^0.3.1: resolved "https://registry.yarnpkg.com/tinyexec/-/tinyexec-0.3.2.tgz#941794e657a85e496577995c6eef66f53f42b3d2" integrity sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA== -tinyexec@^1.0.2, tinyexec@^1.2.4: +tinyexec@^1.0.2, tinyexec@^1.2.4, tinyexec@^1.3.1: version "1.3.1" resolved "https://sfw.security.sentry.io/npm/tinyexec/-/tinyexec-1.3.1.tgz#16a2e3c6e23fafce72640e678e651db36145b9c6" integrity sha512-GCvB3aoys96IuDFBMcTB46JOR6mdMtAToqwiW8JlWhsoh1mhHi/xn9ss/Dg7N555GiJyEt2qzoG/NHCwM6h1EA== @@ -26730,10 +26742,10 @@ unctx@^2.4.1, unctx@^2.5.0: magic-string "^0.30.21" unplugin "^2.3.11" -unctx@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/unctx/-/unctx-3.0.0.tgz#82e2f20c8f9db13a443871caddfdd1af7af2eff1" - integrity sha512-DoXdZVeyi2jyEsn86i8MO5RTItm1kffUkH9/+DQORn3Q688AMOy2551CIl6AdGL2UpwD675wtbNOl75wIQN/uA== +unctx@^3.0.1: + version "3.0.1" + resolved "https://sfw.security.sentry.io/npm/unctx/-/unctx-3.0.1.tgz#16dc56fc256a2bf4df485d9f38866634109058a1" + integrity sha512-5RAt2etv7g362RXyd33R82gm9u/kbtQlpoaOs9Bgm4E32GRMJ0xjbZyvdxUTmiuHk3V1IQb1aUNrp5IWY+JaWw== undefsafe@^2.0.5: version "2.0.5" @@ -27265,10 +27277,10 @@ vary@^1, vary@^1.1.2, vary@~1.1.2: resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= -verkit@^0.3.1: - version "0.3.2" - resolved "https://registry.yarnpkg.com/verkit/-/verkit-0.3.2.tgz#0511ea63310551b62a20c010aa820350c5c350c6" - integrity sha512-zj/ob3UsvJGN0whEAKFp53REA5X66hvffVqoCtVQAakJKnKlH+/PcOfMoFwIG/o4rElqLv/ycAFlx8ZlXUorCg== +verkit@^0.5.0: + version "0.5.0" + resolved "https://sfw.security.sentry.io/npm/verkit/-/verkit-0.5.0.tgz#8b7617dda9ad2edb7851c6a4ff5f3ca428482401" + integrity sha512-u4J1hr6Y+C/hit34GwL3eIcUf3wngT8TlYUjK7tk0jxydKLAq3sYvifjdTDA6U3KCKRcQCQDGf/srjxfZF3l7g== vfile-location@^5.0.0: version "5.0.3" From 7a1455d54a5d7b8e166964bf3f06106169245888 Mon Sep 17 00:00:00 2001 From: s1gr1d <32902192+s1gr1d@users.noreply.github.com> Date: Fri, 9 Oct 2026 09:26:09 +0200 Subject: [PATCH 2/2] fix package.json --- packages/nuxt/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/nuxt/package.json b/packages/nuxt/package.json index 75aed195ca06..b5b642144827 100644 --- a/packages/nuxt/package.json +++ b/packages/nuxt/package.json @@ -62,7 +62,7 @@ "@sentry/bundler-plugins": "11.6.0", "@sentry/server-runtime-injection": "11.6.0", "@sentry/server-utils": "11.6.0", - "@sentry/vue": "11.6.0", + "@sentry/vue": "11.6.0" }, "devDependencies": { "@nuxt/nitro-server": "^3.21.11",