{"version":3,"file":"tanstackrouter.js","sources":["../../src/tanstackrouter.ts"],"sourcesContent":["import {\n browserTracingIntegration as originalBrowserTracingIntegration,\n getAbsoluteUrl,\n startBrowserTracingNavigationSpan,\n startBrowserTracingPageLoadSpan,\n WINDOW,\n} from '@sentry/browser';\nimport {\n PARAMS_KEY_BASE,\n URL_FULL,\n URL_PATH,\n URL_PATH_PARAMETER_KEY_BASE,\n URL_TEMPLATE,\n} from '@sentry/conventions/attributes';\nimport type { Integration } from '@sentry/core';\nimport {\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n SEMANTIC_ATTRIBUTE_SENTRY_SOURCE,\n filterCollectedUrl,\n} from '@sentry/core';\nimport type { AnyRouter } from '@tanstack/vue-router';\n\ntype RouteMatch = ReturnType[number];\n\ninterface TanstackRouterLocation {\n pathname: string;\n search: Record;\n state?: unknown;\n}\n\ninterface TanstackRouterSubscribeArgs {\n toLocation: TanstackRouterLocation;\n fromLocation?: { state: unknown };\n}\n\n/**\n * A custom browser tracing integration for TanStack Router.\n *\n * The minimum compatible version of `@tanstack/vue-router` is `1.64.0`.\n *\n * @param router A TanStack Router `Router` instance that should be used for routing instrumentation.\n * @param options Sentry browser tracing configuration.\n */\nexport function tanstackRouterBrowserTracingIntegration(\n router: R,\n options: Parameters[0] = {},\n): Integration {\n const browserTracingIntegrationInstance = originalBrowserTracingIntegration({\n ...options,\n instrumentNavigation: false,\n instrumentPageLoad: false,\n });\n\n const { instrumentPageLoad = true, instrumentNavigation = true } = options;\n\n return {\n ...browserTracingIntegrationInstance,\n afterAllSetup(client) {\n browserTracingIntegrationInstance.afterAllSetup(client);\n\n const resolveRouteMatch = (pathname: string, search: unknown): RouteMatch | undefined => {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const matchedRoutes = router.matchRoutes(pathname, search as any, { preload: false, throwOnError: false });\n const lastMatch = matchedRoutes[matchedRoutes.length - 1];\n // If we only match __root__, we ended up not matching any route at all, so\n // we fall back to the pathname.\n return lastMatch?.routeId !== '__root__' ? lastMatch : undefined;\n };\n\n const applyRouteMatch = (\n span: NonNullable>,\n match: RouteMatch | undefined,\n toLocation: TanstackRouterLocation,\n fallbackName: string,\n ): void => {\n span.updateName(match ? match.routeId : fallbackName);\n span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, match ? 'route' : 'url');\n span.setAttributes({\n [URL_TEMPLATE]: match?.routeId,\n ...locationToSpanUrlAttributes(router, toLocation),\n ...routeMatchToParamSpanAttributes(match),\n });\n };\n\n const initialWindowLocation = WINDOW.location;\n if (instrumentPageLoad && initialWindowLocation) {\n const routeMatch = resolveRouteMatch(\n initialWindowLocation.pathname,\n router.options.parseSearch(initialWindowLocation.search),\n );\n\n const pageloadSpan = startBrowserTracingPageLoadSpan(client, {\n name: routeMatch ? routeMatch.routeId : initialWindowLocation.pathname,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'pageload',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.pageload.vue.tanstack_router',\n [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: routeMatch ? 'route' : 'url',\n ...(routeMatch && { [URL_TEMPLATE]: routeMatch.routeId }),\n ...routeMatchToParamSpanAttributes(routeMatch),\n },\n });\n\n // A redirect thrown during the initial pageload leaves the span named after the pre-redirect\n // route, so correct it to the resolved route once.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const unsubscribePageloadResolved = router.subscribe('onResolved', (onResolvedArgs: any) => {\n unsubscribePageloadResolved();\n if (!pageloadSpan) {\n return;\n }\n const { toLocation } = onResolvedArgs as TanstackRouterSubscribeArgs;\n const resolvedMatch = resolveRouteMatch(toLocation.pathname, toLocation.search);\n applyRouteMatch(pageloadSpan, resolvedMatch, toLocation, toLocation.pathname);\n });\n }\n\n if (instrumentNavigation) {\n // Navigation is driven by `onBeforeLoad` (accurate start) + `onResolved` (final route), not\n // `onBeforeNavigate`, which TanStack stops firing after any loader redirect (TanStack/router#3920).\n // A redirect chain emits one `onBeforeLoad` per load but a single `onResolved`, so we start the\n // span on the first `onBeforeLoad`, rename it on later ones, and clear it on `onResolved`.\n let inFlightNavigationSpan: ReturnType | undefined;\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n router.subscribe('onBeforeLoad', (onBeforeLoadArgs: any) => {\n const { toLocation, fromLocation } = onBeforeLoadArgs as TanstackRouterSubscribeArgs;\n // Skip the initial pageload (no fromLocation) and no-op reloads (same state).\n if (!fromLocation || toLocation.state === fromLocation.state) {\n return;\n }\n\n const routeMatch = resolveRouteMatch(toLocation.pathname, toLocation.search);\n // In SSR/non-browser contexts, WINDOW.location may be undefined, so fall back to the router's location.\n const fallbackName = WINDOW.location?.pathname || toLocation.pathname;\n\n if (inFlightNavigationSpan) {\n // Redirect continuation within the same navigation: keep the span, update the target.\n applyRouteMatch(inFlightNavigationSpan, routeMatch, toLocation, fallbackName);\n return;\n }\n\n inFlightNavigationSpan = startBrowserTracingNavigationSpan(\n client,\n {\n name: routeMatch ? routeMatch.routeId : fallbackName,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'navigation',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.navigation.vue.tanstack_router',\n [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: routeMatch ? 'route' : 'url',\n ...(routeMatch && { [URL_TEMPLATE]: routeMatch.routeId }),\n ...routeMatchToParamSpanAttributes(routeMatch),\n },\n },\n { url: locationToAbsoluteUrl(router, toLocation) },\n );\n });\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n router.subscribe('onResolved', (onResolvedArgs: any) => {\n const span = inFlightNavigationSpan;\n inFlightNavigationSpan = undefined;\n if (!span) {\n return;\n }\n const { toLocation } = onResolvedArgs as TanstackRouterSubscribeArgs;\n const resolvedMatch = resolveRouteMatch(toLocation.pathname, toLocation.search);\n applyRouteMatch(span, resolvedMatch, toLocation, WINDOW.location?.pathname || toLocation.pathname);\n });\n }\n },\n };\n}\n\nfunction locationToAbsoluteUrl(router: R, location: TanstackRouterLocation): string {\n const search = router.options.stringifySearch(location.search);\n const pathWithSearch = `${location.pathname}${search && search !== '?' ? search : ''}`;\n\n return getAbsoluteUrl(pathWithSearch);\n}\n\nfunction locationToSpanUrlAttributes(\n router: R,\n location: TanstackRouterLocation,\n): Record {\n const absoluteUrl = locationToAbsoluteUrl(router, location);\n\n return {\n [URL_PATH]: location.pathname,\n [URL_FULL]: filterCollectedUrl(absoluteUrl),\n };\n}\n\nfunction routeMatchToParamSpanAttributes(match: RouteMatch | undefined): Record {\n if (!match) {\n return {};\n }\n\n const paramAttributes: Record = {};\n Object.entries(match.params as Record).forEach(([key, value]) => {\n paramAttributes[`${URL_PATH_PARAMETER_KEY_BASE}.${key}`] = value;\n paramAttributes[`${PARAMS_KEY_BASE}.${key}`] = value; // params.[key] is an alias\n });\n\n return paramAttributes;\n}\n"],"names":["originalBrowserTracingIntegration","SEMANTIC_ATTRIBUTE_SENTRY_SOURCE","URL_TEMPLATE","WINDOW","startBrowserTracingPageLoadSpan","SEMANTIC_ATTRIBUTE_SENTRY_OP","SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN","startBrowserTracingNavigationSpan","getAbsoluteUrl","URL_PATH","URL_FULL","filterCollectedUrl","URL_PATH_PARAMETER_KEY_BASE","PARAMS_KEY_BASE"],"mappings":"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"}