@sentry/react-router 10.69.0 → 11.0.0-alpha.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/client/createClientInstrumentation.js +18 -12
- package/build/cjs/client/createClientInstrumentation.js.map +1 -1
- package/build/cjs/client/hydratedRouter.js +4 -1
- package/build/cjs/client/hydratedRouter.js.map +1 -1
- package/build/cjs/client/tracingIntegration.js +1 -0
- package/build/cjs/client/tracingIntegration.js.map +1 -1
- package/build/cjs/client/utils.js +6 -2
- package/build/cjs/client/utils.js.map +1 -1
- package/build/cjs/index.server.js +0 -4
- package/build/cjs/index.server.js.map +1 -1
- package/build/cjs/server/createSentryHandleRequest.js.map +1 -1
- package/build/cjs/server/createServerInstrumentation.js +71 -65
- package/build/cjs/server/createServerInstrumentation.js.map +1 -1
- package/build/cjs/server/integration/reactRouterServer.js +1 -40
- package/build/cjs/server/integration/reactRouterServer.js.map +1 -1
- package/build/cjs/server/serverBuild.js +0 -4
- package/build/cjs/server/serverBuild.js.map +1 -1
- package/build/cjs/server/serverGlobals.js +0 -9
- package/build/cjs/server/serverGlobals.js.map +1 -1
- package/build/cjs/vite/buildEnd/handleOnBuildEnd.js +26 -14
- package/build/cjs/vite/buildEnd/handleOnBuildEnd.js.map +1 -1
- package/build/cjs/vite/makeCustomSentryVitePlugins.js +29 -10
- package/build/cjs/vite/makeCustomSentryVitePlugins.js.map +1 -1
- package/build/cjs/vite/makeServerBuildCapturePlugin.js +2 -6
- package/build/cjs/vite/makeServerBuildCapturePlugin.js.map +1 -1
- package/build/cjs/vite/plugin.js +2 -0
- package/build/cjs/vite/plugin.js.map +1 -1
- package/build/esm/client/createClientInstrumentation.js +20 -14
- package/build/esm/client/createClientInstrumentation.js.map +1 -1
- package/build/esm/client/hydratedRouter.js +4 -1
- package/build/esm/client/hydratedRouter.js.map +1 -1
- package/build/esm/client/tracingIntegration.js +1 -0
- package/build/esm/client/tracingIntegration.js.map +1 -1
- package/build/esm/client/utils.js +7 -3
- package/build/esm/client/utils.js.map +1 -1
- package/build/esm/index.server.js +0 -2
- package/build/esm/index.server.js.map +1 -1
- package/build/esm/package.json +1 -1
- package/build/esm/server/createSentryHandleRequest.js.map +1 -1
- package/build/esm/server/createServerInstrumentation.js +73 -67
- package/build/esm/server/createServerInstrumentation.js.map +1 -1
- package/build/esm/server/integration/reactRouterServer.js +3 -41
- package/build/esm/server/integration/reactRouterServer.js.map +1 -1
- package/build/esm/server/serverBuild.js +1 -4
- package/build/esm/server/serverBuild.js.map +1 -1
- package/build/esm/server/serverGlobals.js +1 -8
- package/build/esm/server/serverGlobals.js.map +1 -1
- package/build/esm/vite/buildEnd/handleOnBuildEnd.js +26 -14
- package/build/esm/vite/buildEnd/handleOnBuildEnd.js.map +1 -1
- package/build/esm/vite/makeCustomSentryVitePlugins.js +28 -9
- package/build/esm/vite/makeCustomSentryVitePlugins.js.map +1 -1
- package/build/esm/vite/makeServerBuildCapturePlugin.js +2 -6
- package/build/esm/vite/makeServerBuildCapturePlugin.js.map +1 -1
- package/build/esm/vite/plugin.js +2 -0
- package/build/esm/vite/plugin.js.map +1 -1
- package/build/types/client/createClientInstrumentation.d.ts.map +1 -1
- package/build/types/client/hydratedRouter.d.ts.map +1 -1
- package/build/types/client/tracingIntegration.d.ts.map +1 -1
- package/build/types/client/utils.d.ts.map +1 -1
- package/build/types/index.types.d.ts +1 -0
- package/build/types/index.types.d.ts.map +1 -1
- package/build/types/server/createSentryHandleRequest.d.ts.map +1 -1
- package/build/types/server/createServerInstrumentation.d.ts.map +1 -1
- package/build/types/server/index.d.ts +0 -2
- package/build/types/server/index.d.ts.map +1 -1
- package/build/types/server/integration/reactRouterServer.d.ts +0 -3
- package/build/types/server/integration/reactRouterServer.d.ts.map +1 -1
- package/build/types/server/serverGlobals.d.ts +0 -10
- package/build/types/server/serverGlobals.d.ts.map +1 -1
- package/build/types/vite/buildEnd/handleOnBuildEnd.d.ts.map +1 -1
- package/build/types/vite/makeCustomSentryVitePlugins.d.ts.map +1 -1
- package/build/types/vite/makeServerBuildCapturePlugin.d.ts.map +1 -1
- package/build/types/vite/plugin.d.ts.map +1 -1
- package/build/types/vite/types.d.ts +1 -1
- package/build/types/vite/types.d.ts.map +1 -1
- package/package.json +14 -14
- package/build/cjs/server/instrumentation/reactRouter.js +0 -106
- package/build/cjs/server/instrumentation/reactRouter.js.map +0 -1
- package/build/cjs/server/instrumentation/util.js +0 -24
- package/build/cjs/server/instrumentation/util.js.map +0 -1
- package/build/cjs/server/wrapServerAction.js +0 -56
- package/build/cjs/server/wrapServerAction.js.map +0 -1
- package/build/cjs/server/wrapServerLoader.js +0 -56
- package/build/cjs/server/wrapServerLoader.js.map +0 -1
- package/build/esm/server/instrumentation/reactRouter.js +0 -104
- package/build/esm/server/instrumentation/reactRouter.js.map +0 -1
- package/build/esm/server/instrumentation/util.js +0 -18
- package/build/esm/server/instrumentation/util.js.map +0 -1
- package/build/esm/server/wrapServerAction.js +0 -54
- package/build/esm/server/wrapServerAction.js.map +0 -1
- package/build/esm/server/wrapServerLoader.js +0 -54
- package/build/esm/server/wrapServerLoader.js.map +0 -1
- package/build/types/server/instrumentation/reactRouter.d.ts +0 -19
- package/build/types/server/instrumentation/reactRouter.d.ts.map +0 -1
- package/build/types/server/instrumentation/util.d.ts +0 -31
- package/build/types/server/instrumentation/util.d.ts.map +0 -1
- package/build/types/server/wrapServerAction.d.ts +0 -33
- package/build/types/server/wrapServerAction.d.ts.map +0 -1
- package/build/types/server/wrapServerLoader.d.ts +0 -33
- package/build/types/server/wrapServerLoader.d.ts.map +0 -1
|
@@ -6,6 +6,7 @@ const debugBuild = require('../common/debug-build.js');
|
|
|
6
6
|
const utils = require('../common/utils.js');
|
|
7
7
|
const utils$1 = require('./utils.js');
|
|
8
8
|
const attributes = require('@sentry/conventions/attributes');
|
|
9
|
+
const op = require('@sentry/conventions/op');
|
|
9
10
|
|
|
10
11
|
const WINDOW = core.GLOBAL_OBJ;
|
|
11
12
|
let currentNumericNavigationSpan;
|
|
@@ -59,7 +60,7 @@ function createSentryClientInstrumentation(options = {}) {
|
|
|
59
60
|
const result2 = await callNavigate();
|
|
60
61
|
if (result2.status === "error" && result2.error instanceof Error) {
|
|
61
62
|
utils.captureInstrumentationError(result2, captureErrors, "react_router.navigate", {
|
|
62
|
-
|
|
63
|
+
[attributes.URL_FULL]: core.filterCollectedUrl(info.currentUrl)
|
|
63
64
|
});
|
|
64
65
|
}
|
|
65
66
|
return;
|
|
@@ -96,7 +97,7 @@ function createSentryClientInstrumentation(options = {}) {
|
|
|
96
97
|
navigationSpan2.setStatus({ code: core.SPAN_STATUS_ERROR, message: "internal_error" });
|
|
97
98
|
}
|
|
98
99
|
utils.captureInstrumentationError(result2, captureErrors, "react_router.navigate", {
|
|
99
|
-
|
|
100
|
+
[attributes.URL_FULL]: WINDOW.location?.pathname || core.filterCollectedUrl(info.currentUrl)
|
|
100
101
|
});
|
|
101
102
|
}
|
|
102
103
|
} finally {
|
|
@@ -128,7 +129,7 @@ function createSentryClientInstrumentation(options = {}) {
|
|
|
128
129
|
navigationSpan.setStatus({ code: core.SPAN_STATUS_ERROR, message: "internal_error" });
|
|
129
130
|
}
|
|
130
131
|
utils.captureInstrumentationError(result, captureErrors, "react_router.navigate", {
|
|
131
|
-
|
|
132
|
+
[attributes.URL_FULL]: core.filterCollectedUrl(toPath)
|
|
132
133
|
});
|
|
133
134
|
}
|
|
134
135
|
return;
|
|
@@ -138,7 +139,8 @@ function createSentryClientInstrumentation(options = {}) {
|
|
|
138
139
|
{
|
|
139
140
|
name: `Fetcher ${info.fetcherKey}`,
|
|
140
141
|
attributes: {
|
|
141
|
-
[
|
|
142
|
+
[attributes.SENTRY_OP]: op.GENERAL_FUNCTION_SPAN_OP,
|
|
143
|
+
[attributes.CODE_FUNCTION_NAME]: "fetcher",
|
|
142
144
|
[core.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: "auto.function.react_router.instrumentation_api"
|
|
143
145
|
}
|
|
144
146
|
},
|
|
@@ -147,7 +149,7 @@ function createSentryClientInstrumentation(options = {}) {
|
|
|
147
149
|
if (result.status === "error" && result.error instanceof Error) {
|
|
148
150
|
span.setStatus({ code: core.SPAN_STATUS_ERROR, message: "internal_error" });
|
|
149
151
|
utils.captureInstrumentationError(result, captureErrors, "react_router.fetcher", {
|
|
150
|
-
|
|
152
|
+
[attributes.URL_FULL]: core.filterCollectedUrl(info.href)
|
|
151
153
|
});
|
|
152
154
|
}
|
|
153
155
|
}
|
|
@@ -167,7 +169,8 @@ function createSentryClientInstrumentation(options = {}) {
|
|
|
167
169
|
{
|
|
168
170
|
name: routePattern,
|
|
169
171
|
attributes: {
|
|
170
|
-
[
|
|
172
|
+
[attributes.SENTRY_OP]: op.GENERAL_FUNCTION_SPAN_OP,
|
|
173
|
+
[attributes.CODE_FUNCTION_NAME]: "clientLoader",
|
|
171
174
|
[core.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: "auto.function.react_router.instrumentation_api"
|
|
172
175
|
}
|
|
173
176
|
},
|
|
@@ -176,7 +179,7 @@ function createSentryClientInstrumentation(options = {}) {
|
|
|
176
179
|
if (result.status === "error" && result.error instanceof Error) {
|
|
177
180
|
span.setStatus({ code: core.SPAN_STATUS_ERROR, message: "internal_error" });
|
|
178
181
|
utils.captureInstrumentationError(result, captureErrors, "react_router.client_loader", {
|
|
179
|
-
|
|
182
|
+
[attributes.URL_FULL]: urlPath
|
|
180
183
|
});
|
|
181
184
|
}
|
|
182
185
|
}
|
|
@@ -191,7 +194,8 @@ function createSentryClientInstrumentation(options = {}) {
|
|
|
191
194
|
{
|
|
192
195
|
name: routePattern,
|
|
193
196
|
attributes: {
|
|
194
|
-
[
|
|
197
|
+
[attributes.SENTRY_OP]: op.GENERAL_FUNCTION_SPAN_OP,
|
|
198
|
+
[attributes.CODE_FUNCTION_NAME]: "clientAction",
|
|
195
199
|
[core.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: "auto.function.react_router.instrumentation_api"
|
|
196
200
|
}
|
|
197
201
|
},
|
|
@@ -200,7 +204,7 @@ function createSentryClientInstrumentation(options = {}) {
|
|
|
200
204
|
if (result.status === "error" && result.error instanceof Error) {
|
|
201
205
|
span.setStatus({ code: core.SPAN_STATUS_ERROR, message: "internal_error" });
|
|
202
206
|
utils.captureInstrumentationError(result, captureErrors, "react_router.client_action", {
|
|
203
|
-
|
|
207
|
+
[attributes.URL_FULL]: urlPath
|
|
204
208
|
});
|
|
205
209
|
}
|
|
206
210
|
}
|
|
@@ -220,7 +224,8 @@ function createSentryClientInstrumentation(options = {}) {
|
|
|
220
224
|
{
|
|
221
225
|
name: `middleware ${routeId}`,
|
|
222
226
|
attributes: {
|
|
223
|
-
[
|
|
227
|
+
[attributes.SENTRY_OP]: op.WEB_SERVER_MIDDLEWARE_SPAN_OP,
|
|
228
|
+
[attributes.CODE_FUNCTION_NAME]: "clientMiddleware",
|
|
224
229
|
[core.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: "auto.function.react_router.instrumentation_api",
|
|
225
230
|
"react_router.route.id": routeId,
|
|
226
231
|
"http.route": routePattern,
|
|
@@ -232,7 +237,7 @@ function createSentryClientInstrumentation(options = {}) {
|
|
|
232
237
|
if (result.status === "error" && result.error instanceof Error) {
|
|
233
238
|
span.setStatus({ code: core.SPAN_STATUS_ERROR, message: "internal_error" });
|
|
234
239
|
utils.captureInstrumentationError(result, captureErrors, "react_router.client_middleware", {
|
|
235
|
-
|
|
240
|
+
[attributes.URL_FULL]: urlPath
|
|
236
241
|
});
|
|
237
242
|
}
|
|
238
243
|
}
|
|
@@ -243,7 +248,8 @@ function createSentryClientInstrumentation(options = {}) {
|
|
|
243
248
|
{
|
|
244
249
|
name: "Lazy Route Load",
|
|
245
250
|
attributes: {
|
|
246
|
-
[
|
|
251
|
+
[attributes.SENTRY_OP]: op.GENERAL_FUNCTION_SPAN_OP,
|
|
252
|
+
[attributes.CODE_FUNCTION_NAME]: "lazy",
|
|
247
253
|
[core.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: "auto.function.react_router.instrumentation_api"
|
|
248
254
|
}
|
|
249
255
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createClientInstrumentation.js","sources":["../../../src/client/createClientInstrumentation.ts"],"sourcesContent":["// oxlint-disable max-lines\nimport { getAbsoluteUrl, startBrowserTracingNavigationSpan } from '@sentry/browser';\nimport type { Span } from '@sentry/core';\nimport {\n debug,\n getActiveSpan,\n getClient,\n getRootSpan,\n GLOBAL_OBJ,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n SEMANTIC_ATTRIBUTE_SENTRY_SOURCE,\n spanToJSON,\n SPAN_STATUS_ERROR,\n startSpan,\n updateSpanName,\n} from '@sentry/core';\nimport { DEBUG_BUILD } from '../common/debug-build';\nimport type { ClientInstrumentation, InstrumentableRoute, InstrumentableRouter } from '../common/types';\nimport { captureInstrumentationError, getPathFromRequest, getPattern, normalizeRoutePath } from '../common/utils';\nimport {\n resolveNavigateAbsoluteUrl,\n resolveNavigateArg,\n finalizeNavigationSpanFromHydratedRouter,\n updateNavigationSpanUrlFromLocation,\n} from './utils';\nimport { URL_TEMPLATE } from '@sentry/conventions/attributes';\n\nconst WINDOW = GLOBAL_OBJ as typeof GLOBAL_OBJ & Window;\n\n// Tracks active numeric navigation span to prevent duplicate spans when popstate fires\nlet currentNumericNavigationSpan: Span | undefined;\n\n// Per-request middleware counters, keyed by Request\nconst middlewareCountersMap = new WeakMap<object, Record<string, number>>();\n\nconst SENTRY_CLIENT_INSTRUMENTATION_FLAG = '__sentryReactRouterClientInstrumentationUsed';\n// Intentionally never reset - once set, instrumentation API handles all navigations for the session.\nconst SENTRY_NAVIGATE_HOOK_INVOKED_FLAG = '__sentryReactRouterNavigateHookInvoked';\nconst SENTRY_POPSTATE_LISTENER_ADDED_FLAG = '__sentryReactRouterPopstateListenerAdded';\n\ntype GlobalObjWithFlags = typeof GLOBAL_OBJ & {\n [SENTRY_CLIENT_INSTRUMENTATION_FLAG]?: boolean;\n [SENTRY_NAVIGATE_HOOK_INVOKED_FLAG]?: boolean;\n [SENTRY_POPSTATE_LISTENER_ADDED_FLAG]?: boolean;\n};\n\nconst GLOBAL_WITH_FLAGS = GLOBAL_OBJ as GlobalObjWithFlags;\n\n/**\n * Options for creating Sentry client instrumentation.\n */\nexport interface CreateSentryClientInstrumentationOptions {\n /**\n * Whether to capture errors from loaders/actions automatically.\n * Set to `false` to avoid duplicates if using custom error handlers.\n * @default true\n */\n captureErrors?: boolean;\n}\n\n/**\n * Creates a Sentry client instrumentation for React Router's instrumentation API.\n */\nexport function createSentryClientInstrumentation(\n options: CreateSentryClientInstrumentationOptions = {},\n): ClientInstrumentation {\n const { captureErrors = true } = options;\n\n DEBUG_BUILD && debug.log('React Router client instrumentation API created.');\n\n return {\n router(router: InstrumentableRouter) {\n // Set the flag when React Router actually invokes our instrumentation.\n // This ensures the flag is only set in Library Mode (where hooks run),\n // not in Framework Mode (where hooks are never called).\n // See: https://github.com/remix-run/react-router/discussions/13749\n GLOBAL_WITH_FLAGS[SENTRY_CLIENT_INSTRUMENTATION_FLAG] = true;\n DEBUG_BUILD && debug.log('React Router client instrumentation API router hook registered.');\n\n // Add popstate listener for browser back/forward navigation (persists for session, one listener only)\n if (!GLOBAL_WITH_FLAGS[SENTRY_POPSTATE_LISTENER_ADDED_FLAG] && WINDOW.addEventListener) {\n GLOBAL_WITH_FLAGS[SENTRY_POPSTATE_LISTENER_ADDED_FLAG] = true;\n\n WINDOW.addEventListener('popstate', () => {\n const client = getClient();\n if (!client) {\n currentNumericNavigationSpan = undefined;\n return;\n }\n\n const pathname = WINDOW.location?.pathname || '/';\n\n // If there's an active numeric navigation span, update it instead of creating a duplicate\n if (currentNumericNavigationSpan) {\n if (currentNumericNavigationSpan.isRecording()) {\n updateNavigationSpanUrlFromLocation(currentNumericNavigationSpan);\n }\n currentNumericNavigationSpan = undefined;\n return;\n }\n\n // Only create a new span for actual browser back/forward button clicks\n startBrowserTracingNavigationSpan(\n client,\n {\n name: pathname,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'url',\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'navigation',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.navigation.react_router.instrumentation_api',\n 'navigation.type': 'browser.popstate',\n },\n },\n { url: getAbsoluteUrl(pathname) },\n );\n });\n\n DEBUG_BUILD && debug.log('React Router popstate listener registered for browser back/forward navigation.');\n }\n\n router.instrument({\n async navigate(callNavigate, info) {\n // navigate(0) triggers a page reload - skip span creation, but still capture errors\n // (navigation can be rejected before reload, e.g., by a navigation guard)\n if (info.to === 0) {\n const result = await callNavigate();\n if (result.status === 'error' && result.error instanceof Error) {\n captureInstrumentationError(result, captureErrors, 'react_router.navigate', {\n 'http.url': info.currentUrl,\n });\n }\n return;\n }\n\n GLOBAL_WITH_FLAGS[SENTRY_NAVIGATE_HOOK_INVOKED_FLAG] = true;\n\n // Handle numeric navigations (navigate(-1), navigate(1), etc.)\n if (typeof info.to === 'number') {\n const client = getClient();\n let navigationSpan;\n\n if (client) {\n const navigationType = info.to < 0 ? 'router.back' : 'router.forward';\n const currentPathname = WINDOW.location?.pathname || info.currentUrl;\n\n navigationSpan = startBrowserTracingNavigationSpan(\n client,\n {\n name: currentPathname,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'url',\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'navigation',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.navigation.react_router.instrumentation_api',\n 'navigation.type': navigationType,\n },\n },\n { url: getAbsoluteUrl(currentPathname) },\n );\n\n // Store ref so popstate listener can update it instead of creating a duplicate\n currentNumericNavigationSpan = navigationSpan;\n }\n\n try {\n const result = await callNavigate();\n\n if (navigationSpan && WINDOW.location) {\n finalizeNavigationSpanFromHydratedRouter(navigationSpan);\n }\n\n if (result.status === 'error' && result.error instanceof Error) {\n if (navigationSpan) {\n navigationSpan.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n }\n captureInstrumentationError(result, captureErrors, 'react_router.navigate', {\n 'http.url': WINDOW.location?.pathname || info.currentUrl,\n });\n }\n } finally {\n currentNumericNavigationSpan = undefined;\n }\n return;\n }\n\n // Handle string/object navigations (e.g., navigate('/about') or navigate({ pathname: '/about' }))\n const client = getClient();\n const toPath = resolveNavigateArg(info.to);\n let navigationSpan;\n\n if (client) {\n navigationSpan = startBrowserTracingNavigationSpan(\n client,\n {\n name: toPath,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'url',\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'navigation',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.navigation.react_router.instrumentation_api',\n 'navigation.type': 'router.navigate',\n },\n },\n { url: resolveNavigateAbsoluteUrl(info.to, info.currentUrl) },\n );\n }\n\n const result = await callNavigate();\n if (result.status === 'error' && result.error instanceof Error) {\n if (navigationSpan) {\n navigationSpan.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n }\n captureInstrumentationError(result, captureErrors, 'react_router.navigate', {\n 'http.url': toPath,\n });\n }\n return;\n },\n\n async fetch(callFetch, info) {\n await startSpan(\n {\n name: `Fetcher ${info.fetcherKey}`,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'function.react_router.fetcher',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.react_router.instrumentation_api',\n },\n },\n async span => {\n const result = await callFetch();\n if (result.status === 'error' && result.error instanceof Error) {\n span.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n captureInstrumentationError(result, captureErrors, 'react_router.fetcher', {\n 'http.url': info.href,\n });\n }\n },\n );\n },\n });\n },\n\n route(route: InstrumentableRoute) {\n const routeId = route.id;\n\n route.instrument({\n async loader(callLoader, info) {\n const urlPath = getPathFromRequest(info.request);\n const pattern = normalizeRoutePath(getPattern(info));\n const routePattern = pattern || urlPath;\n // Parameterize the active navigation root span. (Route hooks don't fire on initial\n // pageload, so this only affects navigations.)\n updateRootSpanRoute(routePattern, !!pattern);\n\n await startSpan(\n {\n name: routePattern,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'function.react_router.client_loader',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.react_router.instrumentation_api',\n },\n },\n async span => {\n const result = await callLoader();\n if (result.status === 'error' && result.error instanceof Error) {\n span.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n captureInstrumentationError(result, captureErrors, 'react_router.client_loader', {\n 'http.url': urlPath,\n });\n }\n },\n );\n },\n\n async action(callAction, info) {\n const urlPath = getPathFromRequest(info.request);\n const pattern = normalizeRoutePath(getPattern(info));\n const routePattern = pattern || urlPath;\n updateRootSpanRoute(routePattern, !!pattern);\n\n await startSpan(\n {\n name: routePattern,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'function.react_router.client_action',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.react_router.instrumentation_api',\n },\n },\n async span => {\n const result = await callAction();\n if (result.status === 'error' && result.error instanceof Error) {\n span.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n captureInstrumentationError(result, captureErrors, 'react_router.client_action', {\n 'http.url': urlPath,\n });\n }\n },\n );\n },\n\n async middleware(callMiddleware, info) {\n const urlPath = getPathFromRequest(info.request);\n const routePattern = normalizeRoutePath(getPattern(info)) || urlPath;\n\n let counters = middlewareCountersMap.get(info.request);\n if (!counters) {\n counters = {};\n middlewareCountersMap.set(info.request, counters);\n }\n\n const middlewareIndex = counters[routeId] ?? 0;\n counters[routeId] = middlewareIndex + 1;\n\n await startSpan(\n {\n name: `middleware ${routeId}`,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'function.react_router.client_middleware',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.react_router.instrumentation_api',\n 'react_router.route.id': routeId,\n 'http.route': routePattern,\n 'react_router.middleware.index': middlewareIndex,\n },\n },\n async span => {\n const result = await callMiddleware();\n if (result.status === 'error' && result.error instanceof Error) {\n span.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n captureInstrumentationError(result, captureErrors, 'react_router.client_middleware', {\n 'http.url': urlPath,\n });\n }\n },\n );\n },\n\n async lazy(callLazy) {\n await startSpan(\n {\n name: 'Lazy Route Load',\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'function.react_router.client_lazy',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.react_router.instrumentation_api',\n },\n },\n async span => {\n const result = await callLazy();\n if (result.status === 'error' && result.error instanceof Error) {\n span.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n captureInstrumentationError(result, captureErrors, 'react_router.client_lazy', {});\n }\n },\n );\n },\n });\n },\n };\n}\n\n/**\n * Updates the active navigation/pageload root span name with the parameterized route, so the\n * transaction reflects the parameterized route pattern (e.g. `/users/:id`).\n */\nfunction updateRootSpanRoute(routeName: string, hasPattern: boolean): void {\n if (!hasPattern) {\n return;\n }\n\n const activeSpan = getActiveSpan();\n const rootSpan = activeSpan && getRootSpan(activeSpan);\n if (!rootSpan) {\n return;\n }\n\n const { op } = spanToJSON(rootSpan);\n if (op !== 'navigation' && op !== 'pageload') {\n return;\n }\n\n updateSpanName(rootSpan, routeName);\n rootSpan.setAttributes({ [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'route', [URL_TEMPLATE]: routeName });\n}\n\n/**\n * Check if React Router's instrumentation API is being used on the client.\n */\nexport function isClientInstrumentationApiUsed(): boolean {\n return !!GLOBAL_WITH_FLAGS[SENTRY_CLIENT_INSTRUMENTATION_FLAG];\n}\n\n/**\n * Check if React Router's instrumentation API's navigate hook was invoked.\n */\nexport function isNavigateHookInvoked(): boolean {\n return !!GLOBAL_WITH_FLAGS[SENTRY_NAVIGATE_HOOK_INVOKED_FLAG];\n}\n"],"names":["GLOBAL_OBJ","DEBUG_BUILD","debug","getClient","updateNavigationSpanUrlFromLocation","startBrowserTracingNavigationSpan","SEMANTIC_ATTRIBUTE_SENTRY_SOURCE","SEMANTIC_ATTRIBUTE_SENTRY_OP","SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN","getAbsoluteUrl","result","captureInstrumentationError","client","navigationSpan","finalizeNavigationSpanFromHydratedRouter","SPAN_STATUS_ERROR","resolveNavigateArg","resolveNavigateAbsoluteUrl","startSpan","getPathFromRequest","normalizeRoutePath","getPattern","getActiveSpan","getRootSpan","spanToJSON","updateSpanName","URL_TEMPLATE"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"createClientInstrumentation.js","sources":["../../../src/client/createClientInstrumentation.ts"],"sourcesContent":["// oxlint-disable max-lines\nimport { getAbsoluteUrl, startBrowserTracingNavigationSpan } from '@sentry/browser';\nimport type { Span } from '@sentry/core';\nimport {\n debug,\n getActiveSpan,\n getClient,\n getRootSpan,\n GLOBAL_OBJ,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n SEMANTIC_ATTRIBUTE_SENTRY_SOURCE,\n spanToJSON,\n SPAN_STATUS_ERROR,\n startSpan,\n updateSpanName,\n filterCollectedUrl,\n} from '@sentry/core';\nimport { DEBUG_BUILD } from '../common/debug-build';\nimport type { ClientInstrumentation, InstrumentableRoute, InstrumentableRouter } from '../common/types';\nimport { captureInstrumentationError, getPathFromRequest, getPattern, normalizeRoutePath } from '../common/utils';\nimport {\n resolveNavigateAbsoluteUrl,\n resolveNavigateArg,\n finalizeNavigationSpanFromHydratedRouter,\n updateNavigationSpanUrlFromLocation,\n} from './utils';\nimport { CODE_FUNCTION_NAME, SENTRY_OP, URL_FULL, URL_TEMPLATE } from '@sentry/conventions/attributes';\nimport { GENERAL_FUNCTION_SPAN_OP, WEB_SERVER_MIDDLEWARE_SPAN_OP } from '@sentry/conventions/op';\n\nconst WINDOW = GLOBAL_OBJ as typeof GLOBAL_OBJ & Window;\n\n// Tracks active numeric navigation span to prevent duplicate spans when popstate fires\nlet currentNumericNavigationSpan: Span | undefined;\n\n// Per-request middleware counters, keyed by Request\nconst middlewareCountersMap = new WeakMap<object, Record<string, number>>();\n\nconst SENTRY_CLIENT_INSTRUMENTATION_FLAG = '__sentryReactRouterClientInstrumentationUsed';\n// Intentionally never reset - once set, instrumentation API handles all navigations for the session.\nconst SENTRY_NAVIGATE_HOOK_INVOKED_FLAG = '__sentryReactRouterNavigateHookInvoked';\nconst SENTRY_POPSTATE_LISTENER_ADDED_FLAG = '__sentryReactRouterPopstateListenerAdded';\n\ntype GlobalObjWithFlags = typeof GLOBAL_OBJ & {\n [SENTRY_CLIENT_INSTRUMENTATION_FLAG]?: boolean;\n [SENTRY_NAVIGATE_HOOK_INVOKED_FLAG]?: boolean;\n [SENTRY_POPSTATE_LISTENER_ADDED_FLAG]?: boolean;\n};\n\nconst GLOBAL_WITH_FLAGS = GLOBAL_OBJ as GlobalObjWithFlags;\n\n/**\n * Options for creating Sentry client instrumentation.\n */\nexport interface CreateSentryClientInstrumentationOptions {\n /**\n * Whether to capture errors from loaders/actions automatically.\n * Set to `false` to avoid duplicates if using custom error handlers.\n * @default true\n */\n captureErrors?: boolean;\n}\n\n/**\n * Creates a Sentry client instrumentation for React Router's instrumentation API.\n */\nexport function createSentryClientInstrumentation(\n options: CreateSentryClientInstrumentationOptions = {},\n): ClientInstrumentation {\n const { captureErrors = true } = options;\n\n DEBUG_BUILD && debug.log('React Router client instrumentation API created.');\n\n return {\n router(router: InstrumentableRouter) {\n // Set the flag when React Router actually invokes our instrumentation.\n // This ensures the flag is only set in Library Mode (where hooks run),\n // not in Framework Mode (where hooks are never called).\n // See: https://github.com/remix-run/react-router/discussions/13749\n GLOBAL_WITH_FLAGS[SENTRY_CLIENT_INSTRUMENTATION_FLAG] = true;\n DEBUG_BUILD && debug.log('React Router client instrumentation API router hook registered.');\n\n // Add popstate listener for browser back/forward navigation (persists for session, one listener only)\n if (!GLOBAL_WITH_FLAGS[SENTRY_POPSTATE_LISTENER_ADDED_FLAG] && WINDOW.addEventListener) {\n GLOBAL_WITH_FLAGS[SENTRY_POPSTATE_LISTENER_ADDED_FLAG] = true;\n\n WINDOW.addEventListener('popstate', () => {\n const client = getClient();\n if (!client) {\n currentNumericNavigationSpan = undefined;\n return;\n }\n\n const pathname = WINDOW.location?.pathname || '/';\n\n // If there's an active numeric navigation span, update it instead of creating a duplicate\n if (currentNumericNavigationSpan) {\n if (currentNumericNavigationSpan.isRecording()) {\n updateNavigationSpanUrlFromLocation(currentNumericNavigationSpan);\n }\n currentNumericNavigationSpan = undefined;\n return;\n }\n\n // Only create a new span for actual browser back/forward button clicks\n startBrowserTracingNavigationSpan(\n client,\n {\n name: pathname,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'url',\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'navigation',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.navigation.react_router.instrumentation_api',\n 'navigation.type': 'browser.popstate',\n },\n },\n { url: getAbsoluteUrl(pathname) },\n );\n });\n\n DEBUG_BUILD && debug.log('React Router popstate listener registered for browser back/forward navigation.');\n }\n\n router.instrument({\n async navigate(callNavigate, info) {\n // navigate(0) triggers a page reload - skip span creation, but still capture errors\n // (navigation can be rejected before reload, e.g., by a navigation guard)\n if (info.to === 0) {\n const result = await callNavigate();\n if (result.status === 'error' && result.error instanceof Error) {\n captureInstrumentationError(result, captureErrors, 'react_router.navigate', {\n [URL_FULL]: filterCollectedUrl(info.currentUrl),\n });\n }\n return;\n }\n\n GLOBAL_WITH_FLAGS[SENTRY_NAVIGATE_HOOK_INVOKED_FLAG] = true;\n\n // Handle numeric navigations (navigate(-1), navigate(1), etc.)\n if (typeof info.to === 'number') {\n const client = getClient();\n let navigationSpan;\n\n if (client) {\n const navigationType = info.to < 0 ? 'router.back' : 'router.forward';\n const currentPathname = WINDOW.location?.pathname || info.currentUrl;\n\n navigationSpan = startBrowserTracingNavigationSpan(\n client,\n {\n name: currentPathname,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'url',\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'navigation',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.navigation.react_router.instrumentation_api',\n 'navigation.type': navigationType,\n },\n },\n { url: getAbsoluteUrl(currentPathname) },\n );\n\n // Store ref so popstate listener can update it instead of creating a duplicate\n currentNumericNavigationSpan = navigationSpan;\n }\n\n try {\n const result = await callNavigate();\n\n if (navigationSpan && WINDOW.location) {\n finalizeNavigationSpanFromHydratedRouter(navigationSpan);\n }\n\n if (result.status === 'error' && result.error instanceof Error) {\n if (navigationSpan) {\n navigationSpan.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n }\n captureInstrumentationError(result, captureErrors, 'react_router.navigate', {\n [URL_FULL]: WINDOW.location?.pathname || filterCollectedUrl(info.currentUrl),\n });\n }\n } finally {\n currentNumericNavigationSpan = undefined;\n }\n return;\n }\n\n // Handle string/object navigations (e.g., navigate('/about') or navigate({ pathname: '/about' }))\n const client = getClient();\n const toPath = resolveNavigateArg(info.to);\n let navigationSpan;\n\n if (client) {\n navigationSpan = startBrowserTracingNavigationSpan(\n client,\n {\n name: toPath,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'url',\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'navigation',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.navigation.react_router.instrumentation_api',\n 'navigation.type': 'router.navigate',\n },\n },\n { url: resolveNavigateAbsoluteUrl(info.to, info.currentUrl) },\n );\n }\n\n const result = await callNavigate();\n if (result.status === 'error' && result.error instanceof Error) {\n if (navigationSpan) {\n navigationSpan.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n }\n captureInstrumentationError(result, captureErrors, 'react_router.navigate', {\n [URL_FULL]: filterCollectedUrl(toPath),\n });\n }\n return;\n },\n\n async fetch(callFetch, info) {\n await startSpan(\n {\n name: `Fetcher ${info.fetcherKey}`,\n attributes: {\n [SENTRY_OP]: GENERAL_FUNCTION_SPAN_OP,\n [CODE_FUNCTION_NAME]: 'fetcher',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.react_router.instrumentation_api',\n },\n },\n async span => {\n const result = await callFetch();\n if (result.status === 'error' && result.error instanceof Error) {\n span.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n captureInstrumentationError(result, captureErrors, 'react_router.fetcher', {\n [URL_FULL]: filterCollectedUrl(info.href),\n });\n }\n },\n );\n },\n });\n },\n\n route(route: InstrumentableRoute) {\n const routeId = route.id;\n\n route.instrument({\n async loader(callLoader, info) {\n const urlPath = getPathFromRequest(info.request);\n const pattern = normalizeRoutePath(getPattern(info));\n const routePattern = pattern || urlPath;\n // Parameterize the active navigation root span. (Route hooks don't fire on initial\n // pageload, so this only affects navigations.)\n updateRootSpanRoute(routePattern, !!pattern);\n\n await startSpan(\n {\n name: routePattern,\n attributes: {\n [SENTRY_OP]: GENERAL_FUNCTION_SPAN_OP,\n [CODE_FUNCTION_NAME]: 'clientLoader',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.react_router.instrumentation_api',\n },\n },\n async span => {\n const result = await callLoader();\n if (result.status === 'error' && result.error instanceof Error) {\n span.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n captureInstrumentationError(result, captureErrors, 'react_router.client_loader', {\n [URL_FULL]: urlPath,\n });\n }\n },\n );\n },\n\n async action(callAction, info) {\n const urlPath = getPathFromRequest(info.request);\n const pattern = normalizeRoutePath(getPattern(info));\n const routePattern = pattern || urlPath;\n updateRootSpanRoute(routePattern, !!pattern);\n\n await startSpan(\n {\n name: routePattern,\n attributes: {\n [SENTRY_OP]: GENERAL_FUNCTION_SPAN_OP,\n [CODE_FUNCTION_NAME]: 'clientAction',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.react_router.instrumentation_api',\n },\n },\n async span => {\n const result = await callAction();\n if (result.status === 'error' && result.error instanceof Error) {\n span.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n captureInstrumentationError(result, captureErrors, 'react_router.client_action', {\n [URL_FULL]: urlPath,\n });\n }\n },\n );\n },\n\n async middleware(callMiddleware, info) {\n const urlPath = getPathFromRequest(info.request);\n const routePattern = normalizeRoutePath(getPattern(info)) || urlPath;\n\n let counters = middlewareCountersMap.get(info.request);\n if (!counters) {\n counters = {};\n middlewareCountersMap.set(info.request, counters);\n }\n\n const middlewareIndex = counters[routeId] ?? 0;\n counters[routeId] = middlewareIndex + 1;\n\n await startSpan(\n {\n name: `middleware ${routeId}`,\n attributes: {\n [SENTRY_OP]: WEB_SERVER_MIDDLEWARE_SPAN_OP,\n [CODE_FUNCTION_NAME]: 'clientMiddleware',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.react_router.instrumentation_api',\n 'react_router.route.id': routeId,\n 'http.route': routePattern,\n 'react_router.middleware.index': middlewareIndex,\n },\n },\n async span => {\n const result = await callMiddleware();\n if (result.status === 'error' && result.error instanceof Error) {\n span.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n captureInstrumentationError(result, captureErrors, 'react_router.client_middleware', {\n [URL_FULL]: urlPath,\n });\n }\n },\n );\n },\n\n async lazy(callLazy) {\n await startSpan(\n {\n name: 'Lazy Route Load',\n attributes: {\n [SENTRY_OP]: GENERAL_FUNCTION_SPAN_OP,\n [CODE_FUNCTION_NAME]: 'lazy',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.react_router.instrumentation_api',\n },\n },\n async span => {\n const result = await callLazy();\n if (result.status === 'error' && result.error instanceof Error) {\n span.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n captureInstrumentationError(result, captureErrors, 'react_router.client_lazy', {});\n }\n },\n );\n },\n });\n },\n };\n}\n\n/**\n * Updates the active navigation/pageload root span name with the parameterized route, so the\n * transaction reflects the parameterized route pattern (e.g. `/users/:id`).\n */\nfunction updateRootSpanRoute(routeName: string, hasPattern: boolean): void {\n if (!hasPattern) {\n return;\n }\n\n const activeSpan = getActiveSpan();\n const rootSpan = activeSpan && getRootSpan(activeSpan);\n if (!rootSpan) {\n return;\n }\n\n const { op } = spanToJSON(rootSpan);\n if (op !== 'navigation' && op !== 'pageload') {\n return;\n }\n\n updateSpanName(rootSpan, routeName);\n rootSpan.setAttributes({ [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'route', [URL_TEMPLATE]: routeName });\n}\n\n/**\n * Check if React Router's instrumentation API is being used on the client.\n */\nexport function isClientInstrumentationApiUsed(): boolean {\n return !!GLOBAL_WITH_FLAGS[SENTRY_CLIENT_INSTRUMENTATION_FLAG];\n}\n\n/**\n * Check if React Router's instrumentation API's navigate hook was invoked.\n */\nexport function isNavigateHookInvoked(): boolean {\n return !!GLOBAL_WITH_FLAGS[SENTRY_NAVIGATE_HOOK_INVOKED_FLAG];\n}\n"],"names":["GLOBAL_OBJ","DEBUG_BUILD","debug","getClient","updateNavigationSpanUrlFromLocation","startBrowserTracingNavigationSpan","SEMANTIC_ATTRIBUTE_SENTRY_SOURCE","SEMANTIC_ATTRIBUTE_SENTRY_OP","SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN","getAbsoluteUrl","result","captureInstrumentationError","URL_FULL","filterCollectedUrl","client","navigationSpan","finalizeNavigationSpanFromHydratedRouter","SPAN_STATUS_ERROR","resolveNavigateArg","resolveNavigateAbsoluteUrl","startSpan","SENTRY_OP","GENERAL_FUNCTION_SPAN_OP","CODE_FUNCTION_NAME","getPathFromRequest","normalizeRoutePath","getPattern","WEB_SERVER_MIDDLEWARE_SPAN_OP","getActiveSpan","getRootSpan","spanToJSON","updateSpanName","URL_TEMPLATE"],"mappings":";;;;;;;;;;AA8BA,MAAM,MAAA,GAASA,eAAA;AAGf,IAAI,4BAAA;AAGJ,MAAM,qBAAA,uBAA4B,OAAA,EAAwC;AAE1E,MAAM,kCAAA,GAAqC,8CAAA;AAE3C,MAAM,iCAAA,GAAoC,wCAAA;AAC1C,MAAM,mCAAA,GAAsC,0CAAA;AAQ5C,MAAM,iBAAA,GAAoBA,eAAA;AAiBnB,SAAS,iCAAA,CACd,OAAA,GAAoD,EAAC,EAC9B;AACvB,EAAA,MAAM,EAAE,aAAA,GAAgB,IAAA,EAAK,GAAI,OAAA;AAEjC,EAAAC,sBAAA,IAAeC,UAAA,CAAM,IAAI,kDAAkD,CAAA;AAE3E,EAAA,OAAO;AAAA,IACL,OAAO,MAAA,EAA8B;AAKnC,MAAA,iBAAA,CAAkB,kCAAkC,CAAA,GAAI,IAAA;AACxD,MAAAD,sBAAA,IAAeC,UAAA,CAAM,IAAI,iEAAiE,CAAA;AAG1F,MAAA,IAAI,CAAC,iBAAA,CAAkB,mCAAmC,CAAA,IAAK,OAAO,gBAAA,EAAkB;AACtF,QAAA,iBAAA,CAAkB,mCAAmC,CAAA,GAAI,IAAA;AAEzD,QAAA,MAAA,CAAO,gBAAA,CAAiB,YAAY,MAAM;AACxC,UAAA,MAAM,SAASC,cAAA,EAAU;AACzB,UAAA,IAAI,CAAC,MAAA,EAAQ;AACX,YAAA,4BAAA,GAA+B,MAAA;AAC/B,YAAA;AAAA,UACF;AAEA,UAAA,MAAM,QAAA,GAAW,MAAA,CAAO,QAAA,EAAU,QAAA,IAAY,GAAA;AAG9C,UAAA,IAAI,4BAAA,EAA8B;AAChC,YAAA,IAAI,4BAAA,CAA6B,aAAY,EAAG;AAC9C,cAAAC,2CAAA,CAAoC,4BAA4B,CAAA;AAAA,YAClE;AACA,YAAA,4BAAA,GAA+B,MAAA;AAC/B,YAAA;AAAA,UACF;AAGA,UAAAC,yCAAA;AAAA,YACE,MAAA;AAAA,YACA;AAAA,cACE,IAAA,EAAM,QAAA;AAAA,cACN,UAAA,EAAY;AAAA,gBACV,CAACC,qCAAgC,GAAG,KAAA;AAAA,gBACpC,CAACC,iCAA4B,GAAG,YAAA;AAAA,gBAChC,CAACC,qCAAgC,GAAG,kDAAA;AAAA,gBACpC,iBAAA,EAAmB;AAAA;AACrB,aACF;AAAA,YACA,EAAE,GAAA,EAAKC,sBAAA,CAAe,QAAQ,CAAA;AAAE,WAClC;AAAA,QACF,CAAC,CAAA;AAED,QAAAR,sBAAA,IAAeC,UAAA,CAAM,IAAI,gFAAgF,CAAA;AAAA,MAC3G;AAEA,MAAA,MAAA,CAAO,UAAA,CAAW;AAAA,QAChB,MAAM,QAAA,CAAS,YAAA,EAAc,IAAA,EAAM;AAGjC,UAAA,IAAI,IAAA,CAAK,OAAO,CAAA,EAAG;AACjB,YAAA,MAAMQ,OAAAA,GAAS,MAAM,YAAA,EAAa;AAClC,YAAA,IAAIA,OAAAA,CAAO,MAAA,KAAW,OAAA,IAAWA,OAAAA,CAAO,iBAAiB,KAAA,EAAO;AAC9D,cAAAC,iCAAA,CAA4BD,OAAAA,EAAQ,eAAe,uBAAA,EAAyB;AAAA,gBAC1E,CAACE,mBAAQ,GAAGC,uBAAA,CAAmB,KAAK,UAAU;AAAA,eAC/C,CAAA;AAAA,YACH;AACA,YAAA;AAAA,UACF;AAEA,UAAA,iBAAA,CAAkB,iCAAiC,CAAA,GAAI,IAAA;AAGvD,UAAA,IAAI,OAAO,IAAA,CAAK,EAAA,KAAO,QAAA,EAAU;AAC/B,YAAA,MAAMC,UAASX,cAAA,EAAU;AACzB,YAAA,IAAIY,eAAAA;AAEJ,YAAA,IAAID,OAAAA,EAAQ;AACV,cAAA,MAAM,cAAA,GAAiB,IAAA,CAAK,EAAA,GAAK,CAAA,GAAI,aAAA,GAAgB,gBAAA;AACrD,cAAA,MAAM,eAAA,GAAkB,MAAA,CAAO,QAAA,EAAU,QAAA,IAAY,IAAA,CAAK,UAAA;AAE1D,cAAAC,eAAAA,GAAiBV,yCAAA;AAAA,gBACfS,OAAAA;AAAA,gBACA;AAAA,kBACE,IAAA,EAAM,eAAA;AAAA,kBACN,UAAA,EAAY;AAAA,oBACV,CAACR,qCAAgC,GAAG,KAAA;AAAA,oBACpC,CAACC,iCAA4B,GAAG,YAAA;AAAA,oBAChC,CAACC,qCAAgC,GAAG,kDAAA;AAAA,oBACpC,iBAAA,EAAmB;AAAA;AACrB,iBACF;AAAA,gBACA,EAAE,GAAA,EAAKC,sBAAA,CAAe,eAAe,CAAA;AAAE,eACzC;AAGA,cAAA,4BAAA,GAA+BM,eAAAA;AAAA,YACjC;AAEA,YAAA,IAAI;AACF,cAAA,MAAML,OAAAA,GAAS,MAAM,YAAA,EAAa;AAElC,cAAA,IAAIK,eAAAA,IAAkB,OAAO,QAAA,EAAU;AACrC,gBAAAC,gDAAA,CAAyCD,eAAc,CAAA;AAAA,cACzD;AAEA,cAAA,IAAIL,OAAAA,CAAO,MAAA,KAAW,OAAA,IAAWA,OAAAA,CAAO,iBAAiB,KAAA,EAAO;AAC9D,gBAAA,IAAIK,eAAAA,EAAgB;AAClB,kBAAAA,gBAAe,SAAA,CAAU,EAAE,MAAME,sBAAA,EAAmB,OAAA,EAAS,kBAAkB,CAAA;AAAA,gBACjF;AACA,gBAAAN,iCAAA,CAA4BD,OAAAA,EAAQ,eAAe,uBAAA,EAAyB;AAAA,kBAC1E,CAACE,mBAAQ,GAAG,MAAA,CAAO,UAAU,QAAA,IAAYC,uBAAA,CAAmB,KAAK,UAAU;AAAA,iBAC5E,CAAA;AAAA,cACH;AAAA,YACF,CAAA,SAAE;AACA,cAAA,4BAAA,GAA+B,MAAA;AAAA,YACjC;AACA,YAAA;AAAA,UACF;AAGA,UAAA,MAAM,SAASV,cAAA,EAAU;AACzB,UAAA,MAAM,MAAA,GAASe,0BAAA,CAAmB,IAAA,CAAK,EAAE,CAAA;AACzC,UAAA,IAAI,cAAA;AAEJ,UAAA,IAAI,MAAA,EAAQ;AACV,YAAA,cAAA,GAAiBb,yCAAA;AAAA,cACf,MAAA;AAAA,cACA;AAAA,gBACE,IAAA,EAAM,MAAA;AAAA,gBACN,UAAA,EAAY;AAAA,kBACV,CAACC,qCAAgC,GAAG,KAAA;AAAA,kBACpC,CAACC,iCAA4B,GAAG,YAAA;AAAA,kBAChC,CAACC,qCAAgC,GAAG,kDAAA;AAAA,kBACpC,iBAAA,EAAmB;AAAA;AACrB,eACF;AAAA,cACA,EAAE,GAAA,EAAKW,kCAAA,CAA2B,KAAK,EAAA,EAAI,IAAA,CAAK,UAAU,CAAA;AAAE,aAC9D;AAAA,UACF;AAEA,UAAA,MAAM,MAAA,GAAS,MAAM,YAAA,EAAa;AAClC,UAAA,IAAI,MAAA,CAAO,MAAA,KAAW,OAAA,IAAW,MAAA,CAAO,iBAAiB,KAAA,EAAO;AAC9D,YAAA,IAAI,cAAA,EAAgB;AAClB,cAAA,cAAA,CAAe,UAAU,EAAE,IAAA,EAAMF,sBAAA,EAAmB,OAAA,EAAS,kBAAkB,CAAA;AAAA,YACjF;AACA,YAAAN,iCAAA,CAA4B,MAAA,EAAQ,eAAe,uBAAA,EAAyB;AAAA,cAC1E,CAACC,mBAAQ,GAAGC,uBAAA,CAAmB,MAAM;AAAA,aACtC,CAAA;AAAA,UACH;AACA,UAAA;AAAA,QACF,CAAA;AAAA,QAEA,MAAM,KAAA,CAAM,SAAA,EAAW,IAAA,EAAM;AAC3B,UAAA,MAAMO,cAAA;AAAA,YACJ;AAAA,cACE,IAAA,EAAM,CAAA,QAAA,EAAW,IAAA,CAAK,UAAU,CAAA,CAAA;AAAA,cAChC,UAAA,EAAY;AAAA,gBACV,CAACC,oBAAS,GAAGC,2BAAA;AAAA,gBACb,CAACC,6BAAkB,GAAG,SAAA;AAAA,gBACtB,CAACf,qCAAgC,GAAG;AAAA;AACtC,aACF;AAAA,YACA,OAAM,IAAA,KAAQ;AACZ,cAAA,MAAM,MAAA,GAAS,MAAM,SAAA,EAAU;AAC/B,cAAA,IAAI,MAAA,CAAO,MAAA,KAAW,OAAA,IAAW,MAAA,CAAO,iBAAiB,KAAA,EAAO;AAC9D,gBAAA,IAAA,CAAK,UAAU,EAAE,IAAA,EAAMS,sBAAA,EAAmB,OAAA,EAAS,kBAAkB,CAAA;AACrE,gBAAAN,iCAAA,CAA4B,MAAA,EAAQ,eAAe,sBAAA,EAAwB;AAAA,kBACzE,CAACC,mBAAQ,GAAGC,uBAAA,CAAmB,KAAK,IAAI;AAAA,iBACzC,CAAA;AAAA,cACH;AAAA,YACF;AAAA,WACF;AAAA,QACF;AAAA,OACD,CAAA;AAAA,IACH,CAAA;AAAA,IAEA,MAAM,KAAA,EAA4B;AAChC,MAAA,MAAM,UAAU,KAAA,CAAM,EAAA;AAEtB,MAAA,KAAA,CAAM,UAAA,CAAW;AAAA,QACf,MAAM,MAAA,CAAO,UAAA,EAAY,IAAA,EAAM;AAC7B,UAAA,MAAM,OAAA,GAAUW,wBAAA,CAAmB,IAAA,CAAK,OAAO,CAAA;AAC/C,UAAA,MAAM,OAAA,GAAUC,wBAAA,CAAmBC,gBAAA,CAAW,IAAI,CAAC,CAAA;AACnD,UAAA,MAAM,eAAe,OAAA,IAAW,OAAA;AAGhC,UAAA,mBAAA,CAAoB,YAAA,EAAc,CAAC,CAAC,OAAO,CAAA;AAE3C,UAAA,MAAMN,cAAA;AAAA,YACJ;AAAA,cACE,IAAA,EAAM,YAAA;AAAA,cACN,UAAA,EAAY;AAAA,gBACV,CAACC,oBAAS,GAAGC,2BAAA;AAAA,gBACb,CAACC,6BAAkB,GAAG,cAAA;AAAA,gBACtB,CAACf,qCAAgC,GAAG;AAAA;AACtC,aACF;AAAA,YACA,OAAM,IAAA,KAAQ;AACZ,cAAA,MAAM,MAAA,GAAS,MAAM,UAAA,EAAW;AAChC,cAAA,IAAI,MAAA,CAAO,MAAA,KAAW,OAAA,IAAW,MAAA,CAAO,iBAAiB,KAAA,EAAO;AAC9D,gBAAA,IAAA,CAAK,UAAU,EAAE,IAAA,EAAMS,sBAAA,EAAmB,OAAA,EAAS,kBAAkB,CAAA;AACrE,gBAAAN,iCAAA,CAA4B,MAAA,EAAQ,eAAe,4BAAA,EAA8B;AAAA,kBAC/E,CAACC,mBAAQ,GAAG;AAAA,iBACb,CAAA;AAAA,cACH;AAAA,YACF;AAAA,WACF;AAAA,QACF,CAAA;AAAA,QAEA,MAAM,MAAA,CAAO,UAAA,EAAY,IAAA,EAAM;AAC7B,UAAA,MAAM,OAAA,GAAUY,wBAAA,CAAmB,IAAA,CAAK,OAAO,CAAA;AAC/C,UAAA,MAAM,OAAA,GAAUC,wBAAA,CAAmBC,gBAAA,CAAW,IAAI,CAAC,CAAA;AACnD,UAAA,MAAM,eAAe,OAAA,IAAW,OAAA;AAChC,UAAA,mBAAA,CAAoB,YAAA,EAAc,CAAC,CAAC,OAAO,CAAA;AAE3C,UAAA,MAAMN,cAAA;AAAA,YACJ;AAAA,cACE,IAAA,EAAM,YAAA;AAAA,cACN,UAAA,EAAY;AAAA,gBACV,CAACC,oBAAS,GAAGC,2BAAA;AAAA,gBACb,CAACC,6BAAkB,GAAG,cAAA;AAAA,gBACtB,CAACf,qCAAgC,GAAG;AAAA;AACtC,aACF;AAAA,YACA,OAAM,IAAA,KAAQ;AACZ,cAAA,MAAM,MAAA,GAAS,MAAM,UAAA,EAAW;AAChC,cAAA,IAAI,MAAA,CAAO,MAAA,KAAW,OAAA,IAAW,MAAA,CAAO,iBAAiB,KAAA,EAAO;AAC9D,gBAAA,IAAA,CAAK,UAAU,EAAE,IAAA,EAAMS,sBAAA,EAAmB,OAAA,EAAS,kBAAkB,CAAA;AACrE,gBAAAN,iCAAA,CAA4B,MAAA,EAAQ,eAAe,4BAAA,EAA8B;AAAA,kBAC/E,CAACC,mBAAQ,GAAG;AAAA,iBACb,CAAA;AAAA,cACH;AAAA,YACF;AAAA,WACF;AAAA,QACF,CAAA;AAAA,QAEA,MAAM,UAAA,CAAW,cAAA,EAAgB,IAAA,EAAM;AACrC,UAAA,MAAM,OAAA,GAAUY,wBAAA,CAAmB,IAAA,CAAK,OAAO,CAAA;AAC/C,UAAA,MAAM,YAAA,GAAeC,wBAAA,CAAmBC,gBAAA,CAAW,IAAI,CAAC,CAAA,IAAK,OAAA;AAE7D,UAAA,IAAI,QAAA,GAAW,qBAAA,CAAsB,GAAA,CAAI,IAAA,CAAK,OAAO,CAAA;AACrD,UAAA,IAAI,CAAC,QAAA,EAAU;AACb,YAAA,QAAA,GAAW,EAAC;AACZ,YAAA,qBAAA,CAAsB,GAAA,CAAI,IAAA,CAAK,OAAA,EAAS,QAAQ,CAAA;AAAA,UAClD;AAEA,UAAA,MAAM,eAAA,GAAkB,QAAA,CAAS,OAAO,CAAA,IAAK,CAAA;AAC7C,UAAA,QAAA,CAAS,OAAO,IAAI,eAAA,GAAkB,CAAA;AAEtC,UAAA,MAAMN,cAAA;AAAA,YACJ;AAAA,cACE,IAAA,EAAM,cAAc,OAAO,CAAA,CAAA;AAAA,cAC3B,UAAA,EAAY;AAAA,gBACV,CAACC,oBAAS,GAAGM,gCAAA;AAAA,gBACb,CAACJ,6BAAkB,GAAG,kBAAA;AAAA,gBACtB,CAACf,qCAAgC,GAAG,gDAAA;AAAA,gBACpC,uBAAA,EAAyB,OAAA;AAAA,gBACzB,YAAA,EAAc,YAAA;AAAA,gBACd,+BAAA,EAAiC;AAAA;AACnC,aACF;AAAA,YACA,OAAM,IAAA,KAAQ;AACZ,cAAA,MAAM,MAAA,GAAS,MAAM,cAAA,EAAe;AACpC,cAAA,IAAI,MAAA,CAAO,MAAA,KAAW,OAAA,IAAW,MAAA,CAAO,iBAAiB,KAAA,EAAO;AAC9D,gBAAA,IAAA,CAAK,UAAU,EAAE,IAAA,EAAMS,sBAAA,EAAmB,OAAA,EAAS,kBAAkB,CAAA;AACrE,gBAAAN,iCAAA,CAA4B,MAAA,EAAQ,eAAe,gCAAA,EAAkC;AAAA,kBACnF,CAACC,mBAAQ,GAAG;AAAA,iBACb,CAAA;AAAA,cACH;AAAA,YACF;AAAA,WACF;AAAA,QACF,CAAA;AAAA,QAEA,MAAM,KAAK,QAAA,EAAU;AACnB,UAAA,MAAMQ,cAAA;AAAA,YACJ;AAAA,cACE,IAAA,EAAM,iBAAA;AAAA,cACN,UAAA,EAAY;AAAA,gBACV,CAACC,oBAAS,GAAGC,2BAAA;AAAA,gBACb,CAACC,6BAAkB,GAAG,MAAA;AAAA,gBACtB,CAACf,qCAAgC,GAAG;AAAA;AACtC,aACF;AAAA,YACA,OAAM,IAAA,KAAQ;AACZ,cAAA,MAAM,MAAA,GAAS,MAAM,QAAA,EAAS;AAC9B,cAAA,IAAI,MAAA,CAAO,MAAA,KAAW,OAAA,IAAW,MAAA,CAAO,iBAAiB,KAAA,EAAO;AAC9D,gBAAA,IAAA,CAAK,UAAU,EAAE,IAAA,EAAMS,sBAAA,EAAmB,OAAA,EAAS,kBAAkB,CAAA;AACrE,gBAAAN,iCAAA,CAA4B,MAAA,EAAQ,aAAA,EAAe,0BAAA,EAA4B,EAAE,CAAA;AAAA,cACnF;AAAA,YACF;AAAA,WACF;AAAA,QACF;AAAA,OACD,CAAA;AAAA,IACH;AAAA,GACF;AACF;AAMA,SAAS,mBAAA,CAAoB,WAAmB,UAAA,EAA2B;AACzE,EAAA,IAAI,CAAC,UAAA,EAAY;AACf,IAAA;AAAA,EACF;AAEA,EAAA,MAAM,aAAaiB,kBAAA,EAAc;AACjC,EAAA,MAAM,QAAA,GAAW,UAAA,IAAcC,gBAAA,CAAY,UAAU,CAAA;AACrD,EAAA,IAAI,CAAC,QAAA,EAAU;AACb,IAAA;AAAA,EACF;AAEA,EAAA,MAAM,EAAE,EAAA,EAAG,GAAIC,eAAA,CAAW,QAAQ,CAAA;AAClC,EAAA,IAAI,EAAA,KAAO,YAAA,IAAgB,EAAA,KAAO,UAAA,EAAY;AAC5C,IAAA;AAAA,EACF;AAEA,EAAAC,mBAAA,CAAe,UAAU,SAAS,CAAA;AAClC,EAAA,QAAA,CAAS,aAAA,CAAc,EAAE,CAACzB,qCAAgC,GAAG,SAAS,CAAC0B,uBAAY,GAAG,SAAA,EAAW,CAAA;AACnG;AAKO,SAAS,8BAAA,GAA0C;AACxD,EAAA,OAAO,CAAC,CAAC,iBAAA,CAAkB,kCAAkC,CAAA;AAC/D;AAKO,SAAS,qBAAA,GAAiC;AAC/C,EAAA,OAAO,CAAC,CAAC,iBAAA,CAAkB,iCAAiC,CAAA;AAC9D;;;;;;"}
|
|
@@ -82,7 +82,10 @@ function instrumentHydratedRouter() {
|
|
|
82
82
|
// this event is for the currently active root span
|
|
83
83
|
(destinationPathname === utils.normalizePathname(rootSpanName) || spanPathname && destinationPathname === utils.normalizePathname(spanPathname))) {
|
|
84
84
|
rootSpan.updateName(parameterizedRoute);
|
|
85
|
-
rootSpan.setAttributes({
|
|
85
|
+
rootSpan.setAttributes({
|
|
86
|
+
[core.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: "route",
|
|
87
|
+
[attributes.URL_TEMPLATE]: parameterizedRoute
|
|
88
|
+
});
|
|
86
89
|
}
|
|
87
90
|
});
|
|
88
91
|
return true;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hydratedRouter.js","sources":["../../../src/client/hydratedRouter.ts"],"sourcesContent":["import { getAbsoluteUrl, startBrowserTracingNavigationSpan } from '@sentry/browser';\nimport type { Span } from '@sentry/core';\nimport {\n debug,\n getActiveSpan,\n getClient,\n getRootSpan,\n GLOBAL_OBJ,\n isThenable,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n SEMANTIC_ATTRIBUTE_SENTRY_SOURCE,\n spanToJSON,\n} from '@sentry/core';\nimport type { DataRouter } from 'react-router';\nimport { DEBUG_BUILD } from '../common/debug-build';\nimport { isClientInstrumentationApiUsed } from './createClientInstrumentation';\nimport {\n finalizeNavigationSpanFromRouterState,\n getParameterizedRoute,\n normalizePathname,\n resolveNavigateAbsoluteUrl,\n resolveNavigateArg,\n} from './utils';\nimport { URL_PATH, URL_TEMPLATE } from '@sentry/conventions/attributes';\n\nconst GLOBAL_OBJ_WITH_DATA_ROUTER = GLOBAL_OBJ as typeof GLOBAL_OBJ & {\n __reactRouterDataRouter?: DataRouter;\n};\n\nconst WINDOW = GLOBAL_OBJ as typeof GLOBAL_OBJ & Window;\n\nconst MAX_RETRIES = 40; // 2 seconds at 50ms interval\n\n/**\n * Instruments the React Router Data Router for pageloads and navigation.\n *\n * This function waits for the router to be available after hydration, then:\n * 1. Updates the pageload transaction with parameterized route info\n * 2. Patches router.navigate() to create navigation transactions\n * 3. Subscribes to router state changes to update navigation transactions with parameterized routes\n */\nexport function instrumentHydratedRouter(): void {\n function trySubscribe(): boolean {\n const router = GLOBAL_OBJ_WITH_DATA_ROUTER.__reactRouterDataRouter;\n\n if (router) {\n // The first time we hit the router, we try to update the pageload transaction\n const pageloadSpan = getActiveRootSpan();\n\n if (pageloadSpan) {\n const pageloadName = spanToJSON(pageloadSpan).description;\n const parameterizePageloadRoute = getParameterizedRoute(router.state);\n if (\n pageloadName &&\n // this event is for the currently active pageload\n normalizePathname(router.state.location.pathname) === normalizePathname(pageloadName)\n ) {\n pageloadSpan.updateName(parameterizePageloadRoute);\n pageloadSpan.setAttributes({\n [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'route',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.pageload.react_router',\n [URL_TEMPLATE]: parameterizePageloadRoute,\n });\n }\n }\n\n // Patching navigate for creating accurate navigation transactions\n if (typeof router.navigate === 'function') {\n const originalNav = router.navigate.bind(router);\n router.navigate = function sentryPatchedNavigate(...args) {\n // Skip if instrumentation API is enabled (it handles navigation spans itself)\n if (!isClientInstrumentationApiUsed()) {\n const target = args[0];\n\n if (typeof target === 'number') {\n // navigate(0) triggers a reload, not a route change — skip span creation\n if (target !== 0) {\n const currentPathname = WINDOW.location?.pathname || '/';\n const navigationSpan = maybeCreateNavigationTransaction(\n currentPathname,\n getAbsoluteUrl(currentPathname),\n 'url',\n );\n\n const result = originalNav(...args);\n\n // Numeric navigations (`navigate(-1)`/`navigate(1)`) don't carry a destination\n // path, so we can only resolve the real URL/route once the router has settled.\n if (navigationSpan) {\n // Finalize from the (updated) router state after navigation completes, in both\n // the resolve and reject paths, so a rejected navigation still ends up with the\n // correct URL attributes instead of the placeholder start pathname.\n if (isThenable(result)) {\n result.then(\n () => finalizeNavigationSpanFromRouterState(navigationSpan, router.state),\n () => finalizeNavigationSpanFromRouterState(navigationSpan, router.state),\n );\n } else {\n finalizeNavigationSpanFromRouterState(navigationSpan, router.state);\n }\n }\n\n return result;\n }\n } else {\n maybeCreateNavigationTransaction(\n resolveNavigateArg(target) || '<unknown route>',\n resolveNavigateAbsoluteUrl(target),\n 'url',\n );\n }\n }\n return originalNav(...args);\n };\n }\n\n // Subscribe to router state changes to update navigation transactions (and any pageload\n // whose route info only became available after `trySubscribe`, e.g. lazy routes) with the\n // parameterized route.\n router.subscribe(newState => {\n const rootSpan = getActiveRootSpan();\n\n if (!rootSpan) {\n return;\n }\n\n const rootSpanJson = spanToJSON(rootSpan);\n\n // When the instrumentation API is active, navigation roots are parameterized\n // by the native route hooks\n if (\n rootSpanJson.op === 'navigation' &&\n isClientInstrumentationApiUsed() &&\n rootSpanJson.data?.[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE] === 'route'\n ) {\n return;\n }\n\n const rootSpanName = rootSpanJson.description;\n const parameterizedRoute = getParameterizedRoute(newState);\n const spanPathname = rootSpanJson.data?.[URL_PATH] as string | undefined;\n const destinationPathname = normalizePathname(newState.location.pathname);\n\n if (\n rootSpanName &&\n newState.navigation.state === 'idle' && // navigation has completed\n // this event is for the currently active root span\n (destinationPathname === normalizePathname(rootSpanName) ||\n (spanPathname && destinationPathname === normalizePathname(spanPathname)))\n ) {\n rootSpan.updateName(parameterizedRoute);\n rootSpan.setAttributes({ [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'route', [URL_TEMPLATE]: parameterizedRoute });\n }\n });\n return true;\n }\n return false;\n }\n\n // Wait until the router is available (since the SDK loads before hydration)\n if (!trySubscribe()) {\n let retryCount = 0;\n // Retry until the router is available or max retries reached\n const interval = setInterval(() => {\n if (trySubscribe() || retryCount >= MAX_RETRIES) {\n if (retryCount >= MAX_RETRIES) {\n DEBUG_BUILD && debug.warn('Unable to instrument React Router: router not found after hydration.');\n }\n clearInterval(interval);\n }\n retryCount++;\n }, 50);\n }\n}\n\nfunction maybeCreateNavigationTransaction(name: string, url: string, source: 'url' | 'route'): Span | undefined {\n const client = getClient();\n\n if (!client) {\n return undefined;\n }\n\n return startBrowserTracingNavigationSpan(\n client,\n {\n name,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: source,\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'navigation',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.navigation.react_router',\n ...(source === 'route' ? { [URL_TEMPLATE]: name } : {}),\n },\n },\n { url },\n );\n}\n\nfunction getActiveRootSpan(): Span | undefined {\n const activeSpan = getActiveSpan();\n if (!activeSpan) {\n return undefined;\n }\n\n const rootSpan = getRootSpan(activeSpan);\n\n const op = spanToJSON(rootSpan).op;\n\n // Only use this root span if it is a pageload or navigation span\n return op === 'navigation' || op === 'pageload' ? rootSpan : undefined;\n}\n"],"names":["GLOBAL_OBJ","spanToJSON","getParameterizedRoute","normalizePathname","SEMANTIC_ATTRIBUTE_SENTRY_SOURCE","SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN","URL_TEMPLATE","isClientInstrumentationApiUsed","getAbsoluteUrl","isThenable","finalizeNavigationSpanFromRouterState","resolveNavigateArg","resolveNavigateAbsoluteUrl","URL_PATH","DEBUG_BUILD","debug","getClient","startBrowserTracingNavigationSpan","SEMANTIC_ATTRIBUTE_SENTRY_OP","getActiveSpan","getRootSpan"],"mappings":";;;;;;;;;AA0BA,MAAM,2BAAA,GAA8BA,eAAA;AAIpC,MAAM,MAAA,GAASA,eAAA;AAEf,MAAM,WAAA,GAAc,EAAA;AAUb,SAAS,wBAAA,GAAiC;AAC/C,EAAA,SAAS,YAAA,GAAwB;AAC/B,IAAA,MAAM,SAAS,2BAAA,CAA4B,uBAAA;AAE3C,IAAA,IAAI,MAAA,EAAQ;AAEV,MAAA,MAAM,eAAe,iBAAA,EAAkB;AAEvC,MAAA,IAAI,YAAA,EAAc;AAChB,QAAA,MAAM,YAAA,GAAeC,eAAA,CAAW,YAAY,CAAA,CAAE,WAAA;AAC9C,QAAA,MAAM,yBAAA,GAA4BC,2BAAA,CAAsB,MAAA,CAAO,KAAK,CAAA;AACpE,QAAA,IACE,YAAA;AAAA,QAEAC,uBAAA,CAAkB,OAAO,KAAA,CAAM,QAAA,CAAS,QAAQ,CAAA,KAAMA,uBAAA,CAAkB,YAAY,CAAA,EACpF;AACA,UAAA,YAAA,CAAa,WAAW,yBAAyB,CAAA;AACjD,UAAA,YAAA,CAAa,aAAA,CAAc;AAAA,YACzB,CAACC,qCAAgC,GAAG,OAAA;AAAA,YACpC,CAACC,qCAAgC,GAAG,4BAAA;AAAA,YACpC,CAACC,uBAAY,GAAG;AAAA,WACjB,CAAA;AAAA,QACH;AAAA,MACF;AAGA,MAAA,IAAI,OAAO,MAAA,CAAO,QAAA,KAAa,UAAA,EAAY;AACzC,QAAA,MAAM,WAAA,GAAc,MAAA,CAAO,QAAA,CAAS,IAAA,CAAK,MAAM,CAAA;AAC/C,QAAA,MAAA,CAAO,QAAA,GAAW,SAAS,qBAAA,CAAA,GAAyB,IAAA,EAAM;AAExD,UAAA,IAAI,CAACC,4DAA+B,EAAG;AACrC,YAAA,MAAM,MAAA,GAAS,KAAK,CAAC,CAAA;AAErB,YAAA,IAAI,OAAO,WAAW,QAAA,EAAU;AAE9B,cAAA,IAAI,WAAW,CAAA,EAAG;AAChB,gBAAA,MAAM,eAAA,GAAkB,MAAA,CAAO,QAAA,EAAU,QAAA,IAAY,GAAA;AACrD,gBAAA,MAAM,cAAA,GAAiB,gCAAA;AAAA,kBACrB,eAAA;AAAA,kBACAC,uBAAe,eAAe,CAAA;AAAA,kBAC9B;AAAA,iBACF;AAEA,gBAAA,MAAM,MAAA,GAAS,WAAA,CAAY,GAAG,IAAI,CAAA;AAIlC,gBAAA,IAAI,cAAA,EAAgB;AAIlB,kBAAA,IAAIC,eAAA,CAAW,MAAM,CAAA,EAAG;AACtB,oBAAA,MAAA,CAAO,IAAA;AAAA,sBACL,MAAMC,2CAAA,CAAsC,cAAA,EAAgB,MAAA,CAAO,KAAK,CAAA;AAAA,sBACxE,MAAMA,2CAAA,CAAsC,cAAA,EAAgB,MAAA,CAAO,KAAK;AAAA,qBAC1E;AAAA,kBACF,CAAA,MAAO;AACL,oBAAAA,2CAAA,CAAsC,cAAA,EAAgB,OAAO,KAAK,CAAA;AAAA,kBACpE;AAAA,gBACF;AAEA,gBAAA,OAAO,MAAA;AAAA,cACT;AAAA,YACF,CAAA,MAAO;AACL,cAAA,gCAAA;AAAA,gBACEC,wBAAA,CAAmB,MAAM,CAAA,IAAK,iBAAA;AAAA,gBAC9BC,iCAA2B,MAAM,CAAA;AAAA,gBACjC;AAAA,eACF;AAAA,YACF;AAAA,UACF;AACA,UAAA,OAAO,WAAA,CAAY,GAAG,IAAI,CAAA;AAAA,QAC5B,CAAA;AAAA,MACF;AAKA,MAAA,MAAA,CAAO,UAAU,CAAA,QAAA,KAAY;AAC3B,QAAA,MAAM,WAAW,iBAAA,EAAkB;AAEnC,QAAA,IAAI,CAAC,QAAA,EAAU;AACb,UAAA;AAAA,QACF;AAEA,QAAA,MAAM,YAAA,GAAeX,gBAAW,QAAQ,CAAA;AAIxC,QAAA,IACE,YAAA,CAAa,OAAO,YAAA,IACpBM,0DAAA,MACA,YAAA,CAAa,IAAA,GAAOH,qCAAgC,CAAA,KAAM,OAAA,EAC1D;AACA,UAAA;AAAA,QACF;AAEA,QAAA,MAAM,eAAe,YAAA,CAAa,WAAA;AAClC,QAAA,MAAM,kBAAA,GAAqBF,4BAAsB,QAAQ,CAAA;AACzD,QAAA,MAAM,YAAA,GAAe,YAAA,CAAa,IAAA,GAAOW,mBAAQ,CAAA;AACjD,QAAA,MAAM,mBAAA,GAAsBV,uBAAA,CAAkB,QAAA,CAAS,QAAA,CAAS,QAAQ,CAAA;AAExE,QAAA,IACE,YAAA,IACA,QAAA,CAAS,UAAA,CAAW,KAAA,KAAU,MAAA;AAAA;AAAA,SAE7B,mBAAA,KAAwBA,wBAAkB,YAAY,CAAA,IACpD,gBAAgB,mBAAA,KAAwBA,uBAAA,CAAkB,YAAY,CAAA,CAAA,EACzE;AACA,UAAA,QAAA,CAAS,WAAW,kBAAkB,CAAA;AACtC,UAAA,QAAA,CAAS,aAAA,CAAc,EAAE,CAACC,qCAAgC,GAAG,SAAS,CAACE,uBAAY,GAAG,kBAAA,EAAoB,CAAA;AAAA,QAC5G;AAAA,MACF,CAAC,CAAA;AACD,MAAA,OAAO,IAAA;AAAA,IACT;AACA,IAAA,OAAO,KAAA;AAAA,EACT;AAGA,EAAA,IAAI,CAAC,cAAa,EAAG;AACnB,IAAA,IAAI,UAAA,GAAa,CAAA;AAEjB,IAAA,MAAM,QAAA,GAAW,YAAY,MAAM;AACjC,MAAA,IAAI,YAAA,EAAa,IAAK,UAAA,IAAc,WAAA,EAAa;AAC/C,QAAA,IAAI,cAAc,WAAA,EAAa;AAC7B,UAAAQ,sBAAA,IAAeC,UAAA,CAAM,KAAK,sEAAsE,CAAA;AAAA,QAClG;AACA,QAAA,aAAA,CAAc,QAAQ,CAAA;AAAA,MACxB;AACA,MAAA,UAAA,EAAA;AAAA,IACF,GAAG,EAAE,CAAA;AAAA,EACP;AACF;AAEA,SAAS,gCAAA,CAAiC,IAAA,EAAc,GAAA,EAAa,MAAA,EAA2C;AAC9G,EAAA,MAAM,SAASC,cAAA,EAAU;AAEzB,EAAA,IAAI,CAAC,MAAA,EAAQ;AACX,IAAA,OAAO,MAAA;AAAA,EACT;AAEA,EAAA,OAAOC,yCAAA;AAAA,IACL,MAAA;AAAA,IACA;AAAA,MACE,IAAA;AAAA,MACA,UAAA,EAAY;AAAA,QACV,CAACb,qCAAgC,GAAG,MAAA;AAAA,QACpC,CAACc,iCAA4B,GAAG,YAAA;AAAA,QAChC,CAACb,qCAAgC,GAAG,8BAAA;AAAA,QACpC,GAAoD;AAAC;AACvD,KACF;AAAA,IACA,EAAE,GAAA;AAAI,GACR;AACF;AAEA,SAAS,iBAAA,GAAsC;AAC7C,EAAA,MAAM,aAAac,kBAAA,EAAc;AACjC,EAAA,IAAI,CAAC,UAAA,EAAY;AACf,IAAA,OAAO,MAAA;AAAA,EACT;AAEA,EAAA,MAAM,QAAA,GAAWC,iBAAY,UAAU,CAAA;AAEvC,EAAA,MAAM,EAAA,GAAKnB,eAAA,CAAW,QAAQ,CAAA,CAAE,EAAA;AAGhC,EAAA,OAAO,EAAA,KAAO,YAAA,IAAgB,EAAA,KAAO,UAAA,GAAa,QAAA,GAAW,MAAA;AAC/D;;;;"}
|
|
1
|
+
{"version":3,"file":"hydratedRouter.js","sources":["../../../src/client/hydratedRouter.ts"],"sourcesContent":["import { getAbsoluteUrl, startBrowserTracingNavigationSpan } from '@sentry/browser';\nimport type { Span } from '@sentry/core';\nimport {\n debug,\n getActiveSpan,\n getClient,\n getRootSpan,\n GLOBAL_OBJ,\n isThenable,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n SEMANTIC_ATTRIBUTE_SENTRY_SOURCE,\n spanToJSON,\n} from '@sentry/core';\nimport type { DataRouter } from 'react-router';\nimport { DEBUG_BUILD } from '../common/debug-build';\nimport { isClientInstrumentationApiUsed } from './createClientInstrumentation';\nimport {\n finalizeNavigationSpanFromRouterState,\n getParameterizedRoute,\n normalizePathname,\n resolveNavigateAbsoluteUrl,\n resolveNavigateArg,\n} from './utils';\nimport { URL_PATH, URL_TEMPLATE } from '@sentry/conventions/attributes';\n\nconst GLOBAL_OBJ_WITH_DATA_ROUTER = GLOBAL_OBJ as typeof GLOBAL_OBJ & {\n __reactRouterDataRouter?: DataRouter;\n};\n\nconst WINDOW = GLOBAL_OBJ as typeof GLOBAL_OBJ & Window;\n\nconst MAX_RETRIES = 40; // 2 seconds at 50ms interval\n\n/**\n * Instruments the React Router Data Router for pageloads and navigation.\n *\n * This function waits for the router to be available after hydration, then:\n * 1. Updates the pageload transaction with parameterized route info\n * 2. Patches router.navigate() to create navigation transactions\n * 3. Subscribes to router state changes to update navigation transactions with parameterized routes\n */\nexport function instrumentHydratedRouter(): void {\n function trySubscribe(): boolean {\n const router = GLOBAL_OBJ_WITH_DATA_ROUTER.__reactRouterDataRouter;\n\n if (router) {\n // The first time we hit the router, we try to update the pageload transaction\n const pageloadSpan = getActiveRootSpan();\n\n if (pageloadSpan) {\n const pageloadName = spanToJSON(pageloadSpan).description;\n const parameterizePageloadRoute = getParameterizedRoute(router.state);\n if (\n pageloadName &&\n // this event is for the currently active pageload\n normalizePathname(router.state.location.pathname) === normalizePathname(pageloadName)\n ) {\n pageloadSpan.updateName(parameterizePageloadRoute);\n pageloadSpan.setAttributes({\n [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'route',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.pageload.react_router',\n [URL_TEMPLATE]: parameterizePageloadRoute,\n });\n }\n }\n\n // Patching navigate for creating accurate navigation transactions\n if (typeof router.navigate === 'function') {\n const originalNav = router.navigate.bind(router);\n router.navigate = function sentryPatchedNavigate(...args) {\n // Skip if instrumentation API is enabled (it handles navigation spans itself)\n if (!isClientInstrumentationApiUsed()) {\n const target = args[0];\n\n if (typeof target === 'number') {\n // navigate(0) triggers a reload, not a route change — skip span creation\n if (target !== 0) {\n const currentPathname = WINDOW.location?.pathname || '/';\n const navigationSpan = maybeCreateNavigationTransaction(\n currentPathname,\n getAbsoluteUrl(currentPathname),\n 'url',\n );\n\n const result = originalNav(...args);\n\n // Numeric navigations (`navigate(-1)`/`navigate(1)`) don't carry a destination\n // path, so we can only resolve the real URL/route once the router has settled.\n if (navigationSpan) {\n // Finalize from the (updated) router state after navigation completes, in both\n // the resolve and reject paths, so a rejected navigation still ends up with the\n // correct URL attributes instead of the placeholder start pathname.\n if (isThenable(result)) {\n result.then(\n () => finalizeNavigationSpanFromRouterState(navigationSpan, router.state),\n () => finalizeNavigationSpanFromRouterState(navigationSpan, router.state),\n );\n } else {\n finalizeNavigationSpanFromRouterState(navigationSpan, router.state);\n }\n }\n\n return result;\n }\n } else {\n maybeCreateNavigationTransaction(\n resolveNavigateArg(target) || '<unknown route>',\n resolveNavigateAbsoluteUrl(target),\n 'url',\n );\n }\n }\n return originalNav(...args);\n };\n }\n\n // Subscribe to router state changes to update navigation transactions (and any pageload\n // whose route info only became available after `trySubscribe`, e.g. lazy routes) with the\n // parameterized route.\n router.subscribe(newState => {\n const rootSpan = getActiveRootSpan();\n\n if (!rootSpan) {\n return;\n }\n\n const rootSpanJson = spanToJSON(rootSpan);\n\n // When the instrumentation API is active, navigation roots are parameterized\n // by the native route hooks\n if (\n rootSpanJson.op === 'navigation' &&\n isClientInstrumentationApiUsed() &&\n rootSpanJson.data?.[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE] === 'route'\n ) {\n return;\n }\n\n const rootSpanName = rootSpanJson.description;\n const parameterizedRoute = getParameterizedRoute(newState);\n const spanPathname = rootSpanJson.data?.[URL_PATH] as string | undefined;\n const destinationPathname = normalizePathname(newState.location.pathname);\n\n if (\n rootSpanName &&\n newState.navigation.state === 'idle' && // navigation has completed\n // this event is for the currently active root span\n (destinationPathname === normalizePathname(rootSpanName) ||\n (spanPathname && destinationPathname === normalizePathname(spanPathname)))\n ) {\n rootSpan.updateName(parameterizedRoute);\n rootSpan.setAttributes({\n [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'route',\n [URL_TEMPLATE]: parameterizedRoute,\n });\n }\n });\n return true;\n }\n return false;\n }\n\n // Wait until the router is available (since the SDK loads before hydration)\n if (!trySubscribe()) {\n let retryCount = 0;\n // Retry until the router is available or max retries reached\n const interval = setInterval(() => {\n if (trySubscribe() || retryCount >= MAX_RETRIES) {\n if (retryCount >= MAX_RETRIES) {\n DEBUG_BUILD && debug.warn('Unable to instrument React Router: router not found after hydration.');\n }\n clearInterval(interval);\n }\n retryCount++;\n }, 50);\n }\n}\n\nfunction maybeCreateNavigationTransaction(name: string, url: string, source: 'url' | 'route'): Span | undefined {\n const client = getClient();\n\n if (!client) {\n return undefined;\n }\n\n return startBrowserTracingNavigationSpan(\n client,\n {\n name,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: source,\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'navigation',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.navigation.react_router',\n ...(source === 'route' ? { [URL_TEMPLATE]: name } : {}),\n },\n },\n { url },\n );\n}\n\nfunction getActiveRootSpan(): Span | undefined {\n const activeSpan = getActiveSpan();\n if (!activeSpan) {\n return undefined;\n }\n\n const rootSpan = getRootSpan(activeSpan);\n\n const op = spanToJSON(rootSpan).op;\n\n // Only use this root span if it is a pageload or navigation span\n return op === 'navigation' || op === 'pageload' ? rootSpan : undefined;\n}\n"],"names":["GLOBAL_OBJ","spanToJSON","getParameterizedRoute","normalizePathname","SEMANTIC_ATTRIBUTE_SENTRY_SOURCE","SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN","URL_TEMPLATE","isClientInstrumentationApiUsed","getAbsoluteUrl","isThenable","finalizeNavigationSpanFromRouterState","resolveNavigateArg","resolveNavigateAbsoluteUrl","URL_PATH","DEBUG_BUILD","debug","getClient","startBrowserTracingNavigationSpan","SEMANTIC_ATTRIBUTE_SENTRY_OP","getActiveSpan","getRootSpan"],"mappings":"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"}
|
|
@@ -17,6 +17,7 @@ function reactRouterTracingIntegration(options = {}) {
|
|
|
17
17
|
browserTracingIntegrationInstance.afterAllSetup(client);
|
|
18
18
|
hydratedRouter.instrumentHydratedRouter();
|
|
19
19
|
},
|
|
20
|
+
// oxlint-disable-next-line typescript/no-deprecated -- exposes the deprecated getter for back-compat until it is removed
|
|
20
21
|
get clientInstrumentation() {
|
|
21
22
|
return clientInstrumentationInstance;
|
|
22
23
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tracingIntegration.js","sources":["../../../src/client/tracingIntegration.ts"],"sourcesContent":["import { browserTracingIntegration as originalBrowserTracingIntegration } from '@sentry/browser';\nimport type { Integration } from '@sentry/core';\nimport type { ClientInstrumentation } from '../common/types';\nimport {\n createSentryClientInstrumentation,\n type CreateSentryClientInstrumentationOptions,\n} from './createClientInstrumentation';\nimport { instrumentHydratedRouter } from './hydratedRouter';\n\n/**\n * Options for the React Router tracing integration.\n */\nexport interface ReactRouterTracingIntegrationOptions {\n /**\n * Options for React Router's instrumentation API.\n */\n instrumentationOptions?: CreateSentryClientInstrumentationOptions;\n\n /** @deprecated `clientInstrumentation` is always built, so this flag is a no-op. Will be removed in a future major. */\n useInstrumentationAPI?: boolean;\n}\n\n/**\n * React Router tracing integration with support for the instrumentation API.\n */\nexport interface ReactRouterTracingIntegration extends Integration {\n /**\n * Client instrumentation to pass to `HydratedRouter`'s `instrumentations` prop.\n *\n * @deprecated Use the standalone `createSentryClientInstrumentation()` export instead and pass its\n * result to `HydratedRouter`'s `instrumentations` prop. This mirrors the server-side\n * `createSentryServerInstrumentation()` API. Will be removed in a future major.\n */\n readonly clientInstrumentation: ClientInstrumentation;\n}\n\n/**\n * Browser tracing integration for React Router (Framework) applications.\n * This integration will create navigation spans and enhance transaction names with parameterized routes.\n */\nexport function reactRouterTracingIntegration(\n options: ReactRouterTracingIntegrationOptions = {},\n): ReactRouterTracingIntegration {\n const browserTracingIntegrationInstance = originalBrowserTracingIntegration({\n // Navigation transactions are started within the hydrated router instrumentation\n instrumentNavigation: false,\n });\n\n // Built eagerly so it can be passed to HydratedRouter's `instrumentations` prop. This has no\n // side effects - the API is only marked \"used\" once React Router invokes the `router()` hook.\n const clientInstrumentationInstance = createSentryClientInstrumentation(options.instrumentationOptions);\n\n return {\n ...browserTracingIntegrationInstance,\n name: 'ReactRouterTracingIntegration',\n afterAllSetup(client) {\n browserTracingIntegrationInstance.afterAllSetup(client);\n instrumentHydratedRouter();\n },\n get clientInstrumentation(): ClientInstrumentation {\n return clientInstrumentationInstance;\n },\n };\n}\n"],"names":["originalBrowserTracingIntegration","createSentryClientInstrumentation","instrumentHydratedRouter"],"mappings":";;;;;;AAwCO,SAAS,6BAAA,CACd,OAAA,GAAgD,EAAC,EAClB;AAC/B,EAAA,MAAM,oCAAoCA,iCAAA,CAAkC;AAAA;AAAA,IAE1E,oBAAA,EAAsB;AAAA,GACvB,CAAA;AAID,EAAA,MAAM,6BAAA,GAAgCC,6DAAA,CAAkC,OAAA,CAAQ,sBAAsB,CAAA;AAEtG,EAAA,OAAO;AAAA,IACL,GAAG,iCAAA;AAAA,IACH,IAAA,EAAM,+BAAA;AAAA,IACN,cAAc,MAAA,EAAQ;AACpB,MAAA,iCAAA,CAAkC,cAAc,MAAM,CAAA;AACtD,MAAAC,uCAAA,EAAyB;AAAA,IAC3B,CAAA;AAAA,
|
|
1
|
+
{"version":3,"file":"tracingIntegration.js","sources":["../../../src/client/tracingIntegration.ts"],"sourcesContent":["import { browserTracingIntegration as originalBrowserTracingIntegration } from '@sentry/browser';\nimport type { Integration } from '@sentry/core';\nimport type { ClientInstrumentation } from '../common/types';\nimport {\n createSentryClientInstrumentation,\n type CreateSentryClientInstrumentationOptions,\n} from './createClientInstrumentation';\nimport { instrumentHydratedRouter } from './hydratedRouter';\n\n/**\n * Options for the React Router tracing integration.\n */\nexport interface ReactRouterTracingIntegrationOptions {\n /**\n * Options for React Router's instrumentation API.\n */\n instrumentationOptions?: CreateSentryClientInstrumentationOptions;\n\n /** @deprecated `clientInstrumentation` is always built, so this flag is a no-op. Will be removed in a future major. */\n useInstrumentationAPI?: boolean;\n}\n\n/**\n * React Router tracing integration with support for the instrumentation API.\n */\nexport interface ReactRouterTracingIntegration extends Integration {\n /**\n * Client instrumentation to pass to `HydratedRouter`'s `instrumentations` prop.\n *\n * @deprecated Use the standalone `createSentryClientInstrumentation()` export instead and pass its\n * result to `HydratedRouter`'s `instrumentations` prop. This mirrors the server-side\n * `createSentryServerInstrumentation()` API. Will be removed in a future major.\n */\n readonly clientInstrumentation: ClientInstrumentation;\n}\n\n/**\n * Browser tracing integration for React Router (Framework) applications.\n * This integration will create navigation spans and enhance transaction names with parameterized routes.\n */\nexport function reactRouterTracingIntegration(\n options: ReactRouterTracingIntegrationOptions = {},\n): ReactRouterTracingIntegration {\n const browserTracingIntegrationInstance = originalBrowserTracingIntegration({\n // Navigation transactions are started within the hydrated router instrumentation\n instrumentNavigation: false,\n });\n\n // Built eagerly so it can be passed to HydratedRouter's `instrumentations` prop. This has no\n // side effects - the API is only marked \"used\" once React Router invokes the `router()` hook.\n const clientInstrumentationInstance = createSentryClientInstrumentation(options.instrumentationOptions);\n\n return {\n ...browserTracingIntegrationInstance,\n name: 'ReactRouterTracingIntegration',\n afterAllSetup(client) {\n browserTracingIntegrationInstance.afterAllSetup(client);\n instrumentHydratedRouter();\n },\n // oxlint-disable-next-line typescript/no-deprecated -- exposes the deprecated getter for back-compat until it is removed\n get clientInstrumentation(): ClientInstrumentation {\n return clientInstrumentationInstance;\n },\n };\n}\n"],"names":["originalBrowserTracingIntegration","createSentryClientInstrumentation","instrumentHydratedRouter"],"mappings":";;;;;;AAwCO,SAAS,6BAAA,CACd,OAAA,GAAgD,EAAC,EAClB;AAC/B,EAAA,MAAM,oCAAoCA,iCAAA,CAAkC;AAAA;AAAA,IAE1E,oBAAA,EAAsB;AAAA,GACvB,CAAA;AAID,EAAA,MAAM,6BAAA,GAAgCC,6DAAA,CAAkC,OAAA,CAAQ,sBAAsB,CAAA;AAEtG,EAAA,OAAO;AAAA,IACL,GAAG,iCAAA;AAAA,IACH,IAAA,EAAM,+BAAA;AAAA,IACN,cAAc,MAAA,EAAQ;AACpB,MAAA,iCAAA,CAAkC,cAAc,MAAM,CAAA;AACtD,MAAAC,uCAAA,EAAyB;AAAA,IAC3B,CAAA;AAAA;AAAA,IAEA,IAAI,qBAAA,GAA+C;AACjD,MAAA,OAAO,6BAAA;AAAA,IACT;AAAA,GACF;AACF;;;;"}
|
|
@@ -55,8 +55,9 @@ function updateNavigationSpanUrlFromLocation(span) {
|
|
|
55
55
|
const destinationUrl = browser.getAbsoluteUrl(`${pathname}${search}${hash}`);
|
|
56
56
|
span.updateName(pathname);
|
|
57
57
|
span.setAttributes({
|
|
58
|
+
[core.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: "url",
|
|
58
59
|
[attributes.URL_PATH]: pathname,
|
|
59
|
-
[attributes.URL_FULL]: destinationUrl
|
|
60
|
+
[attributes.URL_FULL]: core.filterCollectedUrl(destinationUrl)
|
|
60
61
|
});
|
|
61
62
|
}
|
|
62
63
|
function normalizePathname(pathname) {
|
|
@@ -79,7 +80,10 @@ function finalizeNavigationSpanFromRouterState(span, routerState) {
|
|
|
79
80
|
if (routerState.navigation?.state === "idle" && normalizePathname(routerState.location.pathname) === normalizePathname(pathname)) {
|
|
80
81
|
const parameterizedRoute = getParameterizedRoute(routerState);
|
|
81
82
|
span.updateName(parameterizedRoute);
|
|
82
|
-
span.setAttributes({
|
|
83
|
+
span.setAttributes({
|
|
84
|
+
[core.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: "route",
|
|
85
|
+
[attributes.URL_TEMPLATE]: parameterizedRoute
|
|
86
|
+
});
|
|
83
87
|
}
|
|
84
88
|
}
|
|
85
89
|
function finalizeNavigationSpanFromHydratedRouter(span) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","sources":["../../../src/client/utils.ts"],"sourcesContent":["import { getAbsoluteUrl } from '@sentry/browser';\nimport type { Span } from '@sentry/core';\nimport { GLOBAL_OBJ, SEMANTIC_ATTRIBUTE_SENTRY_SOURCE } from '@sentry/core';\nimport { URL_FULL, URL_PATH, URL_TEMPLATE } from '@sentry/conventions/attributes';\nimport type { DataRouter, RouterState } from 'react-router';\n\nconst WINDOW = GLOBAL_OBJ as typeof GLOBAL_OBJ & Window;\n\nconst GLOBAL_OBJ_WITH_DATA_ROUTER = GLOBAL_OBJ as typeof GLOBAL_OBJ & {\n __reactRouterDataRouter?: DataRouter;\n};\n\n/**\n * Resolves a navigate argument to a pathname string.\n *\n * React Router's navigate() accepts a string, number, or a To object ({ pathname, search, hash }).\n * All fields in the To object are optional (Partial<Path>), so we need to detect object args\n * to avoid \"[object Object]\" transaction names.\n */\nexport function resolveNavigateArg(target: unknown): string {\n if (typeof target !== 'object' || target === null) {\n // string or number\n return String(target);\n }\n\n // Object `to` with pathname\n const pathname = (target as Record<string, unknown>).pathname;\n if (typeof pathname === 'string') {\n return pathname || '/';\n }\n\n // Object `to` without pathname - navigation stays on current path\n return WINDOW.location?.pathname || '/';\n}\n\n/**\n * Resolves a navigate argument to the full destination path, preserving `search`/`hash` from a\n * To object. Unlike `resolveNavigateArg` (used for span/route naming, which should stay a bare\n * path), this is used to derive `url.full`/`url.path`, which should reflect the actual\n * destination the user is navigating to, including any query string.\n */\nexport function resolveNavigateUrl(target: unknown): string {\n if (typeof target !== 'object' || target === null) {\n // string or number\n return String(target);\n }\n\n const { pathname, search, hash } = target as Record<string, unknown>;\n const path = typeof pathname === 'string' && pathname !== '' ? pathname : WINDOW.location?.pathname || '/';\n\n return `${path}${typeof search === 'string' ? search : ''}${typeof hash === 'string' ? hash : ''}`;\n}\n\nfunction getNavigateBaseUrl(currentUrl?: string): string {\n const origin = WINDOW.location?.origin || 'http://localhost';\n\n // Prefer the live pathname, but fall back to the hook-provided `currentUrl` (which may be a full\n // URL or a bare path) when `location` is unavailable (e.g. SSR/non-browser environments).\n let pathname = WINDOW.location?.pathname;\n if (!pathname && currentUrl) {\n try {\n pathname = new URL(currentUrl, origin).pathname;\n } catch {\n pathname = currentUrl.startsWith('/') ? currentUrl : `/${currentUrl}`;\n }\n }\n pathname = pathname || '/';\n\n // React Router resolves relative navigate targets against the current path treated as a\n // *directory* (it appends segments), whereas the WHATWG `URL` parser treats the last path\n // segment as a file and drops it. Enforce a trailing slash so relative resolution matches\n // React Router, e.g. `navigate('ssr')` from `/performance` -> `/performance/ssr` (not `/ssr`).\n const directory = pathname.endsWith('/') ? pathname : `${pathname}/`;\n\n return `${origin}${directory}`;\n}\n\n/**\n * Resolves a navigate argument to an absolute URL for `url.full`/`url.path`, correctly handling\n * relative targets (no leading slash) by resolving them against the current URL instead of the\n * document origin alone.\n */\nexport function resolveNavigateAbsoluteUrl(target: unknown, currentUrl?: string): string {\n const destination = resolveNavigateUrl(target);\n\n try {\n const resolved = new URL(destination, getNavigateBaseUrl(currentUrl));\n return getAbsoluteUrl(`${resolved.pathname}${resolved.search}${resolved.hash}`);\n } catch {\n return getAbsoluteUrl(destination);\n }\n}\n\n/**\n * Updates a navigation span's name and `url.path`/`url.full` from the current `location`.\n */\nexport function updateNavigationSpanUrlFromLocation(span: Span): void {\n if (!WINDOW.location) {\n return;\n }\n\n const { pathname, search = '', hash = '' } = WINDOW.location;\n const destinationUrl = getAbsoluteUrl(`${pathname}${search}${hash}`);\n\n span.updateName(pathname);\n span.setAttributes({\n [URL_PATH]: pathname,\n [URL_FULL]: destinationUrl,\n });\n}\n\nexport function normalizePathname(pathname: string): string {\n let normalized = pathname.startsWith('/') ? pathname : `/${pathname}`;\n if (normalized.length > 1 && normalized.endsWith('/')) {\n normalized = normalized.slice(0, -1);\n }\n return normalized;\n}\n\nexport function getParameterizedRoute(routerState: RouterState): string {\n const lastMatch = routerState.matches[routerState.matches.length - 1];\n return normalizePathname(lastMatch?.route.path || routerState.location.pathname);\n}\n\n/**\n * Updates a navigation span's URL attributes and parameterizes its name from the router state.\n * Used after numeric navigations (`navigate(-1)` / `navigate(1)`) where route hooks may not\n * supply a pattern (e.g. index routes).\n *\n * `url.path` reflects raw `location.pathname` (may include a trailing slash when the server\n * redirects index routes), while `url.template` is normalized without trailing slashes.\n */\nexport function finalizeNavigationSpanFromRouterState(span: Span, routerState: RouterState): void {\n updateNavigationSpanUrlFromLocation(span);\n\n if (!WINDOW.location) {\n return;\n }\n\n const { pathname } = WINDOW.location;\n\n if (\n routerState.navigation?.state === 'idle' &&\n normalizePathname(routerState.location.pathname) === normalizePathname(pathname)\n ) {\n const parameterizedRoute = getParameterizedRoute(routerState);\n span.updateName(parameterizedRoute);\n span.setAttributes({ [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'route', [URL_TEMPLATE]: parameterizedRoute });\n }\n}\n\n/**\n * Finalizes a navigation span after numeric navigation using the hydrated data router when\n * available, otherwise falls back to URL attributes from `location` alone.\n */\nexport function finalizeNavigationSpanFromHydratedRouter(span: Span): void {\n const router = GLOBAL_OBJ_WITH_DATA_ROUTER.__reactRouterDataRouter;\n if (router) {\n finalizeNavigationSpanFromRouterState(span, router.state);\n } else {\n updateNavigationSpanUrlFromLocation(span);\n }\n}\n"],"names":["GLOBAL_OBJ","getAbsoluteUrl","URL_PATH","URL_FULL","SEMANTIC_ATTRIBUTE_SENTRY_SOURCE","URL_TEMPLATE"],"mappings":";;;;;;AAMA,MAAM,MAAA,GAASA,eAAA;AAEf,MAAM,2BAAA,GAA8BA,eAAA;AAW7B,SAAS,mBAAmB,MAAA,EAAyB;AAC1D,EAAA,IAAI,OAAO,MAAA,KAAW,QAAA,IAAY,MAAA,KAAW,IAAA,EAAM;AAEjD,IAAA,OAAO,OAAO,MAAM,CAAA;AAAA,EACtB;AAGA,EAAA,MAAM,WAAY,MAAA,CAAmC,QAAA;AACrD,EAAA,IAAI,OAAO,aAAa,QAAA,EAAU;AAChC,IAAA,OAAO,QAAA,IAAY,GAAA;AAAA,EACrB;AAGA,EAAA,OAAO,MAAA,CAAO,UAAU,QAAA,IAAY,GAAA;AACtC;AAQO,SAAS,mBAAmB,MAAA,EAAyB;AAC1D,EAAA,IAAI,OAAO,MAAA,KAAW,QAAA,IAAY,MAAA,KAAW,IAAA,EAAM;AAEjD,IAAA,OAAO,OAAO,MAAM,CAAA;AAAA,EACtB;AAEA,EAAA,MAAM,EAAE,QAAA,EAAU,MAAA,EAAQ,IAAA,EAAK,GAAI,MAAA;AACnC,EAAA,MAAM,IAAA,GAAO,OAAO,QAAA,KAAa,QAAA,IAAY,aAAa,EAAA,GAAK,QAAA,GAAW,MAAA,CAAO,QAAA,EAAU,QAAA,IAAY,GAAA;AAEvG,EAAA,OAAO,CAAA,EAAG,IAAI,CAAA,EAAG,OAAO,MAAA,KAAW,QAAA,GAAW,MAAA,GAAS,EAAE,CAAA,EAAG,OAAO,IAAA,KAAS,QAAA,GAAW,OAAO,EAAE,CAAA,CAAA;AAClG;AAEA,SAAS,mBAAmB,UAAA,EAA6B;AACvD,EAAA,MAAM,MAAA,GAAS,MAAA,CAAO,QAAA,EAAU,MAAA,IAAU,kBAAA;AAI1C,EAAA,IAAI,QAAA,GAAW,OAAO,QAAA,EAAU,QAAA;AAChC,EAAA,IAAI,CAAC,YAAY,UAAA,EAAY;AAC3B,IAAA,IAAI;AACF,MAAA,QAAA,GAAW,IAAI,GAAA,CAAI,UAAA,EAAY,MAAM,CAAA,CAAE,QAAA;AAAA,IACzC,CAAA,CAAA,MAAQ;AACN,MAAA,QAAA,GAAW,WAAW,UAAA,CAAW,GAAG,CAAA,GAAI,UAAA,GAAa,IAAI,UAAU,CAAA,CAAA;AAAA,IACrE;AAAA,EACF;AACA,EAAA,QAAA,GAAW,QAAA,IAAY,GAAA;AAMvB,EAAA,MAAM,YAAY,QAAA,CAAS,QAAA,CAAS,GAAG,CAAA,GAAI,QAAA,GAAW,GAAG,QAAQ,CAAA,CAAA,CAAA;AAEjE,EAAA,OAAO,CAAA,EAAG,MAAM,CAAA,EAAG,SAAS,CAAA,CAAA;AAC9B;AAOO,SAAS,0BAAA,CAA2B,QAAiB,UAAA,EAA6B;AACvF,EAAA,MAAM,WAAA,GAAc,mBAAmB,MAAM,CAAA;AAE7C,EAAA,IAAI;AACF,IAAA,MAAM,WAAW,IAAI,GAAA,CAAI,WAAA,EAAa,kBAAA,CAAmB,UAAU,CAAC,CAAA;AACpE,IAAA,OAAOC,sBAAA,CAAe,CAAA,EAAG,QAAA,CAAS,QAAQ,CAAA,EAAG,SAAS,MAAM,CAAA,EAAG,QAAA,CAAS,IAAI,CAAA,CAAE,CAAA;AAAA,EAChF,CAAA,CAAA,MAAQ;AACN,IAAA,OAAOA,uBAAe,WAAW,CAAA;AAAA,EACnC;AACF;AAKO,SAAS,oCAAoC,IAAA,EAAkB;AACpE,EAAA,IAAI,CAAC,OAAO,QAAA,EAAU;AACpB,IAAA;AAAA,EACF;AAEA,EAAA,MAAM,EAAE,QAAA,EAAU,MAAA,GAAS,IAAI,IAAA,GAAO,EAAA,KAAO,MAAA,CAAO,QAAA;AACpD,EAAA,MAAM,cAAA,GAAiBA,uBAAe,CAAA,EAAG,QAAQ,GAAG,MAAM,CAAA,EAAG,IAAI,CAAA,CAAE,CAAA;AAEnE,EAAA,IAAA,CAAK,WAAW,QAAQ,CAAA;AACxB,EAAA,IAAA,CAAK,aAAA,CAAc;AAAA,IACjB,CAACC,mBAAQ,GAAG,QAAA;AAAA,IACZ,CAACC,mBAAQ,GAAG;AAAA,GACb,CAAA;AACH;AAEO,SAAS,kBAAkB,QAAA,EAA0B;AAC1D,EAAA,IAAI,aAAa,QAAA,CAAS,UAAA,CAAW,GAAG,CAAA,GAAI,QAAA,GAAW,IAAI,QAAQ,CAAA,CAAA;AACnE,EAAA,IAAI,WAAW,MAAA,GAAS,CAAA,IAAK,UAAA,CAAW,QAAA,CAAS,GAAG,CAAA,EAAG;AACrD,IAAA,UAAA,GAAa,UAAA,CAAW,KAAA,CAAM,CAAA,EAAG,EAAE,CAAA;AAAA,EACrC;AACA,EAAA,OAAO,UAAA;AACT;AAEO,SAAS,sBAAsB,WAAA,EAAkC;AACtE,EAAA,MAAM,YAAY,WAAA,CAAY,OAAA,CAAQ,WAAA,CAAY,OAAA,CAAQ,SAAS,CAAC,CAAA;AACpE,EAAA,OAAO,kBAAkB,SAAA,EAAW,KAAA,CAAM,IAAA,IAAQ,WAAA,CAAY,SAAS,QAAQ,CAAA;AACjF;AAUO,SAAS,qCAAA,CAAsC,MAAY,WAAA,EAAgC;AAChG,EAAA,mCAAA,CAAoC,IAAI,CAAA;AAExC,EAAA,IAAI,CAAC,OAAO,QAAA,EAAU;AACpB,IAAA;AAAA,EACF;AAEA,EAAA,MAAM,EAAE,QAAA,EAAS,GAAI,MAAA,CAAO,QAAA;AAE5B,EAAA,IACE,WAAA,CAAY,UAAA,EAAY,KAAA,KAAU,MAAA,IAClC,iBAAA,CAAkB,WAAA,CAAY,QAAA,CAAS,QAAQ,CAAA,KAAM,iBAAA,CAAkB,QAAQ,CAAA,EAC/E;AACA,IAAA,MAAM,kBAAA,GAAqB,sBAAsB,WAAW,CAAA;AAC5D,IAAA,IAAA,CAAK,WAAW,kBAAkB,CAAA;AAClC,IAAA,IAAA,CAAK,aAAA,CAAc,EAAE,CAACC,qCAAgC,GAAG,SAAS,CAACC,uBAAY,GAAG,kBAAA,EAAoB,CAAA;AAAA,EACxG;AACF;AAMO,SAAS,yCAAyC,IAAA,EAAkB;AACzE,EAAA,MAAM,SAAS,2BAAA,CAA4B,uBAAA;AAC3C,EAAA,IAAI,MAAA,EAAQ;AACV,IAAA,qCAAA,CAAsC,IAAA,EAAM,OAAO,KAAK,CAAA;AAAA,EAC1D,CAAA,MAAO;AACL,IAAA,mCAAA,CAAoC,IAAI,CAAA;AAAA,EAC1C;AACF;;;;;;;;;;;"}
|
|
1
|
+
{"version":3,"file":"utils.js","sources":["../../../src/client/utils.ts"],"sourcesContent":["import { getAbsoluteUrl } from '@sentry/browser';\nimport type { Span } from '@sentry/core';\nimport { GLOBAL_OBJ, SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, filterCollectedUrl } from '@sentry/core';\nimport { URL_FULL, URL_PATH, URL_TEMPLATE } from '@sentry/conventions/attributes';\nimport type { DataRouter, RouterState } from 'react-router';\n\nconst WINDOW = GLOBAL_OBJ as typeof GLOBAL_OBJ & Window;\n\nconst GLOBAL_OBJ_WITH_DATA_ROUTER = GLOBAL_OBJ as typeof GLOBAL_OBJ & {\n __reactRouterDataRouter?: DataRouter;\n};\n\n/**\n * Resolves a navigate argument to a pathname string.\n *\n * React Router's navigate() accepts a string, number, or a To object ({ pathname, search, hash }).\n * All fields in the To object are optional (Partial<Path>), so we need to detect object args\n * to avoid \"[object Object]\" transaction names.\n */\nexport function resolveNavigateArg(target: unknown): string {\n if (typeof target !== 'object' || target === null) {\n // string or number\n return String(target);\n }\n\n // Object `to` with pathname\n const pathname = (target as Record<string, unknown>).pathname;\n if (typeof pathname === 'string') {\n return pathname || '/';\n }\n\n // Object `to` without pathname - navigation stays on current path\n return WINDOW.location?.pathname || '/';\n}\n\n/**\n * Resolves a navigate argument to the full destination path, preserving `search`/`hash` from a\n * To object. Unlike `resolveNavigateArg` (used for span/route naming, which should stay a bare\n * path), this is used to derive `url.full`/`url.path`, which should reflect the actual\n * destination the user is navigating to, including any query string.\n */\nexport function resolveNavigateUrl(target: unknown): string {\n if (typeof target !== 'object' || target === null) {\n // string or number\n return String(target);\n }\n\n const { pathname, search, hash } = target as Record<string, unknown>;\n const path = typeof pathname === 'string' && pathname !== '' ? pathname : WINDOW.location?.pathname || '/';\n\n return `${path}${typeof search === 'string' ? search : ''}${typeof hash === 'string' ? hash : ''}`;\n}\n\nfunction getNavigateBaseUrl(currentUrl?: string): string {\n const origin = WINDOW.location?.origin || 'http://localhost';\n\n // Prefer the live pathname, but fall back to the hook-provided `currentUrl` (which may be a full\n // URL or a bare path) when `location` is unavailable (e.g. SSR/non-browser environments).\n let pathname = WINDOW.location?.pathname;\n if (!pathname && currentUrl) {\n try {\n pathname = new URL(currentUrl, origin).pathname;\n } catch {\n pathname = currentUrl.startsWith('/') ? currentUrl : `/${currentUrl}`;\n }\n }\n pathname = pathname || '/';\n\n // React Router resolves relative navigate targets against the current path treated as a\n // *directory* (it appends segments), whereas the WHATWG `URL` parser treats the last path\n // segment as a file and drops it. Enforce a trailing slash so relative resolution matches\n // React Router, e.g. `navigate('ssr')` from `/performance` -> `/performance/ssr` (not `/ssr`).\n const directory = pathname.endsWith('/') ? pathname : `${pathname}/`;\n\n return `${origin}${directory}`;\n}\n\n/**\n * Resolves a navigate argument to an absolute URL for `url.full`/`url.path`, correctly handling\n * relative targets (no leading slash) by resolving them against the current URL instead of the\n * document origin alone.\n */\nexport function resolveNavigateAbsoluteUrl(target: unknown, currentUrl?: string): string {\n const destination = resolveNavigateUrl(target);\n\n try {\n const resolved = new URL(destination, getNavigateBaseUrl(currentUrl));\n return getAbsoluteUrl(`${resolved.pathname}${resolved.search}${resolved.hash}`);\n } catch {\n return getAbsoluteUrl(destination);\n }\n}\n\n/**\n * Updates a navigation span's name and `url.path`/`url.full` from the current `location`.\n */\nexport function updateNavigationSpanUrlFromLocation(span: Span): void {\n if (!WINDOW.location) {\n return;\n }\n\n const { pathname, search = '', hash = '' } = WINDOW.location;\n const destinationUrl = getAbsoluteUrl(`${pathname}${search}${hash}`);\n\n span.updateName(pathname);\n span.setAttributes({\n [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'url',\n [URL_PATH]: pathname,\n [URL_FULL]: filterCollectedUrl(destinationUrl),\n });\n}\n\nexport function normalizePathname(pathname: string): string {\n let normalized = pathname.startsWith('/') ? pathname : `/${pathname}`;\n if (normalized.length > 1 && normalized.endsWith('/')) {\n normalized = normalized.slice(0, -1);\n }\n return normalized;\n}\n\nexport function getParameterizedRoute(routerState: RouterState): string {\n const lastMatch = routerState.matches[routerState.matches.length - 1];\n return normalizePathname(lastMatch?.route.path || routerState.location.pathname);\n}\n\n/**\n * Updates a navigation span's URL attributes and parameterizes its name from the router state.\n * Used after numeric navigations (`navigate(-1)` / `navigate(1)`) where route hooks may not\n * supply a pattern (e.g. index routes).\n *\n * `url.path` reflects raw `location.pathname` (may include a trailing slash when the server\n * redirects index routes), while `url.template` is normalized without trailing slashes.\n */\nexport function finalizeNavigationSpanFromRouterState(span: Span, routerState: RouterState): void {\n updateNavigationSpanUrlFromLocation(span);\n\n if (!WINDOW.location) {\n return;\n }\n\n const { pathname } = WINDOW.location;\n\n if (\n routerState.navigation?.state === 'idle' &&\n normalizePathname(routerState.location.pathname) === normalizePathname(pathname)\n ) {\n const parameterizedRoute = getParameterizedRoute(routerState);\n span.updateName(parameterizedRoute);\n span.setAttributes({\n [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'route',\n [URL_TEMPLATE]: parameterizedRoute,\n });\n }\n}\n\n/**\n * Finalizes a navigation span after numeric navigation using the hydrated data router when\n * available, otherwise falls back to URL attributes from `location` alone.\n */\nexport function finalizeNavigationSpanFromHydratedRouter(span: Span): void {\n const router = GLOBAL_OBJ_WITH_DATA_ROUTER.__reactRouterDataRouter;\n if (router) {\n finalizeNavigationSpanFromRouterState(span, router.state);\n } else {\n updateNavigationSpanUrlFromLocation(span);\n }\n}\n"],"names":["GLOBAL_OBJ","getAbsoluteUrl","SEMANTIC_ATTRIBUTE_SENTRY_SOURCE","URL_PATH","URL_FULL","filterCollectedUrl","URL_TEMPLATE"],"mappings":"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"}
|
|
@@ -4,8 +4,6 @@ const node = require('@sentry/node');
|
|
|
4
4
|
const sdk = require('./server/sdk.js');
|
|
5
5
|
const wrapSentryHandleRequest = require('./server/wrapSentryHandleRequest.js');
|
|
6
6
|
const createSentryHandleRequest = require('./server/createSentryHandleRequest.js');
|
|
7
|
-
const wrapServerAction = require('./server/wrapServerAction.js');
|
|
8
|
-
const wrapServerLoader = require('./server/wrapServerLoader.js');
|
|
9
7
|
const createSentryHandleError = require('./server/createSentryHandleError.js');
|
|
10
8
|
const getMetaTagTransformer = require('./server/getMetaTagTransformer.js');
|
|
11
9
|
const createServerInstrumentation = require('./server/createServerInstrumentation.js');
|
|
@@ -20,8 +18,6 @@ exports.init = sdk.init;
|
|
|
20
18
|
exports.sentryHandleRequest = wrapSentryHandleRequest.sentryHandleRequest;
|
|
21
19
|
exports.wrapSentryHandleRequest = wrapSentryHandleRequest.wrapSentryHandleRequest;
|
|
22
20
|
exports.createSentryHandleRequest = createSentryHandleRequest.createSentryHandleRequest;
|
|
23
|
-
exports.wrapServerAction = wrapServerAction.wrapServerAction;
|
|
24
|
-
exports.wrapServerLoader = wrapServerLoader.wrapServerLoader;
|
|
25
21
|
exports.createSentryHandleError = createSentryHandleError.createSentryHandleError;
|
|
26
22
|
exports.getMetaTagTransformer = getMetaTagTransformer.getMetaTagTransformer;
|
|
27
23
|
exports.createSentryServerInstrumentation = createServerInstrumentation.createSentryServerInstrumentation;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.server.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.server.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createSentryHandleRequest.js","sources":["../../../src/server/createSentryHandleRequest.tsx"],"sourcesContent":["import type { createReadableStreamFromReadable } from '@react-router/node';\nimport type { ReactNode } from 'react';\nimport React from 'react';\nimport type { AppLoadContext, EntryContext, RouterContextProvider, ServerRouter } from 'react-router';\nimport { PassThrough } from 'stream';\nimport { getMetaTagTransformer } from './getMetaTagTransformer';\nimport { wrapSentryHandleRequest } from './wrapSentryHandleRequest';\n\ntype RenderToPipeableStreamOptions = {\n [key: string]: unknown;\n onShellReady?: () => void;\n onAllReady?: () => void;\n onShellError?: (error: unknown) => void;\n onError?: (error: unknown) => void;\n};\n\ntype RenderToPipeableStreamResult = {\n pipe: (destination: NodeJS.WritableStream) => void;\n abort: () => void;\n};\n\ntype RenderToPipeableStreamFunction = (\n node: ReactNode,\n options: RenderToPipeableStreamOptions,\n) => RenderToPipeableStreamResult;\n\nexport interface SentryHandleRequestOptions {\n /**\n * Timeout in milliseconds after which the rendering stream will be aborted\n * @default 10000\n */\n streamTimeout?: number;\n\n /**\n * React's renderToPipeableStream function from 'react-dom/server'\n */\n renderToPipeableStream: RenderToPipeableStreamFunction;\n\n /**\n * The <ServerRouter /> component from '@react-router/server'\n */\n ServerRouter: typeof ServerRouter;\n\n /**\n * createReadableStreamFromReadable from '@react-router/node'\n */\n createReadableStreamFromReadable: typeof createReadableStreamFromReadable;\n\n /**\n * Regular expression to identify bot user agents\n * @default /bot|crawler|spider|googlebot|chrome-lighthouse|baidu|bing|google|yahoo|lighthouse/i\n */\n botRegex?: RegExp;\n}\n\ntype HandleRequestWithoutMiddleware = (\n request: Request,\n responseStatusCode: number,\n responseHeaders: Headers,\n routerContext: EntryContext,\n loadContext: AppLoadContext,\n) => Promise<unknown>;\n\ntype HandleRequestWithMiddleware = (\n request: Request,\n responseStatusCode: number,\n responseHeaders: Headers,\n routerContext: EntryContext,\n loadContext: RouterContextProvider,\n) => Promise<unknown>;\n\n/**\n * A complete Sentry-instrumented handleRequest implementation that handles both\n * route parametrization and trace meta tag injection.\n *\n * @param options Configuration options\n * @returns A Sentry-instrumented handleRequest function\n */\nexport function createSentryHandleRequest(\n options: SentryHandleRequestOptions,\n): HandleRequestWithoutMiddleware & HandleRequestWithMiddleware {\n const {\n streamTimeout = 10000,\n renderToPipeableStream,\n ServerRouter,\n createReadableStreamFromReadable,\n botRegex = /bot|crawler|spider|googlebot|chrome-lighthouse|baidu|bing|google|yahoo|lighthouse/i,\n } = options;\n\n const handleRequest = function handleRequest(\n request: Request,\n responseStatusCode: number,\n responseHeaders: Headers,\n routerContext: EntryContext,\n _loadContext: AppLoadContext | RouterContextProvider,\n ): Promise<Response> {\n return new Promise((resolve, reject) => {\n let shellRendered = false;\n const userAgent = request.headers.get('user-agent');\n\n // Determine if we should use onAllReady or onShellReady\n const isBot = typeof userAgent === 'string' && botRegex.test(userAgent);\n const isSpaMode = !!(routerContext as { isSpaMode?: boolean }).isSpaMode;\n\n const readyOption = isBot || isSpaMode ? 'onAllReady' : 'onShellReady';\n\n const { pipe, abort } = renderToPipeableStream(<ServerRouter context={routerContext} url={request.url} />, {\n [readyOption]() {\n shellRendered = true;\n const body = new PassThrough();\n\n const stream = createReadableStreamFromReadable(body);\n\n responseHeaders.set('Content-Type', 'text/html');\n\n resolve(\n new Response(stream, {\n headers: responseHeaders,\n status: responseStatusCode,\n }),\n );\n\n // this injects trace data to the HTML head\n pipe(getMetaTagTransformer(body));\n },\n onShellError(error: unknown) {\n reject(error);\n },\n onError(error: unknown) {\n // eslint-disable-next-line no-param-reassign\n responseStatusCode = 500;\n // Log streaming rendering errors from inside the shell. Don't log\n // errors encountered during initial shell rendering since they'll\n // reject and get logged in handleDocumentRequest.\n if (shellRendered) {\n // eslint-disable-next-line no-console\n console.error(error);\n }\n },\n });\n\n // Abort the rendering stream after the `streamTimeout`\n setTimeout(abort, streamTimeout);\n });\n };\n\n // Wrap the handle request function for request parametrization\n return wrapSentryHandleRequest(handleRequest as HandleRequestWithoutMiddleware
|
|
1
|
+
{"version":3,"file":"createSentryHandleRequest.js","sources":["../../../src/server/createSentryHandleRequest.tsx"],"sourcesContent":["import type { createReadableStreamFromReadable } from '@react-router/node';\nimport type { ReactNode } from 'react';\nimport React from 'react';\nimport type { AppLoadContext, EntryContext, RouterContextProvider, ServerRouter } from 'react-router';\nimport { PassThrough } from 'stream';\nimport { getMetaTagTransformer } from './getMetaTagTransformer';\nimport { wrapSentryHandleRequest } from './wrapSentryHandleRequest';\n\ntype RenderToPipeableStreamOptions = {\n [key: string]: unknown;\n onShellReady?: () => void;\n onAllReady?: () => void;\n onShellError?: (error: unknown) => void;\n onError?: (error: unknown) => void;\n};\n\ntype RenderToPipeableStreamResult = {\n pipe: (destination: NodeJS.WritableStream) => void;\n abort: () => void;\n};\n\ntype RenderToPipeableStreamFunction = (\n node: ReactNode,\n options: RenderToPipeableStreamOptions,\n) => RenderToPipeableStreamResult;\n\nexport interface SentryHandleRequestOptions {\n /**\n * Timeout in milliseconds after which the rendering stream will be aborted\n * @default 10000\n */\n streamTimeout?: number;\n\n /**\n * React's renderToPipeableStream function from 'react-dom/server'\n */\n renderToPipeableStream: RenderToPipeableStreamFunction;\n\n /**\n * The <ServerRouter /> component from '@react-router/server'\n */\n ServerRouter: typeof ServerRouter;\n\n /**\n * createReadableStreamFromReadable from '@react-router/node'\n */\n createReadableStreamFromReadable: typeof createReadableStreamFromReadable;\n\n /**\n * Regular expression to identify bot user agents\n * @default /bot|crawler|spider|googlebot|chrome-lighthouse|baidu|bing|google|yahoo|lighthouse/i\n */\n botRegex?: RegExp;\n}\n\ntype HandleRequestWithoutMiddleware = (\n request: Request,\n responseStatusCode: number,\n responseHeaders: Headers,\n routerContext: EntryContext,\n loadContext: AppLoadContext,\n) => Promise<unknown>;\n\ntype HandleRequestWithMiddleware = (\n request: Request,\n responseStatusCode: number,\n responseHeaders: Headers,\n routerContext: EntryContext,\n loadContext: RouterContextProvider,\n) => Promise<unknown>;\n\n/**\n * A complete Sentry-instrumented handleRequest implementation that handles both\n * route parametrization and trace meta tag injection.\n *\n * @param options Configuration options\n * @returns A Sentry-instrumented handleRequest function\n */\nexport function createSentryHandleRequest(\n options: SentryHandleRequestOptions,\n): HandleRequestWithoutMiddleware & HandleRequestWithMiddleware {\n const {\n streamTimeout = 10000,\n renderToPipeableStream,\n ServerRouter,\n createReadableStreamFromReadable,\n botRegex = /bot|crawler|spider|googlebot|chrome-lighthouse|baidu|bing|google|yahoo|lighthouse/i,\n } = options;\n\n const handleRequest = function handleRequest(\n request: Request,\n responseStatusCode: number,\n responseHeaders: Headers,\n routerContext: EntryContext,\n _loadContext: AppLoadContext | RouterContextProvider,\n ): Promise<Response> {\n return new Promise((resolve, reject) => {\n let shellRendered = false;\n const userAgent = request.headers.get('user-agent');\n\n // Determine if we should use onAllReady or onShellReady\n const isBot = typeof userAgent === 'string' && botRegex.test(userAgent);\n const isSpaMode = !!(routerContext as { isSpaMode?: boolean }).isSpaMode;\n\n const readyOption = isBot || isSpaMode ? 'onAllReady' : 'onShellReady';\n\n const { pipe, abort } = renderToPipeableStream(<ServerRouter context={routerContext} url={request.url} />, {\n [readyOption]() {\n shellRendered = true;\n const body = new PassThrough();\n\n const stream = createReadableStreamFromReadable(body);\n\n responseHeaders.set('Content-Type', 'text/html');\n\n resolve(\n new Response(stream, {\n headers: responseHeaders,\n status: responseStatusCode,\n }),\n );\n\n // this injects trace data to the HTML head\n pipe(getMetaTagTransformer(body));\n },\n onShellError(error: unknown) {\n reject(error);\n },\n onError(error: unknown) {\n // eslint-disable-next-line no-param-reassign\n responseStatusCode = 500;\n // Log streaming rendering errors from inside the shell. Don't log\n // errors encountered during initial shell rendering since they'll\n // reject and get logged in handleDocumentRequest.\n if (shellRendered) {\n // eslint-disable-next-line no-console\n console.error(error);\n }\n },\n });\n\n // Abort the rendering stream after the `streamTimeout`\n setTimeout(abort, streamTimeout);\n });\n };\n\n // Wrap the handle request function for request parametrization\n return wrapSentryHandleRequest(handleRequest) as HandleRequestWithoutMiddleware & HandleRequestWithMiddleware;\n}\n"],"names":["handleRequest","React","PassThrough","stream","getMetaTagTransformer","wrapSentryHandleRequest"],"mappings":";;;;;;;AA8EO,SAAS,0BACd,OAAA,EAC8D;AAC9D,EAAA,MAAM;AAAA,IACJ,aAAA,GAAgB,GAAA;AAAA,IAChB,sBAAA;AAAA,IACA,YAAA;AAAA,IACA,gCAAA;AAAA,IACA,QAAA,GAAW;AAAA,GACb,GAAI,OAAA;AAEJ,EAAA,MAAM,gBAAgB,SAASA,cAAAA,CAC7B,SACA,kBAAA,EACA,eAAA,EACA,eACA,YAAA,EACmB;AACnB,IAAA,OAAO,IAAI,OAAA,CAAQ,CAAC,OAAA,EAAS,MAAA,KAAW;AACtC,MAAA,IAAI,aAAA,GAAgB,KAAA;AACpB,MAAA,MAAM,SAAA,GAAY,OAAA,CAAQ,OAAA,CAAQ,GAAA,CAAI,YAAY,CAAA;AAGlD,MAAA,MAAM,QAAQ,OAAO,SAAA,KAAc,QAAA,IAAY,QAAA,CAAS,KAAK,SAAS,CAAA;AACtE,MAAA,MAAM,SAAA,GAAY,CAAC,CAAE,aAAA,CAA0C,SAAA;AAE/D,MAAA,MAAM,WAAA,GAAc,KAAA,IAAS,SAAA,GAAY,YAAA,GAAe,cAAA;AAExD,MAAA,MAAM,EAAE,IAAA,EAAM,KAAA,EAAM,GAAI,sBAAA,iBAAuBC,aAAA,CAAA,aAAA,CAAC,YAAA,EAAA,EAAa,OAAA,EAAS,aAAA,EAAe,GAAA,EAAK,OAAA,CAAQ,GAAA,EAAK,CAAA,EAAI;AAAA,QACzG,CAAC,WAAW,CAAA,GAAI;AACd,UAAA,aAAA,GAAgB,IAAA;AAChB,UAAA,MAAM,IAAA,GAAO,IAAIC,kBAAA,EAAY;AAE7B,UAAA,MAAMC,QAAA,GAAS,iCAAiC,IAAI,CAAA;AAEpD,UAAA,eAAA,CAAgB,GAAA,CAAI,gBAAgB,WAAW,CAAA;AAE/C,UAAA,OAAA;AAAA,YACE,IAAI,SAASA,QAAA,EAAQ;AAAA,cACnB,OAAA,EAAS,eAAA;AAAA,cACT,MAAA,EAAQ;AAAA,aACT;AAAA,WACH;AAGA,UAAA,IAAA,CAAKC,2CAAA,CAAsB,IAAI,CAAC,CAAA;AAAA,QAClC,CAAA;AAAA,QACA,aAAa,KAAA,EAAgB;AAC3B,UAAA,MAAA,CAAO,KAAK,CAAA;AAAA,QACd,CAAA;AAAA,QACA,QAAQ,KAAA,EAAgB;AAEtB,UAAA,kBAAA,GAAqB,GAAA;AAIrB,UAAA,IAAI,aAAA,EAAe;AAEjB,YAAA,OAAA,CAAQ,MAAM,KAAK,CAAA;AAAA,UACrB;AAAA,QACF;AAAA,OACD,CAAA;AAGD,MAAA,UAAA,CAAW,OAAO,aAAa,CAAA;AAAA,IACjC,CAAC,CAAA;AAAA,EACH,CAAA;AAGA,EAAA,OAAOC,gDAAwB,aAAa,CAAA;AAC9C;;;;"}
|