Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); const semanticConventions = require('@opentelemetry/semantic-conventions'); const core = require('@sentry/core'); const debugBuild = require('../debug-build.js'); const nextSpanAttributes = require('../nextSpanAttributes.js'); const spanAttributesWithLogicAttached = require('../span-attributes-with-logic-attached.js'); const PAGE_SEGMENT = '__PAGE__'; const commonIsolationScopeMap = new WeakMap(); /** * Takes a shared (garbage collectable) object between resources, e.g. a headers object shared between Next.js server components and returns a common propagation context. * * @param commonObject The shared object. * @param isolationScope The isolationScope that should be shared between all the resources if no isolation scope was created yet. * @returns the shared isolation scope. */ function commonObjectToIsolationScope(commonObject) { if (typeof commonObject === 'object' && commonObject) { const memoIsolationScope = commonIsolationScopeMap.get(commonObject); if (memoIsolationScope) { return memoIsolationScope; } else { const newIsolationScope = new core.Scope(); commonIsolationScopeMap.set(commonObject, newIsolationScope); return newIsolationScope; } } else { return new core.Scope(); } } let nextjsEscapedAsyncStorage; /** * Will mark the execution context of the callback as "escaped" from Next.js internal tracing by unsetting the active * span and propagation context. When an execution passes through this function multiple times, it is a noop after the * first time. */ function escapeNextjsTracing(cb) { const MaybeGlobalAsyncLocalStorage = (core.GLOBAL_OBJ ) .AsyncLocalStorage; if (!MaybeGlobalAsyncLocalStorage) { debugBuild.DEBUG_BUILD && core.debug.warn( "Tried to register AsyncLocalStorage async context strategy in a runtime that doesn't support AsyncLocalStorage.", ); return cb(); } if (!nextjsEscapedAsyncStorage) { nextjsEscapedAsyncStorage = new MaybeGlobalAsyncLocalStorage(); } if (nextjsEscapedAsyncStorage.getStore()) { return cb(); } else { return core.startNewTrace(() => { return nextjsEscapedAsyncStorage.run(true, () => { return cb(); }); }); } } /** * Ideally this function never lands in the develop branch. * * Drops the entire span tree this function was called in, if it was a span tree created by Next.js. */ function dropNextjsRootContext() { const nextJsOwnedSpan = core.getActiveSpan(); if (nextJsOwnedSpan) { const rootSpan = core.getRootSpan(nextJsOwnedSpan); const rootSpanAttributes = core.spanToJSON(rootSpan).data; if (rootSpanAttributes?.['next.span_type']) { core.getRootSpan(nextJsOwnedSpan)?.setAttribute(spanAttributesWithLogicAttached.TRANSACTION_ATTR_SHOULD_DROP_TRANSACTION, true); } } } /** * Checks if the span is a resolve segment span. * @param spanAttributes The attributes of the span to check. * @returns True if the span is a resolve segment span, false otherwise. */ function isResolveSegmentSpan(spanAttributes) { return ( spanAttributes[nextSpanAttributes.ATTR_NEXT_SPAN_TYPE] === 'NextNodeServer.getLayoutOrPageModule' && spanAttributes[nextSpanAttributes.ATTR_NEXT_SPAN_NAME] === 'resolve segment modules' && typeof spanAttributes[nextSpanAttributes.ATTR_NEXT_SEGMENT] === 'string' ); } /** * Returns the enhanced name for a resolve segment span. * @param segment The segment of the resolve segment span. * @param route The route of the resolve segment span. * @returns The enhanced name for the resolve segment span. */ function getEnhancedResolveSegmentSpanName({ segment, route }) { if (segment === PAGE_SEGMENT) { return `resolve page server component "${route}"`; } if (segment === '') { return 'resolve root layout server component'; } return `resolve layout server component "${segment}"`; } /** * Maybe enhances the span name for a resolve segment span. * If the span is not a resolve segment span, this function does nothing. * @param activeSpan The active span. * @param spanAttributes The attributes of the span to check. * @param rootSpanAttributes The attributes of the according root span. */ function maybeEnhanceServerComponentSpanName( activeSpan, spanAttributes, rootSpanAttributes, ) { if (!isResolveSegmentSpan(spanAttributes)) { return; } const segment = spanAttributes[nextSpanAttributes.ATTR_NEXT_SEGMENT] ; const route = rootSpanAttributes[semanticConventions.ATTR_HTTP_ROUTE]; const enhancedName = getEnhancedResolveSegmentSpanName({ segment, route: typeof route === 'string' ? route : '' }); activeSpan.updateName(enhancedName); activeSpan.setAttributes({ 'sentry.nextjs.ssr.function.type': segment === PAGE_SEGMENT ? 'Page' : 'Layout', 'sentry.nextjs.ssr.function.route': route, }); activeSpan.setAttribute(core.SEMANTIC_ATTRIBUTE_SENTRY_OP, 'function.nextjs'); } exports.commonObjectToIsolationScope = commonObjectToIsolationScope; exports.dropNextjsRootContext = dropNextjsRootContext; exports.escapeNextjsTracing = escapeNextjsTracing; exports.getEnhancedResolveSegmentSpanName = getEnhancedResolveSegmentSpanName; exports.isResolveSegmentSpan = isResolveSegmentSpan; exports.maybeEnhanceServerComponentSpanName = maybeEnhanceServerComponentSpanName; //# sourceMappingURL=tracingUtils.js.map