@sentry/nextjs
Version:
Official Sentry SDK for Next.js
83 lines (80 loc) • 3.06 kB
JavaScript
import { parseBaggageHeader, hasSpanStreamingEnabled, PAGELOAD_SPAN_NAME_FALLBACK, debug } from '@sentry/core';
import { WINDOW, startBrowserTracingPageLoadSpan } from '@sentry/react';
import { DEBUG_BUILD } from '../../common/debug-build.js';
import { URL_TEMPLATE, SENTRY_SEGMENT_NAME_SOURCE, SENTRY_ORIGIN, SENTRY_OP } from '@sentry/conventions/attributes';
import { PAGELOAD } from '@sentry/conventions/op';
const globalObject = WINDOW;
function extractNextDataTagInformation() {
let nextData;
const nextDataTag = globalObject.document.getElementById("__NEXT_DATA__");
if (nextDataTag?.innerHTML) {
try {
nextData = JSON.parse(nextDataTag.innerHTML);
} catch {
DEBUG_BUILD && debug.warn("Could not extract __NEXT_DATA__");
}
}
if (!nextData) {
return {};
}
const nextDataTagInfo = {};
const { page, query, props } = nextData;
nextDataTagInfo.route = page;
nextDataTagInfo.params = query;
if (props?.pageProps) {
nextDataTagInfo.sentryTrace = props.pageProps._sentryTraceData;
nextDataTagInfo.baggage = props.pageProps._sentryBaggage;
}
return nextDataTagInfo;
}
function pagesRouterInstrumentPageLoad(client) {
const { route, params, sentryTrace, baggage } = extractNextDataTagInformation();
const parsedBaggage = parseBaggageHeader(baggage);
let name = route || (hasSpanStreamingEnabled(client) ? PAGELOAD_SPAN_NAME_FALLBACK : globalObject.location.pathname);
if (parsedBaggage?.["sentry-transaction"] && name === "/_error") {
name = parsedBaggage["sentry-transaction"];
name = name.replace(/^(GET|POST|PUT|DELETE|PATCH|HEAD|OPTIONS|TRACE|CONNECT)\s+/i, "");
}
startBrowserTracingPageLoadSpan(
client,
{
name,
attributes: {
[SENTRY_OP]: PAGELOAD,
[SENTRY_ORIGIN]: "auto.pageload.nextjs.pages_router_instrumentation",
[SENTRY_SEGMENT_NAME_SOURCE]: route ? "route" : "url",
[URL_TEMPLATE]: route,
...params && { ...params }
}
},
{ sentryTrace, baggage }
);
}
function getNextRouteFromPathname(pathname) {
const pageRoutes = globalObject.__BUILD_MANIFEST?.sortedPages;
if (!pageRoutes) {
return;
}
return pageRoutes.find((route) => {
const routeRegExp = convertNextRouteToRegExp(route);
return pathname.match(routeRegExp);
});
}
function convertNextRouteToRegExp(route) {
const routeParts = route.split("/");
let optionalCatchallWildcardRegex = "";
if (routeParts[routeParts.length - 1]?.match(/^\[\[\.\.\..+\]\]$/)) {
routeParts.pop();
optionalCatchallWildcardRegex = "(?:/(.+?))?";
}
const rejoinedRouteParts = routeParts.map(
(routePart) => routePart.replace(/^\[\.\.\..+\]$/, "(.+?)").replace(/^\[.*\]$/, "([^/]+?)")
// Replace route wildcards with lazy regex wildcards
).join("/");
return new RegExp(
`^${rejoinedRouteParts}${optionalCatchallWildcardRegex}(?:/)?$`
// optional slash at the end
);
}
export { getNextRouteFromPathname, pagesRouterInstrumentPageLoad };
//# sourceMappingURL=pagesRouterRoutingInstrumentation.js.map