@sentry/react 10.63.0 → 10.65.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/cjs/reactrouter-compat-utils/instrumentation.js +15 -1
- package/build/cjs/reactrouter-compat-utils/instrumentation.js.map +1 -1
- package/build/cjs/reactrouter.js +6 -3
- package/build/cjs/reactrouter.js.map +1 -1
- package/build/cjs/reactrouterv3.js +5 -2
- package/build/cjs/reactrouterv3.js.map +1 -1
- package/build/cjs/tanstackrouter.js +80 -42
- package/build/cjs/tanstackrouter.js.map +1 -1
- package/build/esm/package.json +1 -1
- package/build/esm/reactrouter-compat-utils/instrumentation.js +15 -1
- package/build/esm/reactrouter-compat-utils/instrumentation.js.map +1 -1
- package/build/esm/reactrouter.js +6 -3
- package/build/esm/reactrouter.js.map +1 -1
- package/build/esm/reactrouterv3.js +5 -2
- package/build/esm/reactrouterv3.js.map +1 -1
- package/build/esm/tanstackrouter.js +81 -43
- package/build/esm/tanstackrouter.js.map +1 -1
- package/build/types/reactrouter-compat-utils/instrumentation.d.ts.map +1 -1
- package/build/types/reactrouter.d.ts.map +1 -1
- package/build/types/reactrouterv3.d.ts.map +1 -1
- package/build/types/tanstackrouter.d.ts.map +1 -1
- package/build/types/vendor/tanstackrouter-types.d.ts +2 -1
- package/build/types/vendor/tanstackrouter-types.d.ts.map +1 -1
- package/build/types-ts3.8/vendor/tanstackrouter-types.d.ts +2 -1
- package/package.json +4 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reactrouterv3.js","sources":["../../src/reactrouterv3.ts"],"sourcesContent":["import {\n browserTracingIntegration,\n startBrowserTracingNavigationSpan,\n startBrowserTracingPageLoadSpan,\n WINDOW,\n} from '@sentry/browser';\nimport type { Integration, TransactionSource } from '@sentry/core/browser';\nimport {\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n SEMANTIC_ATTRIBUTE_SENTRY_SOURCE,\n} from '@sentry/core/browser';\nimport type { Location } from './types';\n\n// Many of the types below had to be mocked out to prevent typescript issues\n// these types are required for correct functionality.\n\ntype HistoryV3 = {\n location?: Location;\n listen?(cb: (location: Location) => void): void;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n} & Record<string, any>;\n\nexport type Route = { path?: string; childRoutes?: Route[] };\n\nexport type Match = (\n props: { location: Location; routes: Route[] },\n cb: (error?: Error, _redirectLocation?: Location, renderProps?: { routes?: Route[] }) => void,\n) => void;\n\ntype ReactRouterV3TransactionSource = Extract<TransactionSource, 'url' | 'route'>;\n\ninterface ReactRouterOptions {\n history: HistoryV3;\n routes: Route[];\n match: Match;\n}\n\n/**\n * A browser tracing integration that uses React Router v3 to instrument navigations.\n * Expects `history` (and optionally `routes` and `matchPath`) to be passed as options.\n */\nexport function reactRouterV3BrowserTracingIntegration(\n options: Parameters<typeof browserTracingIntegration>[0] & ReactRouterOptions,\n): Integration {\n const integration = browserTracingIntegration({\n ...options,\n instrumentPageLoad: false,\n instrumentNavigation: false,\n });\n\n const { history, routes, match, instrumentPageLoad = true, instrumentNavigation = true } = options;\n\n return {\n ...integration,\n afterAllSetup(client) {\n integration.afterAllSetup(client);\n\n if (instrumentPageLoad && WINDOW.location) {\n normalizeTransactionName(\n routes,\n WINDOW.location as unknown as Location,\n match,\n (localName: string, source: ReactRouterV3TransactionSource = 'url') => {\n startBrowserTracingPageLoadSpan(client, {\n name: localName,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'pageload',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.pageload.react.reactrouter_v3',\n [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: source,\n },\n });\n },\n );\n }\n\n if (instrumentNavigation && history.listen) {\n history.listen(location => {\n if (location.action === 'PUSH' || location.action === 'POP') {\n normalizeTransactionName(\n routes,\n location,\n match,\n (localName: string, source: TransactionSource = 'url') => {\n startBrowserTracingNavigationSpan(client, {\n name: localName,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'navigation',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.navigation.react.reactrouter_v3',\n [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: source,\n },\n });\n },\n );\n }\n });\n }\n },\n };\n}\n\n/**\n * Normalize transaction names using `Router.match`\n */\nfunction normalizeTransactionName(\n appRoutes: Route[],\n location: Location,\n match: Match,\n callback: (pathname: string, source?: ReactRouterV3TransactionSource) => void,\n): void {\n let name = location.pathname;\n match(\n {\n location,\n routes: appRoutes,\n },\n (error, _redirectLocation, renderProps) => {\n if (error || !renderProps) {\n return callback(name);\n }\n\n const routePath = getRouteStringFromRoutes(renderProps.routes || []);\n if (routePath.length === 0 || routePath === '/*') {\n return callback(name);\n }\n\n name = routePath;\n return callback(name, 'route');\n },\n );\n}\n\n/**\n * Generate route name from array of routes\n */\nfunction getRouteStringFromRoutes(routes: Route[]): string {\n if (!Array.isArray(routes) || routes.length === 0) {\n return '';\n }\n\n const routesWithPaths: Route[] = routes.filter((route: Route) => !!route.path);\n\n let index = -1;\n for (let x = routesWithPaths.length - 1; x >= 0; x--) {\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n const route = routesWithPaths[x]!;\n if (route.path?.startsWith('/')) {\n index = x;\n break;\n }\n }\n\n return routesWithPaths.slice(index).reduce((acc, { path }) => {\n const pathSegment = acc === '/' || acc === '' ? path : `/${path}`;\n return `${acc}${pathSegment}`;\n }, '');\n}\n"],"names":["browserTracingIntegration","WINDOW","startBrowserTracingPageLoadSpan","SEMANTIC_ATTRIBUTE_SENTRY_OP","SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN","SEMANTIC_ATTRIBUTE_SENTRY_SOURCE","startBrowserTracingNavigationSpan"],"mappings":"
|
|
1
|
+
{"version":3,"file":"reactrouterv3.js","sources":["../../src/reactrouterv3.ts"],"sourcesContent":["import {\n browserTracingIntegration,\n startBrowserTracingNavigationSpan,\n startBrowserTracingPageLoadSpan,\n WINDOW,\n} from '@sentry/browser';\nimport type { Integration, TransactionSource } from '@sentry/core/browser';\nimport {\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n SEMANTIC_ATTRIBUTE_SENTRY_SOURCE,\n} from '@sentry/core/browser';\nimport type { Location } from './types';\nimport { URL_TEMPLATE } from '@sentry/conventions/attributes';\n\n// Many of the types below had to be mocked out to prevent typescript issues\n// these types are required for correct functionality.\n\ntype HistoryV3 = {\n location?: Location;\n listen?(cb: (location: Location) => void): void;\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n} & Record<string, any>;\n\nexport type Route = { path?: string; childRoutes?: Route[] };\n\nexport type Match = (\n props: { location: Location; routes: Route[] },\n cb: (error?: Error, _redirectLocation?: Location, renderProps?: { routes?: Route[] }) => void,\n) => void;\n\ntype ReactRouterV3TransactionSource = Extract<TransactionSource, 'url' | 'route'>;\n\ninterface ReactRouterOptions {\n history: HistoryV3;\n routes: Route[];\n match: Match;\n}\n\n/**\n * A browser tracing integration that uses React Router v3 to instrument navigations.\n * Expects `history` (and optionally `routes` and `matchPath`) to be passed as options.\n */\nexport function reactRouterV3BrowserTracingIntegration(\n options: Parameters<typeof browserTracingIntegration>[0] & ReactRouterOptions,\n): Integration {\n const integration = browserTracingIntegration({\n ...options,\n instrumentPageLoad: false,\n instrumentNavigation: false,\n });\n\n const { history, routes, match, instrumentPageLoad = true, instrumentNavigation = true } = options;\n\n return {\n ...integration,\n afterAllSetup(client) {\n integration.afterAllSetup(client);\n\n if (instrumentPageLoad && WINDOW.location) {\n normalizeTransactionName(\n routes,\n WINDOW.location as unknown as Location,\n match,\n (localName: string, source: ReactRouterV3TransactionSource = 'url') => {\n startBrowserTracingPageLoadSpan(client, {\n name: localName,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'pageload',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.pageload.react.reactrouter_v3',\n [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: source,\n ...(source === 'route' && { [URL_TEMPLATE]: localName }),\n },\n });\n },\n );\n }\n\n if (instrumentNavigation && history.listen) {\n history.listen(location => {\n if (location.action === 'PUSH' || location.action === 'POP') {\n normalizeTransactionName(\n routes,\n location,\n match,\n (localName: string, source: TransactionSource = 'url') => {\n startBrowserTracingNavigationSpan(client, {\n name: localName,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'navigation',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.navigation.react.reactrouter_v3',\n [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: source,\n ...(source === 'route' && { [URL_TEMPLATE]: localName }),\n },\n });\n },\n );\n }\n });\n }\n },\n };\n}\n\n/**\n * Normalize transaction names using `Router.match`\n */\nfunction normalizeTransactionName(\n appRoutes: Route[],\n location: Location,\n match: Match,\n callback: (pathname: string, source?: ReactRouterV3TransactionSource) => void,\n): void {\n let name = location.pathname;\n match(\n {\n location,\n routes: appRoutes,\n },\n (error, _redirectLocation, renderProps) => {\n if (error || !renderProps) {\n return callback(name);\n }\n\n const routePath = getRouteStringFromRoutes(renderProps.routes || []);\n if (routePath.length === 0 || routePath === '/*') {\n return callback(name);\n }\n\n name = routePath;\n return callback(name, 'route');\n },\n );\n}\n\n/**\n * Generate route name from array of routes\n */\nfunction getRouteStringFromRoutes(routes: Route[]): string {\n if (!Array.isArray(routes) || routes.length === 0) {\n return '';\n }\n\n const routesWithPaths: Route[] = routes.filter((route: Route) => !!route.path);\n\n let index = -1;\n for (let x = routesWithPaths.length - 1; x >= 0; x--) {\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n const route = routesWithPaths[x]!;\n if (route.path?.startsWith('/')) {\n index = x;\n break;\n }\n }\n\n return routesWithPaths.slice(index).reduce((acc, { path }) => {\n const pathSegment = acc === '/' || acc === '' ? path : `/${path}`;\n return `${acc}${pathSegment}`;\n }, '');\n}\n"],"names":["browserTracingIntegration","WINDOW","startBrowserTracingPageLoadSpan","SEMANTIC_ATTRIBUTE_SENTRY_OP","SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN","SEMANTIC_ATTRIBUTE_SENTRY_SOURCE","URL_TEMPLATE","startBrowserTracingNavigationSpan"],"mappings":"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"}
|
|
@@ -2,6 +2,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
|
2
2
|
|
|
3
3
|
const browser = require('@sentry/browser');
|
|
4
4
|
const browser$1 = require('@sentry/core/browser');
|
|
5
|
+
const attributes = require('@sentry/conventions/attributes');
|
|
5
6
|
|
|
6
7
|
function tanstackRouterBrowserTracingIntegration(router, options = {}) {
|
|
7
8
|
const castRouterInstance = router;
|
|
@@ -15,68 +16,105 @@ function tanstackRouterBrowserTracingIntegration(router, options = {}) {
|
|
|
15
16
|
...browserTracingIntegrationInstance,
|
|
16
17
|
afterAllSetup(client) {
|
|
17
18
|
browserTracingIntegrationInstance.afterAllSetup(client);
|
|
19
|
+
const resolveRouteMatch = (pathname, search) => {
|
|
20
|
+
const matchedRoutes = castRouterInstance.matchRoutes(pathname, search, {
|
|
21
|
+
preload: false,
|
|
22
|
+
throwOnError: false
|
|
23
|
+
});
|
|
24
|
+
const lastMatch = matchedRoutes[matchedRoutes.length - 1];
|
|
25
|
+
return lastMatch?.routeId !== "__root__" ? lastMatch : void 0;
|
|
26
|
+
};
|
|
27
|
+
const applyRouteMatch = (span, match, toLocation, fallbackName) => {
|
|
28
|
+
span.updateName(match ? match.routeId : fallbackName);
|
|
29
|
+
span.setAttribute(browser$1.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, match ? "route" : "url");
|
|
30
|
+
span.setAttributes({
|
|
31
|
+
...match && { [attributes.URL_TEMPLATE]: match.routeId },
|
|
32
|
+
...locationToSpanUrlAttributes(castRouterInstance, toLocation),
|
|
33
|
+
...routeMatchToParamSpanAttributes(match)
|
|
34
|
+
});
|
|
35
|
+
};
|
|
18
36
|
const initialWindowLocation = browser.WINDOW.location;
|
|
19
37
|
if (instrumentPageLoad && initialWindowLocation) {
|
|
20
|
-
const
|
|
38
|
+
const routeMatch = resolveRouteMatch(
|
|
21
39
|
initialWindowLocation.pathname,
|
|
22
|
-
castRouterInstance.options.parseSearch(initialWindowLocation.search)
|
|
23
|
-
{ preload: false, throwOnError: false }
|
|
40
|
+
castRouterInstance.options.parseSearch(initialWindowLocation.search)
|
|
24
41
|
);
|
|
25
|
-
const
|
|
26
|
-
const routeMatch = lastMatch?.routeId !== "__root__" ? lastMatch : void 0;
|
|
27
|
-
browser.startBrowserTracingPageLoadSpan(client, {
|
|
42
|
+
const pageloadSpan = browser.startBrowserTracingPageLoadSpan(client, {
|
|
28
43
|
name: routeMatch ? routeMatch.routeId : initialWindowLocation.pathname,
|
|
29
44
|
attributes: {
|
|
30
45
|
[browser$1.SEMANTIC_ATTRIBUTE_SENTRY_OP]: "pageload",
|
|
31
46
|
[browser$1.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: "auto.pageload.react.tanstack_router",
|
|
32
47
|
[browser$1.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: routeMatch ? "route" : "url",
|
|
48
|
+
...routeMatch && { [attributes.URL_TEMPLATE]: routeMatch.routeId },
|
|
33
49
|
...routeMatchToParamSpanAttributes(routeMatch)
|
|
34
50
|
}
|
|
35
51
|
});
|
|
52
|
+
const unsubscribePageloadResolved = castRouterInstance.subscribe("onResolved", (onResolvedArgs) => {
|
|
53
|
+
unsubscribePageloadResolved();
|
|
54
|
+
if (!pageloadSpan) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
const { toLocation } = onResolvedArgs;
|
|
58
|
+
const resolvedMatch = resolveRouteMatch(toLocation.pathname, toLocation.search);
|
|
59
|
+
applyRouteMatch(pageloadSpan, resolvedMatch, toLocation, toLocation.pathname);
|
|
60
|
+
});
|
|
36
61
|
}
|
|
37
62
|
if (instrumentNavigation) {
|
|
38
|
-
|
|
39
|
-
|
|
63
|
+
let inFlightNavigationSpan;
|
|
64
|
+
castRouterInstance.subscribe("onBeforeLoad", (onBeforeLoadArgs) => {
|
|
65
|
+
const { toLocation, fromLocation } = onBeforeLoadArgs;
|
|
66
|
+
if (!fromLocation || toLocation.state === fromLocation.state) {
|
|
40
67
|
return;
|
|
41
68
|
}
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
const unsubscribeOnResolved = castRouterInstance.subscribe("onResolved", (onResolvedArgs) => {
|
|
59
|
-
unsubscribeOnResolved();
|
|
60
|
-
if (navigationSpan) {
|
|
61
|
-
const matchedRoutesOnResolved = castRouterInstance.matchRoutes(
|
|
62
|
-
onResolvedArgs.toLocation.pathname,
|
|
63
|
-
onResolvedArgs.toLocation.search,
|
|
64
|
-
{ preload: false, throwOnError: false }
|
|
65
|
-
);
|
|
66
|
-
const onResolvedLastMatch = matchedRoutesOnResolved[matchedRoutesOnResolved.length - 1];
|
|
67
|
-
const onResolvedRouteMatch = onResolvedLastMatch?.routeId !== "__root__" ? onResolvedLastMatch : void 0;
|
|
68
|
-
if (onResolvedRouteMatch) {
|
|
69
|
-
navigationSpan.updateName(onResolvedRouteMatch.routeId);
|
|
70
|
-
navigationSpan.setAttribute(browser$1.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, "route");
|
|
71
|
-
navigationSpan.setAttributes(routeMatchToParamSpanAttributes(onResolvedRouteMatch));
|
|
69
|
+
const routeMatch = resolveRouteMatch(toLocation.pathname, toLocation.search);
|
|
70
|
+
const fallbackName = browser.WINDOW.location?.pathname || toLocation.pathname;
|
|
71
|
+
if (inFlightNavigationSpan) {
|
|
72
|
+
applyRouteMatch(inFlightNavigationSpan, routeMatch, toLocation, fallbackName);
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
inFlightNavigationSpan = browser.startBrowserTracingNavigationSpan(
|
|
76
|
+
client,
|
|
77
|
+
{
|
|
78
|
+
name: routeMatch ? routeMatch.routeId : fallbackName,
|
|
79
|
+
attributes: {
|
|
80
|
+
[browser$1.SEMANTIC_ATTRIBUTE_SENTRY_OP]: "navigation",
|
|
81
|
+
[browser$1.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: "auto.navigation.react.tanstack_router",
|
|
82
|
+
[browser$1.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: routeMatch ? "route" : "url",
|
|
83
|
+
...routeMatch && { [attributes.URL_TEMPLATE]: routeMatch.routeId },
|
|
84
|
+
...routeMatchToParamSpanAttributes(routeMatch)
|
|
72
85
|
}
|
|
73
|
-
}
|
|
74
|
-
|
|
86
|
+
},
|
|
87
|
+
{ url: locationToAbsoluteUrl(castRouterInstance, toLocation) }
|
|
88
|
+
);
|
|
89
|
+
});
|
|
90
|
+
castRouterInstance.subscribe("onResolved", (onResolvedArgs) => {
|
|
91
|
+
const span = inFlightNavigationSpan;
|
|
92
|
+
inFlightNavigationSpan = void 0;
|
|
93
|
+
if (!span) {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
const { toLocation } = onResolvedArgs;
|
|
97
|
+
const resolvedMatch = resolveRouteMatch(toLocation.pathname, toLocation.search);
|
|
98
|
+
if (resolvedMatch) {
|
|
99
|
+
applyRouteMatch(span, resolvedMatch, toLocation, browser.WINDOW.location?.pathname || toLocation.pathname);
|
|
100
|
+
}
|
|
75
101
|
});
|
|
76
102
|
}
|
|
77
103
|
}
|
|
78
104
|
};
|
|
79
105
|
}
|
|
106
|
+
function locationToAbsoluteUrl(router, location) {
|
|
107
|
+
const search = router.options.stringifySearch?.(location.search) ?? "";
|
|
108
|
+
const pathWithSearch = `${location.pathname}${search && search !== "?" ? search : ""}`;
|
|
109
|
+
return browser.getAbsoluteUrl(pathWithSearch);
|
|
110
|
+
}
|
|
111
|
+
function locationToSpanUrlAttributes(router, location) {
|
|
112
|
+
const absoluteUrl = locationToAbsoluteUrl(router, location);
|
|
113
|
+
return {
|
|
114
|
+
[attributes.URL_PATH]: location.pathname,
|
|
115
|
+
[attributes.URL_FULL]: absoluteUrl
|
|
116
|
+
};
|
|
117
|
+
}
|
|
80
118
|
function routeMatchToParamSpanAttributes(match) {
|
|
81
119
|
if (!match) {
|
|
82
120
|
return {};
|
|
@@ -84,8 +122,8 @@ function routeMatchToParamSpanAttributes(match) {
|
|
|
84
122
|
const paramAttributes = {};
|
|
85
123
|
Object.entries(match.params).forEach(([key, value]) => {
|
|
86
124
|
paramAttributes[`url.path.params.${key}`] = value;
|
|
87
|
-
paramAttributes[
|
|
88
|
-
paramAttributes[
|
|
125
|
+
paramAttributes[attributes.URL_PATH_PARAMETER_KEY.replace("<key>", key)] = value;
|
|
126
|
+
paramAttributes[attributes.PARAMS_KEY.replace("<key>", key)] = value;
|
|
89
127
|
});
|
|
90
128
|
return paramAttributes;
|
|
91
129
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tanstackrouter.js","sources":["../../src/tanstackrouter.ts"],"sourcesContent":["import {\n browserTracingIntegration as originalBrowserTracingIntegration,\n startBrowserTracingNavigationSpan,\n startBrowserTracingPageLoadSpan,\n WINDOW,\n} from '@sentry/browser';\nimport type { Integration } from '@sentry/core/browser';\nimport {\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n SEMANTIC_ATTRIBUTE_SENTRY_SOURCE,\n} from '@sentry/core/browser';\nimport type { VendoredTanstackRouter, VendoredTanstackRouterRouteMatch } from './vendor/tanstackrouter-types';\n\n/**\n * A custom browser tracing integration for TanStack Router.\n *\n * The minimum compatible version of `@tanstack/react-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 // eslint-disable-next-line @typescript-eslint/no-explicit-any\n router: any, // This is `any` because we don't want any type mismatches if TanStack Router changes their types\n options: Parameters<typeof originalBrowserTracingIntegration>[0] = {},\n): Integration {\n const castRouterInstance: VendoredTanstackRouter = router;\n\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 initialWindowLocation = WINDOW.location;\n if (instrumentPageLoad && initialWindowLocation) {\n const matchedRoutes = castRouterInstance.matchRoutes(\n initialWindowLocation.pathname,\n castRouterInstance.options.parseSearch(initialWindowLocation.search),\n { preload: false, throwOnError: false },\n );\n\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 const routeMatch = lastMatch?.routeId !== '__root__' ? lastMatch : undefined;\n\n startBrowserTracingPageLoadSpan(client, {\n name: routeMatch ? routeMatch.routeId : initialWindowLocation.pathname,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'pageload',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.pageload.react.tanstack_router',\n [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: routeMatch ? 'route' : 'url',\n ...routeMatchToParamSpanAttributes(routeMatch),\n },\n });\n }\n\n if (instrumentNavigation) {\n // The onBeforeNavigate hook is called at the very beginning of a navigation and is only called once per navigation, even when the user is redirected\n castRouterInstance.subscribe('onBeforeNavigate', onBeforeNavigateArgs => {\n // onBeforeNavigate is called during pageloads. We can avoid creating navigation spans by:\n // 1. Checking if there's no fromLocation (initial pageload)\n // 2. Comparing the states of the to and from arguments\n if (\n !onBeforeNavigateArgs.fromLocation ||\n onBeforeNavigateArgs.toLocation.state === onBeforeNavigateArgs.fromLocation.state\n ) {\n return;\n }\n\n const matchedRoutesOnBeforeNavigate = castRouterInstance.matchRoutes(\n onBeforeNavigateArgs.toLocation.pathname,\n onBeforeNavigateArgs.toLocation.search,\n { preload: false, throwOnError: false },\n );\n\n const onBeforeNavigateLastMatch = matchedRoutesOnBeforeNavigate[matchedRoutesOnBeforeNavigate.length - 1];\n const onBeforeNavigateRouteMatch =\n onBeforeNavigateLastMatch?.routeId !== '__root__' ? onBeforeNavigateLastMatch : undefined;\n\n const navigationLocation = WINDOW.location;\n const navigationSpan = startBrowserTracingNavigationSpan(client, {\n name: onBeforeNavigateRouteMatch ? onBeforeNavigateRouteMatch.routeId : navigationLocation.pathname,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'navigation',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.navigation.react.tanstack_router',\n [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: onBeforeNavigateRouteMatch ? 'route' : 'url',\n },\n });\n\n // In case the user is redirected during navigation we want to update the span with the right value.\n const unsubscribeOnResolved = castRouterInstance.subscribe('onResolved', onResolvedArgs => {\n unsubscribeOnResolved();\n if (navigationSpan) {\n const matchedRoutesOnResolved = castRouterInstance.matchRoutes(\n onResolvedArgs.toLocation.pathname,\n onResolvedArgs.toLocation.search,\n { preload: false, throwOnError: false },\n );\n\n const onResolvedLastMatch = matchedRoutesOnResolved[matchedRoutesOnResolved.length - 1];\n const onResolvedRouteMatch =\n onResolvedLastMatch?.routeId !== '__root__' ? onResolvedLastMatch : undefined;\n\n if (onResolvedRouteMatch) {\n navigationSpan.updateName(onResolvedRouteMatch.routeId);\n navigationSpan.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, 'route');\n navigationSpan.setAttributes(routeMatchToParamSpanAttributes(onResolvedRouteMatch));\n }\n }\n });\n });\n }\n },\n };\n}\n\nfunction routeMatchToParamSpanAttributes(match: VendoredTanstackRouterRouteMatch | undefined): Record<string, string> {\n if (!match) {\n return {};\n }\n\n const paramAttributes: Record<string, string> = {};\n Object.entries(match.params).forEach(([key, value]) => {\n paramAttributes[`url.path.params.${key}`] = value; // TODO(v11): remove attribute which does not adhere to Sentry's semantic convention\n paramAttributes[`url.path.parameter.${key}`] = value;\n paramAttributes[`params.${key}`] = value; // params.[key] is an alias\n });\n\n return paramAttributes;\n}\n"],"names":["originalBrowserTracingIntegration","WINDOW","startBrowserTracingPageLoadSpan","SEMANTIC_ATTRIBUTE_SENTRY_OP","SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN","SEMANTIC_ATTRIBUTE_SENTRY_SOURCE","startBrowserTracingNavigationSpan"],"mappings":"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"}
|
|
1
|
+
{"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 type { Integration } from '@sentry/core/browser';\nimport {\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n SEMANTIC_ATTRIBUTE_SENTRY_SOURCE,\n} from '@sentry/core/browser';\nimport type { VendoredTanstackRouter, VendoredTanstackRouterRouteMatch } from './vendor/tanstackrouter-types';\nimport { PARAMS_KEY, URL_FULL, URL_PATH, URL_PATH_PARAMETER_KEY, URL_TEMPLATE } from '@sentry/conventions/attributes';\n\ninterface TanstackRouterLocation {\n pathname: string;\n search: Record<string, unknown>;\n state?: unknown;\n}\n\n/**\n * A custom browser tracing integration for TanStack Router.\n *\n * The minimum compatible version of `@tanstack/react-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 // eslint-disable-next-line @typescript-eslint/no-explicit-any\n router: any, // This is `any` because we don't want any type mismatches if TanStack Router changes their types\n options: Parameters<typeof originalBrowserTracingIntegration>[0] = {},\n): Integration {\n const castRouterInstance: VendoredTanstackRouter = router;\n\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): VendoredTanstackRouterRouteMatch | undefined => {\n const matchedRoutes = castRouterInstance.matchRoutes(pathname, search as {}, {\n preload: false,\n throwOnError: false,\n });\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<ReturnType<typeof startBrowserTracingPageLoadSpan>>,\n match: VendoredTanstackRouterRouteMatch | 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 ...(match && { [URL_TEMPLATE]: match.routeId }),\n ...locationToSpanUrlAttributes(castRouterInstance, toLocation),\n ...routeMatchToParamSpanAttributes(match),\n });\n };\n\n const initialWindowLocation = WINDOW.location;\n if (instrumentPageLoad && initialWindowLocation) {\n const routeMatch = resolveRouteMatch(\n initialWindowLocation.pathname,\n castRouterInstance.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.react.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 const unsubscribePageloadResolved = castRouterInstance.subscribe('onResolved', onResolvedArgs => {\n unsubscribePageloadResolved();\n if (!pageloadSpan) {\n return;\n }\n const { toLocation } = onResolvedArgs;\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<typeof startBrowserTracingNavigationSpan> | undefined;\n\n castRouterInstance.subscribe('onBeforeLoad', onBeforeLoadArgs => {\n const { toLocation, fromLocation } = onBeforeLoadArgs;\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 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.react.tanstack_router',\n [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: routeMatch ? 'route' : 'url',\n ...(routeMatch && { [URL_TEMPLATE]: routeMatch.routeId }),\n ...routeMatchToParamSpanAttributes(routeMatch),\n },\n },\n { url: locationToAbsoluteUrl(castRouterInstance, toLocation) },\n );\n });\n\n castRouterInstance.subscribe('onResolved', onResolvedArgs => {\n const span = inFlightNavigationSpan;\n inFlightNavigationSpan = undefined;\n if (!span) {\n return;\n }\n const { toLocation } = onResolvedArgs;\n const resolvedMatch = resolveRouteMatch(toLocation.pathname, toLocation.search);\n if (resolvedMatch) {\n applyRouteMatch(span, resolvedMatch, toLocation, WINDOW.location?.pathname || toLocation.pathname);\n }\n });\n }\n },\n };\n}\n\nfunction locationToAbsoluteUrl(router: VendoredTanstackRouter, 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: VendoredTanstackRouter,\n location: TanstackRouterLocation,\n): Record<string, string> {\n const absoluteUrl = locationToAbsoluteUrl(router, location);\n\n return {\n [URL_PATH]: location.pathname,\n [URL_FULL]: absoluteUrl,\n };\n}\n\nfunction routeMatchToParamSpanAttributes(match: VendoredTanstackRouterRouteMatch | undefined): Record<string, string> {\n if (!match) {\n return {};\n }\n\n const paramAttributes: Record<string, string> = {};\n Object.entries(match.params).forEach(([key, value]) => {\n paramAttributes[`url.path.params.${key}`] = value; // TODO(v11): remove attribute which does not adhere to Sentry's semantic convention\n paramAttributes[URL_PATH_PARAMETER_KEY.replace('<key>', key)] = value;\n paramAttributes[PARAMS_KEY.replace('<key>', 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","URL_PATH_PARAMETER_KEY","PARAMS_KEY"],"mappings":"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"}
|
package/build/esm/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"type":"module","version":"10.
|
|
1
|
+
{"type":"module","version":"10.65.0","sideEffects":false}
|
|
@@ -5,6 +5,7 @@ import { DEBUG_BUILD } from '../debug-build.js';
|
|
|
5
5
|
import { hoistNonReactStatics } from '../hoist-non-react-statics.js';
|
|
6
6
|
import { checkRouteForAsyncHandler } from './lazy-routes.js';
|
|
7
7
|
import { getActiveRootSpan, setNavigationContext, clearNavigationContext, resolveRouteNameAndSource, transactionNameHasWildcard, initializeRouterUtils } from './utils.js';
|
|
8
|
+
import { URL_TEMPLATE } from '@sentry/conventions/attributes';
|
|
8
9
|
|
|
9
10
|
let _useEffect;
|
|
10
11
|
let _useLocation;
|
|
@@ -165,6 +166,9 @@ function updateNavigationSpan(activeRootSpan, location, allRoutes2, forceUpdate
|
|
|
165
166
|
if (isImprovement) {
|
|
166
167
|
activeRootSpan.updateName(name);
|
|
167
168
|
activeRootSpan.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, source);
|
|
169
|
+
if (source === "route") {
|
|
170
|
+
activeRootSpan.setAttribute(URL_TEMPLATE, name);
|
|
171
|
+
}
|
|
168
172
|
if (!transactionNameHasWildcard(name) && source === "route") {
|
|
169
173
|
addNonEnumerableProperty(
|
|
170
174
|
activeRootSpan,
|
|
@@ -549,6 +553,9 @@ function handleNavigation(opts) {
|
|
|
549
553
|
} else {
|
|
550
554
|
trackedNav.span.updateName(name);
|
|
551
555
|
trackedNav.span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, source);
|
|
556
|
+
if (source === "route") {
|
|
557
|
+
trackedNav.span.setAttribute(URL_TEMPLATE, name);
|
|
558
|
+
}
|
|
552
559
|
addNonEnumerableProperty(
|
|
553
560
|
trackedNav.span,
|
|
554
561
|
"__sentry_navigation_name_set__",
|
|
@@ -580,7 +587,8 @@ function handleNavigation(opts) {
|
|
|
580
587
|
attributes: {
|
|
581
588
|
[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: source,
|
|
582
589
|
[SEMANTIC_ATTRIBUTE_SENTRY_OP]: "navigation",
|
|
583
|
-
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: `auto.navigation.react.reactrouter${version ? `_v${version}` : ""}
|
|
590
|
+
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: `auto.navigation.react.reactrouter${version ? `_v${version}` : ""}`,
|
|
591
|
+
...source === "route" && { [URL_TEMPLATE]: placeholderEntry.routeName }
|
|
584
592
|
}
|
|
585
593
|
});
|
|
586
594
|
} catch (e) {
|
|
@@ -646,6 +654,9 @@ function updatePageloadTransaction({
|
|
|
646
654
|
if (activeRootSpan) {
|
|
647
655
|
activeRootSpan.updateName(name);
|
|
648
656
|
activeRootSpan.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, source);
|
|
657
|
+
if (source === "route") {
|
|
658
|
+
activeRootSpan.setAttribute(URL_TEMPLATE, name);
|
|
659
|
+
}
|
|
649
660
|
patchSpanEnd(activeRootSpan, location, routes, basename, "pageload");
|
|
650
661
|
}
|
|
651
662
|
} else if (activeRootSpan) {
|
|
@@ -694,6 +705,9 @@ function tryUpdateSpanNameBeforeEnd(span, spanJson, currentName, location, route
|
|
|
694
705
|
if (isImprovement && spanNotEnded) {
|
|
695
706
|
span.updateName(name);
|
|
696
707
|
span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, source);
|
|
708
|
+
if (source === "route") {
|
|
709
|
+
span.setAttribute(URL_TEMPLATE, name);
|
|
710
|
+
}
|
|
697
711
|
}
|
|
698
712
|
} catch (error) {
|
|
699
713
|
DEBUG_BUILD && debug.warn(`Error updating span details before ending: ${error}`);
|