diff --git a/packages/react/src/tanstackrouter.ts b/packages/react/src/tanstackrouter.ts index e6d1a1e0e681..033864c56b99 100644 --- a/packages/react/src/tanstackrouter.ts +++ b/packages/react/src/tanstackrouter.ts @@ -7,10 +7,12 @@ import { } from '@sentry/browser'; import type { Integration } from '@sentry/core/browser'; import { + createUrlRouteProvider, filterCollectedUrl, hasSpanStreamingEnabled, NAVIGATION_SPAN_NAME_FALLBACK, PAGELOAD_SPAN_NAME_FALLBACK, + setRouteProvider, } from '@sentry/core'; import { SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN } from '@sentry/core/browser'; import type { VendoredTanstackRouter, VendoredTanstackRouterRouteMatch } from './vendor/tanstackrouter-types'; @@ -54,22 +56,34 @@ export function tanstackRouterBrowserTracingIntegration( const { instrumentPageLoad = true, instrumentNavigation = true } = options; + const resolveRouteMatch = (pathname: string, search: unknown): VendoredTanstackRouterRouteMatch | undefined => { + const matchedRoutes = castRouterInstance.matchRoutes(pathname, search as {}, { + preload: false, + throwOnError: false, + }); + const lastMatch = matchedRoutes[matchedRoutes.length - 1]; + // If we only match __root__, we ended up not matching any route at all, so + // we fall back to the pathname. + return lastMatch?.routeId !== '__root__' ? lastMatch : undefined; + }; + return { ...browserTracingIntegrationInstance, + setup(client) { + // Registered before `afterAllSetup` so the provider is in place by the time the pageload span + // is named. + setRouteProvider( + createUrlRouteProvider( + url => resolveRouteMatch(url.pathname, castRouterInstance.options.parseSearch(url.search))?.routeId, + ), + client, + ); + + browserTracingIntegrationInstance.setup?.(client); + }, afterAllSetup(client) { browserTracingIntegrationInstance.afterAllSetup(client); - const resolveRouteMatch = (pathname: string, search: unknown): VendoredTanstackRouterRouteMatch | undefined => { - const matchedRoutes = castRouterInstance.matchRoutes(pathname, search as {}, { - preload: false, - throwOnError: false, - }); - const lastMatch = matchedRoutes[matchedRoutes.length - 1]; - // If we only match __root__, we ended up not matching any route at all, so - // we fall back to the pathname. - return lastMatch?.routeId !== '__root__' ? lastMatch : undefined; - }; - const applyRouteMatch = ( span: NonNullable>, match: VendoredTanstackRouterRouteMatch | undefined, diff --git a/packages/solid/src/tanstackrouter.ts b/packages/solid/src/tanstackrouter.ts index 29dd7874924a..bd923afc15b6 100644 --- a/packages/solid/src/tanstackrouter.ts +++ b/packages/solid/src/tanstackrouter.ts @@ -17,9 +17,11 @@ import { import { NAVIGATION, PAGELOAD } from '@sentry/conventions/op'; import type { Integration } from '@sentry/core'; import { + createUrlRouteProvider, hasSpanStreamingEnabled, NAVIGATION_SPAN_NAME_FALLBACK, PAGELOAD_SPAN_NAME_FALLBACK, + setRouteProvider, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, filterCollectedUrl, } from '@sentry/core'; @@ -53,19 +55,29 @@ export function tanstackRouterBrowserTracingIntegration( const { instrumentPageLoad = true, instrumentNavigation = true } = options; + const resolveRouteMatch = (pathname: string, search: Record): RouteMatch | undefined => { + const matchedRoutes = router.matchRoutes(pathname, search, { preload: false, throwOnError: false }); + const lastMatch = matchedRoutes[matchedRoutes.length - 1]; + // If we only match __root__, we ended up not matching any route at all, so + // we fall back to the pathname. + return lastMatch?.routeId !== '__root__' ? lastMatch : undefined; + }; + return { ...browserTracingIntegrationInstance, + setup(client) { + // Registered before `afterAllSetup` so the provider is in place by the time the pageload span + // is named. + setRouteProvider( + createUrlRouteProvider(url => resolveRouteMatch(url.pathname, router.options.parseSearch(url.search))?.routeId), + client, + ); + + browserTracingIntegrationInstance.setup?.(client); + }, afterAllSetup(client) { browserTracingIntegrationInstance.afterAllSetup(client); - const resolveRouteMatch = (pathname: string, search: Record): RouteMatch | undefined => { - const matchedRoutes = router.matchRoutes(pathname, search, { preload: false, throwOnError: false }); - const lastMatch = matchedRoutes[matchedRoutes.length - 1]; - // If we only match __root__, we ended up not matching any route at all, so - // we fall back to the pathname. - return lastMatch?.routeId !== '__root__' ? lastMatch : undefined; - }; - const applyRouteMatch = ( span: NonNullable>, match: RouteMatch | undefined, diff --git a/packages/vue/src/tanstackrouter.ts b/packages/vue/src/tanstackrouter.ts index ed2c659c76f9..86a1a75b7cd1 100644 --- a/packages/vue/src/tanstackrouter.ts +++ b/packages/vue/src/tanstackrouter.ts @@ -17,9 +17,11 @@ import { import { NAVIGATION, PAGELOAD } from '@sentry/conventions/op'; import type { Integration } from '@sentry/core'; import { + createUrlRouteProvider, hasSpanStreamingEnabled, NAVIGATION_SPAN_NAME_FALLBACK, PAGELOAD_SPAN_NAME_FALLBACK, + setRouteProvider, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, filterCollectedUrl, } from '@sentry/core'; @@ -58,20 +60,30 @@ export function tanstackRouterBrowserTracingIntegration( const { instrumentPageLoad = true, instrumentNavigation = true } = options; + const resolveRouteMatch = (pathname: string, search: unknown): RouteMatch | undefined => { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const matchedRoutes = router.matchRoutes(pathname, search as any, { preload: false, throwOnError: false }); + const lastMatch = matchedRoutes[matchedRoutes.length - 1]; + // If we only match __root__, we ended up not matching any route at all, so + // we fall back to the pathname. + return lastMatch?.routeId !== '__root__' ? lastMatch : undefined; + }; + return { ...browserTracingIntegrationInstance, + setup(client) { + // Registered before `afterAllSetup` so the provider is in place by the time the pageload span + // is named. + setRouteProvider( + createUrlRouteProvider(url => resolveRouteMatch(url.pathname, router.options.parseSearch(url.search))?.routeId), + client, + ); + + browserTracingIntegrationInstance.setup?.(client); + }, afterAllSetup(client) { browserTracingIntegrationInstance.afterAllSetup(client); - const resolveRouteMatch = (pathname: string, search: unknown): RouteMatch | undefined => { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const matchedRoutes = router.matchRoutes(pathname, search as any, { preload: false, throwOnError: false }); - const lastMatch = matchedRoutes[matchedRoutes.length - 1]; - // If we only match __root__, we ended up not matching any route at all, so - // we fall back to the pathname. - return lastMatch?.routeId !== '__root__' ? lastMatch : undefined; - }; - const applyRouteMatch = ( span: NonNullable>, match: RouteMatch | undefined,