UNPKG

@sentry/nextjs

Version:
256 lines (252 loc) • 13.2 kB
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); const traceMetaTags = require('../../common/traceMetaTags.js'); const core = require('@sentry/core'); const node = require('@sentry/node'); const fs = require('fs'); const path = require('path'); const buildLogger = require('../buildLogger.js'); const createRouteManifest = require('../manifest/createRouteManifest.js'); const util = require('../util.js'); const buildTime = require('./buildTime.js'); const tunnel = require('./tunnel.js'); let showedExportModeTunnelWarning = false; let showedUnusedTunnelRouteHandlerWarning = false; let showedTunnelRouteHandlerModeLog = false; let showedExperimentalBuildModeWarning = false; const MISSING_INSTRUMENTATION_FILE_WARNING_SHOWN = "__SENTRY_MISSING_INSTRUMENTATION_FILE_WARNING_SHOWN__"; function resolveReleaseName(userSentryOptions) { const shouldCreateRelease = userSentryOptions.release?.create !== false; return shouldCreateRelease ? userSentryOptions.release?.name ?? node.getSentryRelease() ?? buildTime.getGitRevision() : userSentryOptions.release?.name; } function maybeSetUpTunnelRouteRewriteRules(incomingUserNextConfigObject, userSentryOptions) { if (userSentryOptions.tunnelRoute === void 0) { maybeWarnAboutUnusedTunnelRouteHandler(incomingUserNextConfigObject, userSentryOptions.silent); return; } if (!userSentryOptions.tunnelRoute) { return; } if (incomingUserNextConfigObject.output === "export") { if (!showedExportModeTunnelWarning) { showedExportModeTunnelWarning = true; buildLogger.getBuildLogger(userSentryOptions.silent).warn( "[@sentry/nextjs] The Sentry Next.js SDK `tunnelRoute` option will not work in combination with Next.js static exports. The `tunnelRoute` option uses server-side features that cannot be accessed in export mode. If you still want to tunnel Sentry events, set up your own tunnel: https://docs.sentry.io/platforms/javascript/troubleshooting/#using-the-tunnel-option" ); } return; } const resolvedTunnelRoute = tunnel.resolveTunnelRoute(userSentryOptions.tunnelRoute); userSentryOptions.tunnelRoute = resolvedTunnelRoute || void 0; const tunnelRouteHandlerFile = tunnel.findTunnelRouteHandlerFile(incomingUserNextConfigObject.pageExtensions); if (!tunnelRouteHandlerFile) { tunnel.setUpTunnelRewriteRules(incomingUserNextConfigObject, resolvedTunnelRoute); return; } tunnel.setUpTunnelHandlerRewrite(incomingUserNextConfigObject, resolvedTunnelRoute); if (!showedTunnelRouteHandlerModeLog) { showedTunnelRouteHandlerModeLog = true; buildLogger.getBuildLogger(userSentryOptions.silent).log( `[@sentry/nextjs] The tunnel route sends events through ${tunnelRouteHandlerFile}. Only the event payload goes to Sentry.` ); } } function maybeWarnAboutUnusedTunnelRouteHandler(incomingUserNextConfigObject, silent) { if (showedUnusedTunnelRouteHandlerWarning || incomingUserNextConfigObject.output === "export") { return; } const tunnelRouteHandlerFile = tunnel.findTunnelRouteHandlerFile(incomingUserNextConfigObject.pageExtensions); if (!tunnelRouteHandlerFile) { return; } showedUnusedTunnelRouteHandlerWarning = true; buildLogger.getBuildLogger(silent).warn( `[@sentry/nextjs] Found ${tunnelRouteHandlerFile}, but the \`tunnelRoute\` option is not set. Set \`tunnelRoute\` in \`withSentryConfig\` to send events through this route.` ); } function shouldReturnEarlyInExperimentalBuildMode(silent) { if (!process.argv.includes("--experimental-build-mode")) { return false; } if (!showedExperimentalBuildModeWarning) { showedExperimentalBuildModeWarning = true; buildLogger.getBuildLogger(silent).warn( "[@sentry/nextjs] The Sentry Next.js SDK does not currently fully support next build --experimental-build-mode" ); } return process.argv.includes("generate"); } function maybeCreateRouteManifest(incomingUserNextConfigObject, userSentryOptions) { if (userSentryOptions.routeManifestInjection === false) { return void 0; } const manifest = createRouteManifest.createRouteManifest({ basePath: incomingUserNextConfigObject.basePath, localeParamNames: userSentryOptions.routeManifestInjection?.localeParamNames, silent: userSentryOptions.silent }); const excludeFilter = userSentryOptions.routeManifestInjection?.exclude; return filterRouteManifest(manifest, excludeFilter); } function filterRouteManifest(manifest, excludeFilter) { if (!excludeFilter) { return manifest; } const shouldExclude = (route) => { if (typeof excludeFilter === "function") { return excludeFilter(route); } return excludeFilter.some((pattern) => core.isMatchingPattern(route, pattern)); }; return { staticRoutes: manifest.staticRoutes.filter((r) => !shouldExclude(r.path)), dynamicRoutes: manifest.dynamicRoutes.filter((r) => !shouldExclude(r.path)) }; } function maybeSetClientTraceMetadataOption(incomingUserNextConfigObject, nextJsVersion, silent) { if (nextJsVersion) { const { major, minor } = core.parseSemver(nextJsVersion); if (major !== void 0 && minor !== void 0 && (major >= 15 || major === 14 && minor >= 3)) { incomingUserNextConfigObject.experimental = incomingUserNextConfigObject.experimental || {}; incomingUserNextConfigObject.experimental.clientTraceMetadata = [ "baggage", "sentry-trace", traceMetaTags.CACHE_ORIGIN_META_TAG_NAME, ...incomingUserNextConfigObject.experimental?.clientTraceMetadata || [] ]; } } else { buildLogger.getBuildLogger(silent).log( "[@sentry/nextjs] The Sentry SDK was not able to determine your Next.js version. If you are using Next.js version 15 or greater, please add `experimental.clientTraceMetadata: ['sentry-trace', 'baggage', 'sentry-cache-origin']` to your Next.js config to enable pageload tracing for App Router." ); } } function maybeSetInstrumentationHookOption(incomingUserNextConfigObject, nextJsVersion, silent) { const logger = buildLogger.getBuildLogger(silent); if (nextJsVersion && util.requiresInstrumentationHook(nextJsVersion)) { if (incomingUserNextConfigObject.experimental?.instrumentationHook === false) { logger.warn( "[@sentry/nextjs] You turned off the `experimental.instrumentationHook` option. Note that Sentry will not be initialized if you did not set it up inside `instrumentation.(js|ts)`." ); } incomingUserNextConfigObject.experimental = { instrumentationHook: true, ...incomingUserNextConfigObject.experimental }; return; } if (nextJsVersion) { return; } if (incomingUserNextConfigObject.experimental && "instrumentationHook" in incomingUserNextConfigObject.experimental) { if (incomingUserNextConfigObject.experimental.instrumentationHook === false) { logger.warn( "[@sentry/nextjs] You set `experimental.instrumentationHook` to `false`. If you are using Next.js version 15 or greater, you can remove that option. If you are using Next.js version 14 or lower, you need to set `experimental.instrumentationHook` in your `next.config.(js|mjs)` to `true` for the SDK to be properly initialized in combination with `instrumentation.(js|ts)`." ); } } else { logger.log( "[@sentry/nextjs] The Sentry SDK was not able to determine your Next.js version. If you are using Next.js version 15 or greater, Next.js will probably show you a warning about the `experimental.instrumentationHook` being set. To silence Next.js' warning, explicitly set the `experimental.instrumentationHook` option in your `next.config.(js|mjs|ts)` to `undefined`. If you are on Next.js version 14 or lower, you can silence this particular warning by explicitly setting the `experimental.instrumentationHook` option in your `next.config.(js|mjs)` to `true`." ); incomingUserNextConfigObject.experimental = { instrumentationHook: true, ...incomingUserNextConfigObject.experimental }; } } function warnIfMissingOnRouterTransitionStartHook(userSentryOptions) { const instrumentationClientFileContents = buildTime.getInstrumentationClientFileContents(); if (instrumentationClientFileContents !== void 0 && !instrumentationClientFileContents.includes("onRouterTransitionStart") && !userSentryOptions.suppressOnRouterTransitionStartWarning) { buildLogger.getBuildLogger(userSentryOptions.silent).warn( "[@sentry/nextjs] ACTION REQUIRED: To instrument navigations, the Sentry SDK requires you to export an `onRouterTransitionStart` hook from your `instrumentation-client.(js|ts)` file. You can do so by adding `export const onRouterTransitionStart = Sentry.captureRouterTransitionStart;` to the file." ); } } function warnIfMissingInstrumentationFile(incomingUserNextConfigObject, userSentryOptions) { if (process.env[MISSING_INSTRUMENTATION_FILE_WARNING_SHOWN] || process.env.SENTRY_SUPPRESS_INSTRUMENTATION_FILE_WARNING) { return; } const projectDir = process.cwd(); const exists = (relativePath) => fs.existsSync(path.join(projectDir, relativePath)); const routerDir = ["pages", path.join("src", "pages"), "app", path.join("src", "app")].find(exists); if (!routerDir) { return; } const instrumentationDir = path.dirname(routerDir); const pageExtensions = incomingUserNextConfigObject.pageExtensions ?? util.DEFAULT_PAGE_EXTENSIONS; if (pageExtensions.some((extension) => exists(path.join(instrumentationDir, `instrumentation.${extension}`)))) { return; } process.env[MISSING_INSTRUMENTATION_FILE_WARNING_SHOWN] = "1"; buildLogger.getBuildLogger(userSentryOptions.silent).warn( `[@sentry/nextjs] Could not find an instrumentation file next to your ${routerDir} directory. Next.js production builds only load it from there, so the Sentry SDK will not be initialized on the server. Create ${path.join(instrumentationDir, "instrumentation.ts")}, or move your existing instrumentation file there: https://docs.sentry.io/platforms/javascript/guides/nextjs/manual-setup/#register-server-side-sdk (you can suppress this warning by setting SENTRY_SUPPRESS_INSTRUMENTATION_FILE_WARNING=1 as environment variable)` ); } function getNextMajor(nextJsVersion) { if (!nextJsVersion) { return void 0; } const { major } = core.parseSemver(nextJsVersion); return major; } function readVercelCronsConfig() { try { const vercelJsonPath = path.join(process.cwd(), "vercel.json"); const vercelJsonContents = fs.readFileSync(vercelJsonPath, "utf8"); const cronsConfig = JSON.parse(vercelJsonContents).crons; if (cronsConfig && Array.isArray(cronsConfig) && cronsConfig.length > 0) { return cronsConfig; } return void 0; } catch (e) { if (e.code === "ENOENT") { return void 0; } core.debug.error("[@sentry/nextjs] Failed to read vercel.json for automatic cron job monitoring instrumentation", e); return void 0; } } function maybeGetVercelCronsConfig(userSentryOptions) { const result = { config: void 0, strategy: void 0 }; if (!process.env.VERCEL) { return result; } const experimentalEnabled = userSentryOptions._experimental?.vercelCronsMonitoring === true; const legacyEnabled = userSentryOptions.webpack?.automaticVercelMonitors === true; if (!experimentalEnabled && !legacyEnabled) { return result; } const config = readVercelCronsConfig(); if (!config) { return result; } result.config = config; if (experimentalEnabled && legacyEnabled) { core.debug.warn( "[@sentry/nextjs] Both '_experimental.vercelCronsMonitoring' and 'webpack.automaticVercelMonitors' are enabled. Using the new span-based approach from '_experimental.vercelCronsMonitoring'. You can remove 'webpack.automaticVercelMonitors' from your config." ); result.strategy = "spans"; } else if (experimentalEnabled) { core.debug.log( "[@sentry/nextjs] Creating Sentry cron monitors for your Vercel Cron Jobs using span-based instrumentation." ); result.strategy = "spans"; } else { core.debug.log( "[@sentry/nextjs] Creating Sentry cron monitors for your Vercel Cron Jobs. You can disable this feature by setting the 'webpack.automaticVercelMonitors' option to false in your Next.js config." ); result.strategy = "wrapper"; } return result; } exports.filterRouteManifest = filterRouteManifest; exports.getNextMajor = getNextMajor; exports.maybeCreateRouteManifest = maybeCreateRouteManifest; exports.maybeGetVercelCronsConfig = maybeGetVercelCronsConfig; exports.maybeSetClientTraceMetadataOption = maybeSetClientTraceMetadataOption; exports.maybeSetInstrumentationHookOption = maybeSetInstrumentationHookOption; exports.maybeSetUpTunnelRouteRewriteRules = maybeSetUpTunnelRouteRewriteRules; exports.resolveReleaseName = resolveReleaseName; exports.shouldReturnEarlyInExperimentalBuildMode = shouldReturnEarlyInExperimentalBuildMode; exports.warnIfMissingInstrumentationFile = warnIfMissingInstrumentationFile; exports.warnIfMissingOnRouterTransitionStartHook = warnIfMissingOnRouterTransitionStartHook; //# sourceMappingURL=getFinalConfigObjectUtils.js.map