import { context } from '@opentelemetry/api'; import { registerSpanErrorInstrumentation, GLOBAL_OBJ, applySdkMetadata, spanToJSON, getRootSpan, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, getCapturedScopesOnSpan, getIsolationScope, getCurrentScope, setCapturedScopesOnSpan, stripUrlQueryAndFragment, getGlobalScope } from '@sentry/core'; import { getScopesFromContext } from '@sentry/opentelemetry'; import { getDefaultIntegrations, init as init$1 } from '@sentry/vercel-edge'; export * from '@sentry/vercel-edge'; import { DEBUG_BUILD } from '../common/debug-build.js'; import { ATTR_NEXT_SPAN_TYPE } from '../common/nextSpanAttributes.js'; import { TRANSACTION_ATTR_SHOULD_DROP_TRANSACTION } from '../common/span-attributes-with-logic-attached.js'; import { addHeadersAsAttributes } from '../common/utils/addHeadersAsAttributes.js'; import { dropMiddlewareTunnelRequests } from '../common/utils/dropMiddlewareTunnelRequests.js'; import { isBuild } from '../common/utils/isBuild.js'; import { isCloudflareWaitUntilAvailable, waitUntil, flushSafelyWithTimeout } from '../common/utils/responseEnd.js'; import { setUrlProcessingMetadata } from '../common/utils/setUrlProcessingMetadata.js'; import { distDirRewriteFramesIntegration } from './distDirRewriteFramesIntegration.js'; export { wrapGetStaticPropsWithSentry } from '../common/pages-router-instrumentation/wrapGetStaticPropsWithSentry.js'; export { wrapGetInitialPropsWithSentry } from '../common/pages-router-instrumentation/wrapGetInitialPropsWithSentry.js'; export { wrapAppGetInitialPropsWithSentry } from '../common/pages-router-instrumentation/wrapAppGetInitialPropsWithSentry.js'; export { wrapDocumentGetInitialPropsWithSentry } from '../common/pages-router-instrumentation/wrapDocumentGetInitialPropsWithSentry.js'; export { wrapErrorGetInitialPropsWithSentry } from '../common/pages-router-instrumentation/wrapErrorGetInitialPropsWithSentry.js'; export { wrapGetServerSidePropsWithSentry } from '../common/pages-router-instrumentation/wrapGetServerSidePropsWithSentry.js'; export { wrapServerComponentWithSentry } from '../common/wrapServerComponentWithSentry.js'; export { wrapRouteHandlerWithSentry } from '../common/wrapRouteHandlerWithSentry.js'; export { wrapApiHandlerWithSentryVercelCrons } from '../common/pages-router-instrumentation/wrapApiHandlerWithSentryVercelCrons.js'; export { wrapMiddlewareWithSentry } from '../common/wrapMiddlewareWithSentry.js'; export { wrapPageComponentWithSentry } from '../common/pages-router-instrumentation/wrapPageComponentWithSentry.js'; export { wrapGenerationFunctionWithSentry } from '../common/wrapGenerationFunctionWithSentry.js'; export { withServerActionInstrumentation } from '../common/withServerActionInstrumentation.js'; export { captureRequestError } from '../common/captureRequestError.js'; export { captureUnderscoreErrorException } from '../common/pages-router-instrumentation/_error.js'; export { startInactiveSpan, startSpan, startSpanManual } from '../common/utils/nextSpan.js'; export { wrapApiHandlerWithSentry } from './wrapApiHandlerWithSentry.js'; // import/export got a false positive, and affects most of our index barrel files // can be removed once following issue is fixed: https://github.com/import-js/eslint-plugin-import/issues/703 /* eslint-disable import/export */ const globalWithInjectedValues = GLOBAL_OBJ ; /** Inits the Sentry NextJS SDK on the Edge Runtime. */ function init(options = {}) { registerSpanErrorInstrumentation(); if (isBuild()) { return; } if (!DEBUG_BUILD && options.debug) { // eslint-disable-next-line no-console console.warn( '[@sentry/nextjs] You have enabled `debug: true`, but Sentry debug logging was removed from your bundle (likely via `withSentryConfig({ disableLogger: true })` / `webpack.treeshake.removeDebugLogging: true`). Set that option to `false` to see Sentry debug output.', ); } const customDefaultIntegrations = getDefaultIntegrations(options); // This value is injected at build time, based on the output directory specified in the build config. Though a default // is set there, we set it here as well, just in case something has gone wrong with the injection. const distDirName = process.env._sentryRewriteFramesDistDir || globalWithInjectedValues._sentryRewriteFramesDistDir; if (distDirName) { customDefaultIntegrations.push(distDirRewriteFramesIntegration({ distDirName })); } // Detect if running on OpenNext/Cloudflare const isRunningOnCloudflare = isCloudflareWaitUntilAvailable(); const opts = { defaultIntegrations: customDefaultIntegrations, release: process.env._sentryRelease || globalWithInjectedValues._sentryRelease, ...options, // Override runtime to 'cloudflare' when running on OpenNext/Cloudflare ...(isRunningOnCloudflare && { runtime: { name: 'cloudflare' } }), }; // Use appropriate SDK metadata based on the runtime environment if (isRunningOnCloudflare) { applySdkMetadata(opts, 'nextjs', ['nextjs', 'cloudflare']); } else { applySdkMetadata(opts, 'nextjs', ['nextjs', 'vercel-edge']); } const client = init$1(opts); client?.on('spanStart', span => { const spanAttributes = spanToJSON(span).data; const rootSpan = getRootSpan(span); const isRootSpan = span === rootSpan; dropMiddlewareTunnelRequests(span, spanAttributes); // Mark all spans generated by Next.js as 'auto' if (spanAttributes?.['next.span_type'] !== undefined) { span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, 'auto'); } // Make sure middleware spans get the right op if (spanAttributes?.['next.span_type'] === 'Middleware.execute') { span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_OP, 'http.server.middleware'); span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, 'url'); } // We want to fork the isolation scope for incoming requests if (spanAttributes?.[ATTR_NEXT_SPAN_TYPE] === 'BaseServer.handleRequest' && isRootSpan) { const scopes = getCapturedScopesOnSpan(span); const isolationScope = (scopes.isolationScope || getIsolationScope()).clone(); const scope = scopes.scope || getCurrentScope(); const currentScopesPointer = getScopesFromContext(context.active()); if (currentScopesPointer) { currentScopesPointer.isolationScope = isolationScope; } setCapturedScopesOnSpan(span, scope, isolationScope); } if (isRootSpan) { // todo: check if we can set request headers for edge on sdkProcessingMetadata const headers = getIsolationScope().getScopeData().sdkProcessingMetadata?.normalizedRequest?.headers; addHeadersAsAttributes(headers, rootSpan); } }); // Use the preprocessEvent hook instead of an event processor, so that the users event processors receive the most // up-to-date value, but also so that the logic that detects changes to the transaction names to set the source to // "custom", doesn't trigger. client?.on('preprocessEvent', event => { // The otel auto inference will clobber the transaction name because the span has an http.target if ( event.type === 'transaction' && event.contexts?.trace?.data?.['next.span_type'] === 'Middleware.execute' && event.contexts?.trace?.data?.['next.span_name'] ) { if (event.transaction) { // Older nextjs versions pass the full url appended to the middleware name, which results in high cardinality transaction names. // We want to remove the url from the name here. const spanName = event.contexts.trace.data['next.span_name']; if (typeof spanName === 'string') { const match = spanName.match(/^middleware (GET|POST|PUT|DELETE|PATCH|HEAD|OPTIONS)/); if (match) { const normalizedName = `middleware ${match[1]}`; event.transaction = normalizedName; } else { event.transaction = stripUrlQueryAndFragment(event.contexts.trace.data['next.span_name']); } } } } setUrlProcessingMetadata(event); }); client?.on('spanEnd', span => { if (span === getRootSpan(span)) { waitUntil(flushSafelyWithTimeout()); } }); getGlobalScope().addEventProcessor( Object.assign( (event => { // Filter transactions that we explicitly want to drop. if (event.type === 'transaction') { if (event.contexts?.trace?.data?.[TRANSACTION_ATTR_SHOULD_DROP_TRANSACTION]) { return null; } return event; } else { return event; } }) , { id: 'NextLowQualityTransactionsFilter' }, ), ); try { // @ts-expect-error `process.turbopack` is a magic string that will be replaced by Next.js if (process.turbopack) { getGlobalScope().setTag('turbopack', true); } } catch { // Noop // The statement above can throw because process is not defined on the client } } /** * Just a passthrough in case this is imported from the client. */ function withSentryConfig(exportedUserNextConfig) { return exportedUserNextConfig; } export { init, withSentryConfig }; //# sourceMappingURL=index.js.map