UNPKG

@sentry/nextjs

Version:
118 lines (114 loc) 4.39 kB
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); const core = require('@sentry/core'); const react = require('@sentry/react'); const RouterImport = require('next/router'); const debugBuild = require('../../common/debug-build.js'); const attributes = require('@sentry/conventions/attributes'); const Router = RouterImport.default.events ? RouterImport.default : RouterImport.default.default; const globalObject = react.WINDOW; function extractNextDataTagInformation() { let nextData; const nextDataTag = globalObject.document.getElementById("__NEXT_DATA__"); if (nextDataTag?.innerHTML) { try { nextData = JSON.parse(nextDataTag.innerHTML); } catch { debugBuild.DEBUG_BUILD && core.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 = core.parseBaggageHeader(baggage); let name = route || 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, ""); } const origin = core.browserPerformanceTimeOrigin(); react.startBrowserTracingPageLoadSpan( client, { name, // pageload should always start at timeOrigin (and needs to be in s, not ms) startTime: origin ? origin / 1e3 : void 0, attributes: { [core.SEMANTIC_ATTRIBUTE_SENTRY_OP]: "pageload", [core.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: "auto.pageload.nextjs.pages_router_instrumentation", [core.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: route ? "route" : "url", ...route && { [attributes.URL_TEMPLATE]: route }, ...params && { ...params } } }, { sentryTrace, baggage } ); } function pagesRouterInstrumentNavigation(client) { Router.events.on("routeChangeStart", (navigationTarget) => { const strippedNavigationTarget = core.stripUrlQueryAndFragment(navigationTarget); const matchedRoute = getNextRouteFromPathname(strippedNavigationTarget); let newLocation; let spanSource; if (matchedRoute) { newLocation = matchedRoute; spanSource = "route"; } else { newLocation = strippedNavigationTarget; spanSource = "url"; } react.startBrowserTracingNavigationSpan( client, { name: newLocation, attributes: { [core.SEMANTIC_ATTRIBUTE_SENTRY_OP]: "navigation", [core.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: "auto.navigation.nextjs.pages_router_instrumentation", [core.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: spanSource, ...spanSource === "route" && { [attributes.URL_TEMPLATE]: newLocation } } }, { url: react.getAbsoluteUrl(navigationTarget) } ); }); } 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 ); } exports.pagesRouterInstrumentNavigation = pagesRouterInstrumentNavigation; exports.pagesRouterInstrumentPageLoad = pagesRouterInstrumentPageLoad; //# sourceMappingURL=pagesRouterRoutingInstrumentation.js.map