@sentry/nextjs
Version:
Official Sentry SDK for Next.js
233 lines (230 loc) • 11 kB
JavaScript
import { debug, parseSemver, isMatchingPattern } from '@sentry/core';
import { getSentryRelease } from '@sentry/node';
import * as fs from 'fs';
import { createRequire } from 'module';
import * as path from 'path';
import { createRouteManifest } from '../manifest/createRouteManifest.js';
import { requiresInstrumentationHook } from '../util.js';
import { getGitRevision, getInstrumentationClientFileContents } from './buildTime.js';
import { resolveTunnelRoute, setUpTunnelRewriteRules } from './tunnel.js';
let showedExportModeTunnelWarning = false;
let showedExperimentalBuildModeWarning = false;
function resolveReleaseName(userSentryOptions) {
const shouldCreateRelease = userSentryOptions.release?.create !== false;
return shouldCreateRelease ? userSentryOptions.release?.name ?? getSentryRelease() ?? getGitRevision() : userSentryOptions.release?.name;
}
function maybeSetUpTunnelRouteRewriteRules(incomingUserNextConfigObject, userSentryOptions) {
if (!userSentryOptions.tunnelRoute) {
return;
}
if (incomingUserNextConfigObject.output === "export") {
if (!showedExportModeTunnelWarning) {
showedExportModeTunnelWarning = true;
console.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 = resolveTunnelRoute(userSentryOptions.tunnelRoute);
userSentryOptions.tunnelRoute = resolvedTunnelRoute || void 0;
setUpTunnelRewriteRules(incomingUserNextConfigObject, resolvedTunnelRoute);
}
function shouldReturnEarlyInExperimentalBuildMode() {
if (!process.argv.includes("--experimental-build-mode")) {
return false;
}
if (!showedExperimentalBuildModeWarning) {
showedExperimentalBuildModeWarning = true;
console.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.disableManifestInjection) {
console.warn(
"[@sentry/nextjs] The `disableManifestInjection` option is deprecated. Use `routeManifestInjection: false` instead."
);
}
if (userSentryOptions.routeManifestInjection === false) {
return void 0;
}
if (userSentryOptions.routeManifestInjection === void 0 && userSentryOptions.disableManifestInjection) {
return void 0;
}
const manifest = createRouteManifest({
basePath: incomingUserNextConfigObject.basePath
});
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) => isMatchingPattern(route, pattern));
};
return {
staticRoutes: manifest.staticRoutes.filter((r) => !shouldExclude(r.path)),
dynamicRoutes: manifest.dynamicRoutes.filter((r) => !shouldExclude(r.path)),
isrRoutes: manifest.isrRoutes.filter((r) => !shouldExclude(r))
};
}
function maybeSetClientTraceMetadataOption(incomingUserNextConfigObject, nextJsVersion) {
if (incomingUserNextConfigObject.cacheComponents) {
return;
}
if (nextJsVersion) {
const { major, minor } = 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",
...incomingUserNextConfigObject.experimental?.clientTraceMetadata || []
];
}
} else {
console.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']` to your Next.js config to enable pageload tracing for App Router."
);
}
}
function maybeSetInstrumentationHookOption(incomingUserNextConfigObject, nextJsVersion) {
if (nextJsVersion && requiresInstrumentationHook(nextJsVersion)) {
if (incomingUserNextConfigObject.experimental?.instrumentationHook === false) {
console.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) {
console.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 {
console.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 = getInstrumentationClientFileContents();
if (instrumentationClientFileContents !== void 0 && !instrumentationClientFileContents.includes("onRouterTransitionStart") && !userSentryOptions.suppressOnRouterTransitionStartWarning) {
console.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 getNextMajor(nextJsVersion) {
if (!nextJsVersion) {
return void 0;
}
const { major } = parseSemver(nextJsVersion);
return major;
}
function maybeAddOutputFileTracingIncludes(incomingUserNextConfigObject, nextJsVersion) {
if (!nextJsVersion) {
return;
}
const { major, minor } = parseSemver(nextJsVersion);
if (major === void 0 || minor === void 0 || major < 14 || major === 14 && minor < 1) {
return;
}
let meriyahDistDir;
try {
const serverUtilsPkgPath = createRequire(`${__dirname}/`).resolve("@sentry/server-utils/package.json");
meriyahDistDir = path.dirname(createRequire(serverUtilsPkgPath).resolve("meriyah"));
} catch {
return;
}
const meriyahIncludes = ["meriyah.mjs", "meriyah.cjs"].map(
(file) => path.relative(process.cwd(), path.join(meriyahDistDir, file)).replace(/\\/g, "/")
);
const mergeIncludes = (existing) => ({
...existing,
"/*": [.../* @__PURE__ */ new Set([...existing?.["/*"] ?? [], ...meriyahIncludes])]
});
if (major >= 15) {
incomingUserNextConfigObject.outputFileTracingIncludes = mergeIncludes(
incomingUserNextConfigObject.outputFileTracingIncludes
);
} else {
incomingUserNextConfigObject.experimental = {
...incomingUserNextConfigObject.experimental,
outputFileTracingIncludes: mergeIncludes(incomingUserNextConfigObject.experimental?.outputFileTracingIncludes)
};
}
}
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;
}
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) {
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) {
debug.log(
"[@sentry/nextjs] Creating Sentry cron monitors for your Vercel Cron Jobs using span-based instrumentation."
);
result.strategy = "spans";
} else {
debug.log(
"[@sentry/nextjs] Creating Sentry cron monitors for your Vercel Cron Jobs. You can disable this feature by setting the 'automaticVercelMonitors' option to false in your Next.js config."
);
result.strategy = "wrapper";
}
return result;
}
export { filterRouteManifest, getNextMajor, maybeAddOutputFileTracingIncludes, maybeCreateRouteManifest, maybeGetVercelCronsConfig, maybeSetClientTraceMetadataOption, maybeSetInstrumentationHookOption, maybeSetUpTunnelRouteRewriteRules, resolveReleaseName, shouldReturnEarlyInExperimentalBuildMode, warnIfMissingOnRouterTransitionStartHook };
//# sourceMappingURL=getFinalConfigObjectUtils.js.map