Files
klz-cables.com/.pnpm-store/v10/files/d1/b4a3f3531f50c9bc6e516b258f751021de382d7f221af9e387a26c07ca106be60db98310d390533b39275c91b8448a88999b24d5515ca0a6d1177dcb9df71a
Marc Mintel 5397309103
Some checks failed
Build & Deploy / 🔍 Prepare (push) Successful in 20s
Build & Deploy / 🧪 QA (push) Failing after 34s
Build & Deploy / 🏗️ Build (push) Has started running
Build & Deploy / 🚀 Deploy (push) Has been cancelled
Build & Deploy / 🧪 Smoke Test (push) Has been cancelled
Build & Deploy / ⚡ Lighthouse (push) Has been cancelled
Build & Deploy / 🔔 Notify (push) Has been cancelled
fix(products): fix breadcrumbs and product filtering (backport from main)
2026-02-24 16:04:21 +01:00

122 lines
4.4 KiB
Plaintext

import { withIsolationScope, getClient, debug, getActiveSpan, continueTrace, startSpan, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, handleCallbackErrors, SPAN_STATUS_ERROR, captureException, getIsolationScope } from '@sentry/core';
import { waitUntil, flushSafelyWithTimeout } from './utils/responseEnd.js';
import { DEBUG_BUILD } from './debug-build.js';
import { isNotFoundNavigationError, isRedirectNavigationError } from './nextNavigationErrorUtils.js';
/**
* Wraps a Next.js Server Action implementation with Sentry Error and Performance instrumentation.
*/
function withServerActionInstrumentation(
...args
) {
if (typeof args[1] === 'function') {
const [serverActionName, callback] = args;
return withServerActionInstrumentationImplementation(serverActionName, {}, callback);
} else {
const [serverActionName, options, callback] = args;
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
return withServerActionInstrumentationImplementation(serverActionName, options, callback);
}
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
async function withServerActionInstrumentationImplementation(
serverActionName,
options,
callback,
) {
return withIsolationScope(async isolationScope => {
const sendDefaultPii = getClient()?.getOptions().sendDefaultPii;
let sentryTraceHeader;
let baggageHeader;
const fullHeadersObject = {};
try {
const awaitedHeaders = await options.headers;
sentryTraceHeader = awaitedHeaders?.get('sentry-trace') ?? undefined;
baggageHeader = awaitedHeaders?.get('baggage');
awaitedHeaders?.forEach((value, key) => {
fullHeadersObject[key] = value;
});
} catch {
DEBUG_BUILD &&
debug.warn(
"Sentry wasn't able to extract the tracing headers for a server action. Will not trace this request.",
);
}
isolationScope.setTransactionName(`serverAction/${serverActionName}`);
isolationScope.setSDKProcessingMetadata({
normalizedRequest: {
headers: fullHeadersObject,
} ,
});
// Normally, there is an active span here (from Next.js OTEL) and we just use that as parent
// Else, we manually continueTrace from the incoming headers
const continueTraceIfNoActiveSpan = getActiveSpan()
? (_opts, callback) => callback()
: continueTrace;
return continueTraceIfNoActiveSpan(
{
sentryTrace: sentryTraceHeader,
baggage: baggageHeader,
},
async () => {
try {
return await startSpan(
{
op: 'function.server_action',
name: `serverAction/${serverActionName}`,
forceTransaction: true,
attributes: {
[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'route',
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.nextjs.server_action',
},
},
async span => {
const result = await handleCallbackErrors(callback, error => {
if (isNotFoundNavigationError(error)) {
// We don't want to report "not-found"s
span.setStatus({ code: SPAN_STATUS_ERROR, message: 'not_found' });
} else if (isRedirectNavigationError(error)) {
// Don't do anything for redirects
} else {
span.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });
captureException(error, {
mechanism: {
handled: false,
type: 'auto.function.nextjs.server_action',
},
});
}
});
if (options.recordResponse !== undefined ? options.recordResponse : sendDefaultPii) {
getIsolationScope().setExtra('server_action_result', result);
}
if (options.formData) {
options.formData.forEach((value, key) => {
getIsolationScope().setExtra(
`server_action_form_data.${key}`,
typeof value === 'string' ? value : '[non-string value]',
);
});
}
return result;
},
);
} finally {
waitUntil(flushSafelyWithTimeout());
}
},
);
});
}
export { withServerActionInstrumentation };
//# sourceMappingURL=withServerActionInstrumentation.js.map