@sentry/react-router 11.0.0-alpha.0 → 11.0.0-alpha.1
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 +2 -1
- package/build/cjs/client/createClientInstrumentation.js.map +1 -1
- package/build/cjs/client/hydratedRouter.js +6 -5
- package/build/cjs/client/hydratedRouter.js.map +1 -1
- package/build/cjs/index.server.js +0 -1
- package/build/cjs/index.server.js.map +1 -1
- package/build/cjs/server/integration/lowQualityTransactionsFilterIntegration.js +1 -1
- package/build/cjs/server/integration/lowQualityTransactionsFilterIntegration.js.map +1 -1
- package/build/cjs/server/sdk.js +1 -1
- package/build/cjs/server/sdk.js.map +1 -1
- package/build/cjs/server/wrapSentryHandleRequest.js +0 -2
- package/build/cjs/server/wrapSentryHandleRequest.js.map +1 -1
- package/build/cjs/vite/buildEnd/handleOnBuildEnd.js +3 -13
- package/build/cjs/vite/buildEnd/handleOnBuildEnd.js.map +1 -1
- package/build/esm/client/createClientInstrumentation.js +2 -1
- package/build/esm/client/createClientInstrumentation.js.map +1 -1
- package/build/esm/client/hydratedRouter.js +7 -6
- package/build/esm/client/hydratedRouter.js.map +1 -1
- package/build/esm/index.server.js +1 -1
- package/build/esm/package.json +1 -1
- package/build/esm/server/integration/lowQualityTransactionsFilterIntegration.js +1 -1
- package/build/esm/server/integration/lowQualityTransactionsFilterIntegration.js.map +1 -1
- package/build/esm/server/sdk.js +1 -1
- package/build/esm/server/sdk.js.map +1 -1
- package/build/esm/server/wrapSentryHandleRequest.js +1 -2
- package/build/esm/server/wrapSentryHandleRequest.js.map +1 -1
- package/build/esm/vite/buildEnd/handleOnBuildEnd.js +3 -13
- package/build/esm/vite/buildEnd/handleOnBuildEnd.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/server/index.d.ts +1 -1
- package/build/types/server/index.d.ts.map +1 -1
- package/build/types/server/integration/lowQualityTransactionsFilterIntegration.d.ts +1 -2
- package/build/types/server/integration/lowQualityTransactionsFilterIntegration.d.ts.map +1 -1
- package/build/types/server/wrapSentryHandleRequest.d.ts +0 -2
- package/build/types/server/wrapSentryHandleRequest.d.ts.map +1 -1
- package/build/types/vite/buildEnd/handleOnBuildEnd.d.ts.map +1 -1
- package/build/types/vite/types.d.ts +0 -48
- package/build/types/vite/types.d.ts.map +1 -1
- package/package.json +8 -8
|
@@ -275,7 +275,8 @@ function updateRootSpanRoute(routeName, hasPattern) {
|
|
|
275
275
|
if (!rootSpan) {
|
|
276
276
|
return;
|
|
277
277
|
}
|
|
278
|
-
const {
|
|
278
|
+
const { attributes: attributes$1 } = core.spanToJSON(rootSpan);
|
|
279
|
+
const op = attributes$1[attributes.SENTRY_OP];
|
|
279
280
|
if (op !== "navigation" && op !== "pageload") {
|
|
280
281
|
return;
|
|
281
282
|
}
|
|
@@ -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 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":"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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 { attributes } = spanToJSON(rootSpan);\n const op = attributes[SENTRY_OP];\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","attributes","spanToJSON","updateSpanName","URL_TEMPLATE"],"mappings":"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"}
|
|
@@ -16,7 +16,7 @@ function instrumentHydratedRouter() {
|
|
|
16
16
|
if (router) {
|
|
17
17
|
const pageloadSpan = getActiveRootSpan();
|
|
18
18
|
if (pageloadSpan) {
|
|
19
|
-
const pageloadName = core.spanToJSON(pageloadSpan).
|
|
19
|
+
const pageloadName = core.spanToJSON(pageloadSpan).name;
|
|
20
20
|
const parameterizePageloadRoute = utils.getParameterizedRoute(router.state);
|
|
21
21
|
if (pageloadName && // this event is for the currently active pageload
|
|
22
22
|
utils.normalizePathname(router.state.location.pathname) === utils.normalizePathname(pageloadName)) {
|
|
@@ -71,12 +71,13 @@ function instrumentHydratedRouter() {
|
|
|
71
71
|
return;
|
|
72
72
|
}
|
|
73
73
|
const rootSpanJson = core.spanToJSON(rootSpan);
|
|
74
|
-
|
|
74
|
+
const rootSpanAttributes = rootSpanJson.attributes;
|
|
75
|
+
if (rootSpanAttributes[attributes.SENTRY_OP] === "navigation" && createClientInstrumentation.isClientInstrumentationApiUsed() && rootSpanAttributes[core.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE] === "route") {
|
|
75
76
|
return;
|
|
76
77
|
}
|
|
77
|
-
const rootSpanName = rootSpanJson.
|
|
78
|
+
const rootSpanName = rootSpanJson.name;
|
|
78
79
|
const parameterizedRoute = utils.getParameterizedRoute(newState);
|
|
79
|
-
const spanPathname =
|
|
80
|
+
const spanPathname = rootSpanAttributes[attributes.URL_PATH];
|
|
80
81
|
const destinationPathname = utils.normalizePathname(newState.location.pathname);
|
|
81
82
|
if (rootSpanName && newState.navigation.state === "idle" && // navigation has completed
|
|
82
83
|
// this event is for the currently active root span
|
|
@@ -130,7 +131,7 @@ function getActiveRootSpan() {
|
|
|
130
131
|
return void 0;
|
|
131
132
|
}
|
|
132
133
|
const rootSpan = core.getRootSpan(activeSpan);
|
|
133
|
-
const op = core.spanToJSON(rootSpan).
|
|
134
|
+
const op = core.spanToJSON(rootSpan).attributes[attributes.SENTRY_OP];
|
|
134
135
|
return op === "navigation" || op === "pageload" ? rootSpan : void 0;
|
|
135
136
|
}
|
|
136
137
|
|
|
@@ -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({\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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"}
|
|
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 { SENTRY_OP, 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).name;\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 const rootSpanAttributes = rootSpanJson.attributes;\n\n // When the instrumentation API is active, navigation roots are parameterized\n // by the native route hooks\n if (\n rootSpanAttributes[SENTRY_OP] === 'navigation' &&\n isClientInstrumentationApiUsed() &&\n rootSpanAttributes[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE] === 'route'\n ) {\n return;\n }\n\n const rootSpanName = rootSpanJson.name;\n const parameterizedRoute = getParameterizedRoute(newState);\n const spanPathname = rootSpanAttributes[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).attributes[SENTRY_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","SENTRY_OP","URL_PATH","DEBUG_BUILD","debug","getClient","startBrowserTracingNavigationSpan","SEMANTIC_ATTRIBUTE_SENTRY_OP","getActiveSpan","getRootSpan"],"mappings":"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"}
|
|
@@ -15,7 +15,6 @@ const serverGlobals = require('./server/serverGlobals.js');
|
|
|
15
15
|
|
|
16
16
|
|
|
17
17
|
exports.init = sdk.init;
|
|
18
|
-
exports.sentryHandleRequest = wrapSentryHandleRequest.sentryHandleRequest;
|
|
19
18
|
exports.wrapSentryHandleRequest = wrapSentryHandleRequest.wrapSentryHandleRequest;
|
|
20
19
|
exports.createSentryHandleRequest = createSentryHandleRequest.createSentryHandleRequest;
|
|
21
20
|
exports.createSentryHandleError = createSentryHandleError.createSentryHandleError;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.server.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.server.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -10,7 +10,7 @@ const LOW_QUALITY_TRANSACTIONS_FILTERS = [
|
|
|
10
10
|
// Filter by `http.target` instead, which carries the raw request path.
|
|
11
11
|
{ attributes: { "http.target": /\/__manifest/ } }
|
|
12
12
|
];
|
|
13
|
-
const _lowQualityTransactionsFilterIntegration = ((
|
|
13
|
+
const _lowQualityTransactionsFilterIntegration = (() => ({
|
|
14
14
|
name: "LowQualityTransactionsFilter",
|
|
15
15
|
beforeSetup(client) {
|
|
16
16
|
const opts = client.getOptions();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lowQualityTransactionsFilterIntegration.js","sources":["../../../../src/server/integration/lowQualityTransactionsFilterIntegration.ts"],"sourcesContent":["import type { IntegrationFn } from '@sentry/core';\nimport { defineIntegration } from '@sentry/core';\
|
|
1
|
+
{"version":3,"file":"lowQualityTransactionsFilterIntegration.js","sources":["../../../../src/server/integration/lowQualityTransactionsFilterIntegration.ts"],"sourcesContent":["import type { IntegrationFn } from '@sentry/core';\nimport { defineIntegration } from '@sentry/core';\n\nconst LOW_QUALITY_TRANSACTIONS_FILTERS = [\n /GET \\/node_modules\\//,\n /GET \\/favicon\\.ico/,\n /GET \\/@id\\//,\n // The span description for the `__manifest` endpoint is `GET *` (`http.route` resolves to `*`).\n // Filter by `http.target` instead, which carries the raw request path.\n { attributes: { 'http.target': /\\/__manifest/ } },\n];\n\nconst _lowQualityTransactionsFilterIntegration = (() => ({\n name: 'LowQualityTransactionsFilter' as const,\n beforeSetup(client) {\n const opts = client.getOptions();\n opts.ignoreSpans = [...(opts.ignoreSpans || []), ...LOW_QUALITY_TRANSACTIONS_FILTERS];\n },\n})) satisfies IntegrationFn;\n\n/**\n * Integration that filters out noisy http transactions such as requests to node_modules, favicon.ico, @id/, __manifest.\n * Adds entries to `ignoreSpans` so the filter applies in both static and streaming trace lifecycles.\n */\nexport const lowQualityTransactionsFilterIntegration = defineIntegration(_lowQualityTransactionsFilterIntegration);\n"],"names":["defineIntegration"],"mappings":";;;;AAGA,MAAM,gCAAA,GAAmC;AAAA,EACvC,sBAAA;AAAA,EACA,oBAAA;AAAA,EACA,aAAA;AAAA;AAAA;AAAA,EAGA,EAAE,UAAA,EAAY,EAAE,aAAA,EAAe,gBAAe;AAChD,CAAA;AAEA,MAAM,4CAA4C,OAAO;AAAA,EACvD,IAAA,EAAM,8BAAA;AAAA,EACN,YAAY,MAAA,EAAQ;AAClB,IAAA,MAAM,IAAA,GAAO,OAAO,UAAA,EAAW;AAC/B,IAAA,IAAA,CAAK,WAAA,GAAc,CAAC,GAAI,IAAA,CAAK,eAAe,EAAC,EAAI,GAAG,gCAAgC,CAAA;AAAA,EACtF;AACF,CAAA,CAAA,CAAA;AAMO,MAAM,uCAAA,GAA0CA,uBAAkB,wCAAwC;;;;"}
|
package/build/cjs/server/sdk.js
CHANGED
|
@@ -9,7 +9,7 @@ const reactRouterServer = require('./integration/reactRouterServer.js');
|
|
|
9
9
|
function getDefaultReactRouterServerIntegrations(options) {
|
|
10
10
|
return [
|
|
11
11
|
...node.getDefaultIntegrations(options),
|
|
12
|
-
lowQualityTransactionsFilterIntegration.lowQualityTransactionsFilterIntegration(
|
|
12
|
+
lowQualityTransactionsFilterIntegration.lowQualityTransactionsFilterIntegration(),
|
|
13
13
|
reactRouterServer.reactRouterServerIntegration()
|
|
14
14
|
];
|
|
15
15
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sdk.js","sources":["../../../src/server/sdk.ts"],"sourcesContent":["import type { Integration } from '@sentry/core';\nimport { applySdkMetadata, debug, setTag } from '@sentry/core';\nimport type { NodeClient, NodeOptions } from '@sentry/node';\nimport { getDefaultIntegrations as getNodeDefaultIntegrations, init as initNodeSdk } from '@sentry/node';\nimport { DEBUG_BUILD } from '../common/debug-build';\nimport { lowQualityTransactionsFilterIntegration } from './integration/lowQualityTransactionsFilterIntegration';\nimport { reactRouterServerIntegration } from './integration/reactRouterServer';\n\n/**\n * Returns the default integrations for the React Router SDK.\n * @param options The options for the SDK.\n */\nexport function getDefaultReactRouterServerIntegrations(options: NodeOptions): Integration[] {\n return [\n ...getNodeDefaultIntegrations(options),\n lowQualityTransactionsFilterIntegration(
|
|
1
|
+
{"version":3,"file":"sdk.js","sources":["../../../src/server/sdk.ts"],"sourcesContent":["import type { Integration } from '@sentry/core';\nimport { applySdkMetadata, debug, setTag } from '@sentry/core';\nimport type { NodeClient, NodeOptions } from '@sentry/node';\nimport { getDefaultIntegrations as getNodeDefaultIntegrations, init as initNodeSdk } from '@sentry/node';\nimport { DEBUG_BUILD } from '../common/debug-build';\nimport { lowQualityTransactionsFilterIntegration } from './integration/lowQualityTransactionsFilterIntegration';\nimport { reactRouterServerIntegration } from './integration/reactRouterServer';\n\n/**\n * Returns the default integrations for the React Router SDK.\n * @param options The options for the SDK.\n */\nexport function getDefaultReactRouterServerIntegrations(options: NodeOptions): Integration[] {\n return [\n ...getNodeDefaultIntegrations(options),\n lowQualityTransactionsFilterIntegration(),\n reactRouterServerIntegration(),\n ];\n}\n\n/**\n * Initializes the server side of the React Router SDK\n */\nexport function init(options: NodeOptions): NodeClient | undefined {\n const opts: NodeOptions = {\n ...options,\n defaultIntegrations: getDefaultReactRouterServerIntegrations(options),\n };\n\n DEBUG_BUILD && debug.log('Initializing SDK...');\n\n applySdkMetadata(opts, 'react-router', ['react-router', 'node']);\n\n const client = initNodeSdk(opts);\n\n setTag('runtime', 'node');\n\n DEBUG_BUILD && debug.log('SDK successfully initialized');\n\n return client;\n}\n"],"names":["getNodeDefaultIntegrations","lowQualityTransactionsFilterIntegration","reactRouterServerIntegration","DEBUG_BUILD","debug","applySdkMetadata","initNodeSdk","setTag"],"mappings":";;;;;;;;AAYO,SAAS,wCAAwC,OAAA,EAAqC;AAC3F,EAAA,OAAO;AAAA,IACL,GAAGA,4BAA2B,OAAO,CAAA;AAAA,IACrCC,+EAAA,EAAwC;AAAA,IACxCC,8CAAA;AAA6B,GAC/B;AACF;AAKO,SAAS,KAAK,OAAA,EAA8C;AACjE,EAAA,MAAM,IAAA,GAAoB;AAAA,IACxB,GAAG,OAAA;AAAA,IACH,mBAAA,EAAqB,wCAAwC,OAAO;AAAA,GACtE;AAEA,EAAAC,sBAAA,IAAeC,UAAA,CAAM,IAAI,qBAAqB,CAAA;AAE9C,EAAAC,qBAAA,CAAiB,IAAA,EAAM,cAAA,EAAgB,CAAC,cAAA,EAAgB,MAAM,CAAC,CAAA;AAE/D,EAAA,MAAM,MAAA,GAASC,UAAY,IAAI,CAAA;AAE/B,EAAAC,WAAA,CAAO,WAAW,MAAM,CAAA;AAExB,EAAAJ,sBAAA,IAAeC,UAAA,CAAM,IAAI,8BAA8B,CAAA;AAEvD,EAAA,OAAO,MAAA;AACT;;;;;"}
|
|
@@ -53,8 +53,6 @@ function wrapSentryHandleRequest(originalHandle) {
|
|
|
53
53
|
}
|
|
54
54
|
};
|
|
55
55
|
}
|
|
56
|
-
const sentryHandleRequest = wrapSentryHandleRequest;
|
|
57
56
|
|
|
58
|
-
exports.sentryHandleRequest = sentryHandleRequest;
|
|
59
57
|
exports.wrapSentryHandleRequest = wrapSentryHandleRequest;
|
|
60
58
|
//# sourceMappingURL=wrapSentryHandleRequest.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wrapSentryHandleRequest.js","sources":["../../../src/server/wrapSentryHandleRequest.ts"],"sourcesContent":["import { HTTP_ROUTE } from '@sentry/conventions/attributes';\nimport {\n flushIfServerless,\n getActiveSpan,\n getCurrentScope,\n getRootSpan,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n SEMANTIC_ATTRIBUTE_SENTRY_SOURCE,\n updateSpanName,\n} from '@sentry/core';\nimport type { AppLoadContext, EntryContext, RouterContextProvider } from 'react-router';\nimport { isInstrumentationApiUsed } from './serverGlobals';\n\ntype OriginalHandleRequestWithoutMiddleware = (\n request: Request,\n responseStatusCode: number,\n responseHeaders: Headers,\n routerContext: EntryContext,\n loadContext: AppLoadContext,\n) => Promise<unknown>;\n\ntype OriginalHandleRequestWithMiddleware = (\n request: Request,\n responseStatusCode: number,\n responseHeaders: Headers,\n routerContext: EntryContext,\n loadContext: RouterContextProvider,\n) => Promise<unknown>;\n\n/**\n * Wraps the original handleRequest function to add Sentry instrumentation.\n *\n * @param originalHandle - The original handleRequest function to wrap\n * @returns A wrapped version of the handle request function with Sentry instrumentation\n */\nexport function wrapSentryHandleRequest(\n originalHandle: OriginalHandleRequestWithoutMiddleware,\n): OriginalHandleRequestWithoutMiddleware;\n/**\n * Wraps the original handleRequest function to add Sentry instrumentation.\n *\n * @param originalHandle - The original handleRequest function to wrap\n * @returns A wrapped version of the handle request function with Sentry instrumentation\n */\nexport function wrapSentryHandleRequest(\n originalHandle: OriginalHandleRequestWithMiddleware,\n): OriginalHandleRequestWithMiddleware;\n/**\n * Wraps the original handleRequest function to add Sentry instrumentation.\n *\n * @param originalHandle - The original handleRequest function to wrap\n * @returns A wrapped version of the handle request function with Sentry instrumentation\n */\nexport function wrapSentryHandleRequest(\n originalHandle: OriginalHandleRequestWithoutMiddleware | OriginalHandleRequestWithMiddleware,\n): OriginalHandleRequestWithoutMiddleware | OriginalHandleRequestWithMiddleware {\n return async function sentryInstrumentedHandleRequest(\n request: Request,\n responseStatusCode: number,\n responseHeaders: Headers,\n routerContext: EntryContext,\n loadContext: AppLoadContext | RouterContextProvider,\n ) {\n const parameterizedPath =\n routerContext?.staticHandlerContext?.matches?.[routerContext.staticHandlerContext.matches.length - 1]?.route.path;\n\n const activeSpan = getActiveSpan();\n const rootSpan = activeSpan ? getRootSpan(activeSpan) : undefined;\n\n if (parameterizedPath && rootSpan) {\n // Normalize route name - avoid \"//\" for root routes\n const routeName = parameterizedPath.startsWith('/') ? parameterizedPath : `/${parameterizedPath}`;\n\n const transactionName = `${request.method} ${routeName}`;\n\n updateSpanName(rootSpan, transactionName);\n getCurrentScope().setTransactionName(transactionName);\n\n // Set route attributes - acts as fallback for lazy-only routes when using instrumentation API\n // Don't override origin when instrumentation API is used (preserve instrumentation_api origin)\n if (isInstrumentationApiUsed()) {\n rootSpan.setAttributes({\n [HTTP_ROUTE]: routeName,\n [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'route',\n });\n } else {\n rootSpan.setAttributes({\n [HTTP_ROUTE]: routeName,\n [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'route',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.react_router.request_handler',\n });\n }\n }\n\n try {\n // Type guard to call the correct overload based on loadContext type\n if (isRouterContextProvider(loadContext)) {\n // loadContext is RouterContextProvider\n return await (originalHandle as OriginalHandleRequestWithMiddleware)(\n request,\n responseStatusCode,\n responseHeaders,\n routerContext,\n loadContext,\n );\n } else {\n // loadContext is AppLoadContext\n return await (originalHandle as OriginalHandleRequestWithoutMiddleware)(\n request,\n responseStatusCode,\n responseHeaders,\n routerContext,\n loadContext,\n );\n }\n } finally {\n await flushIfServerless();\n }\n\n /**\n * Helper type guard to determine if the context is a RouterContextProvider.\n *\n * @param ctx - The context to check\n * @returns True if the context is a RouterContextProvider\n */\n function isRouterContextProvider(ctx: AppLoadContext | RouterContextProvider): ctx is RouterContextProvider {\n return typeof (ctx as RouterContextProvider)?.get === 'function';\n }\n };\n}\n
|
|
1
|
+
{"version":3,"file":"wrapSentryHandleRequest.js","sources":["../../../src/server/wrapSentryHandleRequest.ts"],"sourcesContent":["import { HTTP_ROUTE } from '@sentry/conventions/attributes';\nimport {\n flushIfServerless,\n getActiveSpan,\n getCurrentScope,\n getRootSpan,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n SEMANTIC_ATTRIBUTE_SENTRY_SOURCE,\n updateSpanName,\n} from '@sentry/core';\nimport type { AppLoadContext, EntryContext, RouterContextProvider } from 'react-router';\nimport { isInstrumentationApiUsed } from './serverGlobals';\n\ntype OriginalHandleRequestWithoutMiddleware = (\n request: Request,\n responseStatusCode: number,\n responseHeaders: Headers,\n routerContext: EntryContext,\n loadContext: AppLoadContext,\n) => Promise<unknown>;\n\ntype OriginalHandleRequestWithMiddleware = (\n request: Request,\n responseStatusCode: number,\n responseHeaders: Headers,\n routerContext: EntryContext,\n loadContext: RouterContextProvider,\n) => Promise<unknown>;\n\n/**\n * Wraps the original handleRequest function to add Sentry instrumentation.\n *\n * @param originalHandle - The original handleRequest function to wrap\n * @returns A wrapped version of the handle request function with Sentry instrumentation\n */\nexport function wrapSentryHandleRequest(\n originalHandle: OriginalHandleRequestWithoutMiddleware,\n): OriginalHandleRequestWithoutMiddleware;\n/**\n * Wraps the original handleRequest function to add Sentry instrumentation.\n *\n * @param originalHandle - The original handleRequest function to wrap\n * @returns A wrapped version of the handle request function with Sentry instrumentation\n */\nexport function wrapSentryHandleRequest(\n originalHandle: OriginalHandleRequestWithMiddleware,\n): OriginalHandleRequestWithMiddleware;\n/**\n * Wraps the original handleRequest function to add Sentry instrumentation.\n *\n * @param originalHandle - The original handleRequest function to wrap\n * @returns A wrapped version of the handle request function with Sentry instrumentation\n */\nexport function wrapSentryHandleRequest(\n originalHandle: OriginalHandleRequestWithoutMiddleware | OriginalHandleRequestWithMiddleware,\n): OriginalHandleRequestWithoutMiddleware | OriginalHandleRequestWithMiddleware {\n return async function sentryInstrumentedHandleRequest(\n request: Request,\n responseStatusCode: number,\n responseHeaders: Headers,\n routerContext: EntryContext,\n loadContext: AppLoadContext | RouterContextProvider,\n ) {\n const parameterizedPath =\n routerContext?.staticHandlerContext?.matches?.[routerContext.staticHandlerContext.matches.length - 1]?.route.path;\n\n const activeSpan = getActiveSpan();\n const rootSpan = activeSpan ? getRootSpan(activeSpan) : undefined;\n\n if (parameterizedPath && rootSpan) {\n // Normalize route name - avoid \"//\" for root routes\n const routeName = parameterizedPath.startsWith('/') ? parameterizedPath : `/${parameterizedPath}`;\n\n const transactionName = `${request.method} ${routeName}`;\n\n updateSpanName(rootSpan, transactionName);\n getCurrentScope().setTransactionName(transactionName);\n\n // Set route attributes - acts as fallback for lazy-only routes when using instrumentation API\n // Don't override origin when instrumentation API is used (preserve instrumentation_api origin)\n if (isInstrumentationApiUsed()) {\n rootSpan.setAttributes({\n [HTTP_ROUTE]: routeName,\n [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'route',\n });\n } else {\n rootSpan.setAttributes({\n [HTTP_ROUTE]: routeName,\n [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'route',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.react_router.request_handler',\n });\n }\n }\n\n try {\n // Type guard to call the correct overload based on loadContext type\n if (isRouterContextProvider(loadContext)) {\n // loadContext is RouterContextProvider\n return await (originalHandle as OriginalHandleRequestWithMiddleware)(\n request,\n responseStatusCode,\n responseHeaders,\n routerContext,\n loadContext,\n );\n } else {\n // loadContext is AppLoadContext\n return await (originalHandle as OriginalHandleRequestWithoutMiddleware)(\n request,\n responseStatusCode,\n responseHeaders,\n routerContext,\n loadContext,\n );\n }\n } finally {\n await flushIfServerless();\n }\n\n /**\n * Helper type guard to determine if the context is a RouterContextProvider.\n *\n * @param ctx - The context to check\n * @returns True if the context is a RouterContextProvider\n */\n function isRouterContextProvider(ctx: AppLoadContext | RouterContextProvider): ctx is RouterContextProvider {\n return typeof (ctx as RouterContextProvider)?.get === 'function';\n }\n };\n}\n"],"names":["getActiveSpan","getRootSpan","updateSpanName","getCurrentScope","isInstrumentationApiUsed","HTTP_ROUTE","SEMANTIC_ATTRIBUTE_SENTRY_SOURCE","SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN","flushIfServerless"],"mappings":";;;;;;AAqDO,SAAS,wBACd,cAAA,EAC8E;AAC9E,EAAA,OAAO,eAAe,+BAAA,CACpB,OAAA,EACA,kBAAA,EACA,eAAA,EACA,eACA,WAAA,EACA;AACA,IAAA,MAAM,iBAAA,GACJ,aAAA,EAAe,oBAAA,EAAsB,OAAA,GAAU,aAAA,CAAc,qBAAqB,OAAA,CAAQ,MAAA,GAAS,CAAC,CAAA,EAAG,KAAA,CAAM,IAAA;AAE/G,IAAA,MAAM,aAAaA,kBAAA,EAAc;AACjC,IAAA,MAAM,QAAA,GAAW,UAAA,GAAaC,gBAAA,CAAY,UAAU,CAAA,GAAI,MAAA;AAExD,IAAA,IAAI,qBAAqB,QAAA,EAAU;AAEjC,MAAA,MAAM,YAAY,iBAAA,CAAkB,UAAA,CAAW,GAAG,CAAA,GAAI,iBAAA,GAAoB,IAAI,iBAAiB,CAAA,CAAA;AAE/F,MAAA,MAAM,eAAA,GAAkB,CAAA,EAAG,OAAA,CAAQ,MAAM,IAAI,SAAS,CAAA,CAAA;AAEtD,MAAAC,mBAAA,CAAe,UAAU,eAAe,CAAA;AACxC,MAAAC,oBAAA,EAAgB,CAAE,mBAAmB,eAAe,CAAA;AAIpD,MAAA,IAAIC,wCAAyB,EAAG;AAC9B,QAAA,QAAA,CAAS,aAAA,CAAc;AAAA,UACrB,CAACC,qBAAU,GAAG,SAAA;AAAA,UACd,CAACC,qCAAgC,GAAG;AAAA,SACrC,CAAA;AAAA,MACH,CAAA,MAAO;AACL,QAAA,QAAA,CAAS,aAAA,CAAc;AAAA,UACrB,CAACD,qBAAU,GAAG,SAAA;AAAA,UACd,CAACC,qCAAgC,GAAG,OAAA;AAAA,UACpC,CAACC,qCAAgC,GAAG;AAAA,SACrC,CAAA;AAAA,MACH;AAAA,IACF;AAEA,IAAA,IAAI;AAEF,MAAA,IAAI,uBAAA,CAAwB,WAAW,CAAA,EAAG;AAExC,QAAA,OAAO,MAAO,cAAA;AAAA,UACZ,OAAA;AAAA,UACA,kBAAA;AAAA,UACA,eAAA;AAAA,UACA,aAAA;AAAA,UACA;AAAA,SACF;AAAA,MACF,CAAA,MAAO;AAEL,QAAA,OAAO,MAAO,cAAA;AAAA,UACZ,OAAA;AAAA,UACA,kBAAA;AAAA,UACA,eAAA;AAAA,UACA,aAAA;AAAA,UACA;AAAA,SACF;AAAA,MACF;AAAA,IACF,CAAA,SAAE;AACA,MAAA,MAAMC,sBAAA,EAAkB;AAAA,IAC1B;AAQA,IAAA,SAAS,wBAAwB,GAAA,EAA2E;AAC1G,MAAA,OAAO,OAAQ,KAA+B,GAAA,KAAQ,UAAA;AAAA,IACxD;AAAA,EACF,CAAA;AACF;;;;"}
|
|
@@ -11,18 +11,10 @@ function getSentryConfig(viteConfig) {
|
|
|
11
11
|
return viteConfig.sentryConfig;
|
|
12
12
|
}
|
|
13
13
|
function resolveSourceMapsDisable(sentryConfig) {
|
|
14
|
-
if (sentryConfig.sourceMapsUploadOptions?.enabled === false) {
|
|
15
|
-
return true;
|
|
16
|
-
}
|
|
17
14
|
return sentryConfig.sourcemaps?.disable ?? sentryConfig.unstable_sentryVitePluginOptions?.sourcemaps?.disable;
|
|
18
15
|
}
|
|
19
16
|
const sentryOnBuildEnd = async ({ reactRouterConfig, viteConfig }) => {
|
|
20
17
|
const sentryConfig = getSentryConfig(viteConfig);
|
|
21
|
-
const {
|
|
22
|
-
sourceMapsUploadOptions,
|
|
23
|
-
// extract to exclude from rest config
|
|
24
|
-
...sentryConfigWithoutDeprecatedSourceMapOption
|
|
25
|
-
} = sentryConfig;
|
|
26
18
|
const unstableSentryVitePluginOptions = sentryConfig.unstable_sentryVitePluginOptions;
|
|
27
19
|
const {
|
|
28
20
|
authToken,
|
|
@@ -33,19 +25,17 @@ const sentryOnBuildEnd = async ({ reactRouterConfig, viteConfig }) => {
|
|
|
33
25
|
debug = false
|
|
34
26
|
} = {
|
|
35
27
|
...unstableSentryVitePluginOptions,
|
|
36
|
-
...
|
|
37
|
-
// spread in the config without the deprecated sourceMapsUploadOptions
|
|
28
|
+
...sentryConfig,
|
|
38
29
|
sourcemaps: {
|
|
39
30
|
...unstableSentryVitePluginOptions?.sourcemaps,
|
|
40
31
|
...sentryConfig.sourcemaps,
|
|
41
|
-
...sourceMapsUploadOptions,
|
|
42
32
|
disable: resolveSourceMapsDisable(sentryConfig)
|
|
43
33
|
},
|
|
44
34
|
release: {
|
|
45
35
|
...unstableSentryVitePluginOptions?.release,
|
|
46
36
|
...sentryConfig.release
|
|
47
37
|
},
|
|
48
|
-
project: unstableSentryVitePluginOptions?.project ? Array.isArray(unstableSentryVitePluginOptions?.project) ? unstableSentryVitePluginOptions?.project[0] : unstableSentryVitePluginOptions?.project :
|
|
38
|
+
project: unstableSentryVitePluginOptions?.project ? Array.isArray(unstableSentryVitePluginOptions?.project) ? unstableSentryVitePluginOptions?.project[0] : unstableSentryVitePluginOptions?.project : sentryConfig.project
|
|
49
39
|
};
|
|
50
40
|
const cliInstance = new SentryCli.default(null, {
|
|
51
41
|
authToken,
|
|
@@ -95,7 +85,7 @@ const sentryOnBuildEnd = async ({ reactRouterConfig, viteConfig }) => {
|
|
|
95
85
|
updatedFilesToDeleteAfterUpload = [`${reactRouterConfig.buildDirectory}/**/*.map`];
|
|
96
86
|
debug && // eslint-disable-next-line no-console
|
|
97
87
|
console.info(
|
|
98
|
-
`[Sentry] Automatically setting \`
|
|
88
|
+
`[Sentry] Automatically setting \`sourcemaps.filesToDeleteAfterUpload: ${JSON.stringify(
|
|
99
89
|
updatedFilesToDeleteAfterUpload
|
|
100
90
|
)}\` to delete generated source maps after they were uploaded to Sentry.`
|
|
101
91
|
);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handleOnBuildEnd.js","sources":["../../../../src/vite/buildEnd/handleOnBuildEnd.ts"],"sourcesContent":["import { rm } from 'node:fs/promises';\nimport type { Config } from '@react-router/dev/config';\nimport SentryCli from '@sentry/cli';\nimport type { SentryVitePluginOptions } from '@sentry/bundler-plugins/vite';\nimport { glob } from 'glob';\nimport type { SentryReactRouterBuildOptions } from '../types';\n\ntype BuildEndHook = NonNullable<Config['buildEnd']>;\n\nfunction getSentryConfig(viteConfig: unknown): SentryReactRouterBuildOptions {\n if (!viteConfig || typeof viteConfig !== 'object' || !('sentryConfig' in viteConfig)) {\n // eslint-disable-next-line no-console\n console.error('[Sentry] sentryConfig not found - it needs to be passed to vite.config.ts');\n }\n\n return (viteConfig as { sentryConfig: SentryReactRouterBuildOptions }).sentryConfig;\n}\n\n/**\n * This hook is the only place that injects debug IDs and uploads source maps for React\n * Router, so `disable` has to be honoured wherever the user set it. Reading it from the\n * top-level config only would silently ignore `unstable_sentryVitePluginOptions`.\n */\nfunction resolveSourceMapsDisable(sentryConfig: SentryReactRouterBuildOptions): boolean | 'disable-upload' | undefined {\n // eslint-disable-next-line typescript/no-deprecated\n if (sentryConfig.sourceMapsUploadOptions?.enabled === false) {\n return true;\n }\n\n return sentryConfig.sourcemaps?.disable ?? sentryConfig.unstable_sentryVitePluginOptions?.sourcemaps?.disable;\n}\n\n/**\n * A build end hook that handles Sentry release creation and source map uploads.\n * It creates a new Sentry release if configured, uploads source maps to Sentry,\n * and optionally deletes the source map files after upload.\n */\nexport const sentryOnBuildEnd: BuildEndHook = async ({ reactRouterConfig, viteConfig }) => {\n const sentryConfig = getSentryConfig(viteConfig);\n\n // todo(v11): Remove deprecated sourceMapsUploadOptions support (no need for spread/pick anymore)\n const {\n sourceMapsUploadOptions, // extract to exclude from rest config\n ...sentryConfigWithoutDeprecatedSourceMapOption\n } = sentryConfig;\n\n const unstableSentryVitePluginOptions = sentryConfig.unstable_sentryVitePluginOptions;\n\n const {\n authToken,\n org,\n project,\n release,\n sourcemaps = { disable: false },\n debug = false,\n }: Omit<SentryReactRouterBuildOptions, 'sourcemaps' | 'sourceMapsUploadOptions'> &\n // Pick 'sourcemaps' from Vite plugin options as the types allow more (e.g. Promise values for `deleteFilesAfterUpload`)\n Pick<SentryVitePluginOptions, 'sourcemaps'> = {\n ...unstableSentryVitePluginOptions,\n ...sentryConfigWithoutDeprecatedSourceMapOption, // spread in the config without the deprecated sourceMapsUploadOptions\n sourcemaps: {\n ...unstableSentryVitePluginOptions?.sourcemaps,\n ...sentryConfig.sourcemaps,\n ...sourceMapsUploadOptions,\n disable: resolveSourceMapsDisable(sentryConfig),\n },\n release: {\n ...unstableSentryVitePluginOptions?.release,\n ...sentryConfig.release,\n },\n project: unstableSentryVitePluginOptions?.project\n ? Array.isArray(unstableSentryVitePluginOptions?.project)\n ? unstableSentryVitePluginOptions?.project[0]\n : unstableSentryVitePluginOptions?.project\n : sentryConfigWithoutDeprecatedSourceMapOption.project,\n };\n\n const cliInstance = new SentryCli(null, {\n authToken,\n org,\n ...sentryConfig.unstable_sentryVitePluginOptions,\n // same handling as in bundler plugins: https://github.com/getsentry/sentry-javascript-bundler-plugins/blob/05084f214c763a05137d863ff5a05ef38254f68d/packages/bundler-plugin-core/src/build-plugin-manager.ts#L102-L103\n project: Array.isArray(project) ? project[0] : project,\n });\n\n // check if release should be created\n if (release?.name) {\n try {\n await cliInstance.releases.new(release.name);\n } catch (error) {\n // eslint-disable-next-line no-console\n console.error('[Sentry] Could not create release', error);\n }\n }\n\n // `disable: 'disable-upload'` still injects debug IDs, so that source maps can be\n // uploaded manually at a later point - only `true` turns source maps off entirely.\n const sourceMapsFullyDisabled = sourcemaps?.disable === true;\n const uploadDisabled = sourceMapsFullyDisabled || sourcemaps?.disable === 'disable-upload';\n\n if (!sourceMapsFullyDisabled && viteConfig.build.sourcemap !== false) {\n // inject debugIds\n try {\n await cliInstance.execute(\n ['sourcemaps', 'inject', reactRouterConfig.buildDirectory],\n debug ? 'rejectOnError' : false,\n );\n } catch (error) {\n // eslint-disable-next-line no-console\n console.error('[Sentry] Could not inject debug ids', error);\n }\n\n if (!uploadDisabled) {\n // upload sourcemaps\n try {\n await cliInstance.releases.uploadSourceMaps(release?.name || 'undefined', {\n include: [\n {\n paths: [reactRouterConfig.buildDirectory],\n },\n ],\n live: 'rejectOnError',\n });\n } catch (error) {\n // eslint-disable-next-line no-console\n console.error('[Sentry] Could not upload sourcemaps', error);\n }\n }\n }\n\n // Only clean up source maps that were actually uploaded. Deleting them after skipping\n // the upload would leave the user with neither, breaking a manual upload.\n if (uploadDisabled) {\n return;\n }\n\n // delete sourcemaps after upload\n let updatedFilesToDeleteAfterUpload = await sourcemaps?.filesToDeleteAfterUpload;\n\n // set a default value no option was set\n if (typeof updatedFilesToDeleteAfterUpload === 'undefined') {\n updatedFilesToDeleteAfterUpload = [`${reactRouterConfig.buildDirectory}/**/*.map`];\n debug &&\n // eslint-disable-next-line no-console\n console.info(\n `[Sentry] Automatically setting \\`sourceMapsUploadOptions.filesToDeleteAfterUpload: ${JSON.stringify(\n updatedFilesToDeleteAfterUpload,\n )}\\` to delete generated source maps after they were uploaded to Sentry.`,\n );\n }\n if (updatedFilesToDeleteAfterUpload) {\n try {\n const filePathsToDelete = await glob(updatedFilesToDeleteAfterUpload, {\n absolute: true,\n nodir: true,\n });\n if (debug) {\n filePathsToDelete.forEach(filePathToDelete => {\n // eslint-disable-next-line no-console\n console.info(`Deleting asset after upload: ${filePathToDelete}`);\n });\n }\n await Promise.all(\n filePathsToDelete.map(filePathToDelete =>\n rm(filePathToDelete, { force: true }).catch((e: unknown) => {\n // This is allowed to fail - we just don't do anything\n debug &&\n // eslint-disable-next-line no-console\n console.debug(`An error occurred while attempting to delete asset: ${filePathToDelete}`, e);\n }),\n ),\n );\n } catch (error) {\n // eslint-disable-next-line no-console\n console.error('Error deleting files after sourcemap upload:', error);\n }\n }\n};\n"],"names":["SentryCli","glob","rm"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"handleOnBuildEnd.js","sources":["../../../../src/vite/buildEnd/handleOnBuildEnd.ts"],"sourcesContent":["import { rm } from 'node:fs/promises';\nimport type { Config } from '@react-router/dev/config';\nimport SentryCli from '@sentry/cli';\nimport type { SentryVitePluginOptions } from '@sentry/bundler-plugins/vite';\nimport { glob } from 'glob';\nimport type { SentryReactRouterBuildOptions } from '../types';\n\ntype BuildEndHook = NonNullable<Config['buildEnd']>;\n\nfunction getSentryConfig(viteConfig: unknown): SentryReactRouterBuildOptions {\n if (!viteConfig || typeof viteConfig !== 'object' || !('sentryConfig' in viteConfig)) {\n // eslint-disable-next-line no-console\n console.error('[Sentry] sentryConfig not found - it needs to be passed to vite.config.ts');\n }\n\n return (viteConfig as { sentryConfig: SentryReactRouterBuildOptions }).sentryConfig;\n}\n\n/**\n * This hook is the only place that injects debug IDs and uploads source maps for React\n * Router, so `disable` has to be honoured wherever the user set it. Reading it from the\n * top-level config only would silently ignore `unstable_sentryVitePluginOptions`.\n */\nfunction resolveSourceMapsDisable(sentryConfig: SentryReactRouterBuildOptions): boolean | 'disable-upload' | undefined {\n return sentryConfig.sourcemaps?.disable ?? sentryConfig.unstable_sentryVitePluginOptions?.sourcemaps?.disable;\n}\n\n/**\n * A build end hook that handles Sentry release creation and source map uploads.\n * It creates a new Sentry release if configured, uploads source maps to Sentry,\n * and optionally deletes the source map files after upload.\n */\nexport const sentryOnBuildEnd: BuildEndHook = async ({ reactRouterConfig, viteConfig }) => {\n const sentryConfig = getSentryConfig(viteConfig);\n\n const unstableSentryVitePluginOptions = sentryConfig.unstable_sentryVitePluginOptions;\n\n const {\n authToken,\n org,\n project,\n release,\n sourcemaps = { disable: false },\n debug = false,\n }: Omit<SentryReactRouterBuildOptions, 'sourcemaps'> &\n // Pick 'sourcemaps' from Vite plugin options as the types allow more (e.g. Promise values for `deleteFilesAfterUpload`)\n Pick<SentryVitePluginOptions, 'sourcemaps'> = {\n ...unstableSentryVitePluginOptions,\n ...sentryConfig,\n sourcemaps: {\n ...unstableSentryVitePluginOptions?.sourcemaps,\n ...sentryConfig.sourcemaps,\n disable: resolveSourceMapsDisable(sentryConfig),\n },\n release: {\n ...unstableSentryVitePluginOptions?.release,\n ...sentryConfig.release,\n },\n project: unstableSentryVitePluginOptions?.project\n ? Array.isArray(unstableSentryVitePluginOptions?.project)\n ? unstableSentryVitePluginOptions?.project[0]\n : unstableSentryVitePluginOptions?.project\n : sentryConfig.project,\n };\n\n const cliInstance = new SentryCli(null, {\n authToken,\n org,\n ...sentryConfig.unstable_sentryVitePluginOptions,\n // same handling as in bundler plugins: https://github.com/getsentry/sentry-javascript-bundler-plugins/blob/05084f214c763a05137d863ff5a05ef38254f68d/packages/bundler-plugin-core/src/build-plugin-manager.ts#L102-L103\n project: Array.isArray(project) ? project[0] : project,\n });\n\n // check if release should be created\n if (release?.name) {\n try {\n await cliInstance.releases.new(release.name);\n } catch (error) {\n // eslint-disable-next-line no-console\n console.error('[Sentry] Could not create release', error);\n }\n }\n\n // `disable: 'disable-upload'` still injects debug IDs, so that source maps can be\n // uploaded manually at a later point - only `true` turns source maps off entirely.\n const sourceMapsFullyDisabled = sourcemaps?.disable === true;\n const uploadDisabled = sourceMapsFullyDisabled || sourcemaps?.disable === 'disable-upload';\n\n if (!sourceMapsFullyDisabled && viteConfig.build.sourcemap !== false) {\n // inject debugIds\n try {\n await cliInstance.execute(\n ['sourcemaps', 'inject', reactRouterConfig.buildDirectory],\n debug ? 'rejectOnError' : false,\n );\n } catch (error) {\n // eslint-disable-next-line no-console\n console.error('[Sentry] Could not inject debug ids', error);\n }\n\n if (!uploadDisabled) {\n // upload sourcemaps\n try {\n await cliInstance.releases.uploadSourceMaps(release?.name || 'undefined', {\n include: [\n {\n paths: [reactRouterConfig.buildDirectory],\n },\n ],\n live: 'rejectOnError',\n });\n } catch (error) {\n // eslint-disable-next-line no-console\n console.error('[Sentry] Could not upload sourcemaps', error);\n }\n }\n }\n\n // Only clean up source maps that were actually uploaded. Deleting them after skipping\n // the upload would leave the user with neither, breaking a manual upload.\n if (uploadDisabled) {\n return;\n }\n\n // delete sourcemaps after upload\n let updatedFilesToDeleteAfterUpload = await sourcemaps?.filesToDeleteAfterUpload;\n\n // set a default value no option was set\n if (typeof updatedFilesToDeleteAfterUpload === 'undefined') {\n updatedFilesToDeleteAfterUpload = [`${reactRouterConfig.buildDirectory}/**/*.map`];\n debug &&\n // eslint-disable-next-line no-console\n console.info(\n `[Sentry] Automatically setting \\`sourcemaps.filesToDeleteAfterUpload: ${JSON.stringify(\n updatedFilesToDeleteAfterUpload,\n )}\\` to delete generated source maps after they were uploaded to Sentry.`,\n );\n }\n if (updatedFilesToDeleteAfterUpload) {\n try {\n const filePathsToDelete = await glob(updatedFilesToDeleteAfterUpload, {\n absolute: true,\n nodir: true,\n });\n if (debug) {\n filePathsToDelete.forEach(filePathToDelete => {\n // eslint-disable-next-line no-console\n console.info(`Deleting asset after upload: ${filePathToDelete}`);\n });\n }\n await Promise.all(\n filePathsToDelete.map(filePathToDelete =>\n rm(filePathToDelete, { force: true }).catch((e: unknown) => {\n // This is allowed to fail - we just don't do anything\n debug &&\n // eslint-disable-next-line no-console\n console.debug(`An error occurred while attempting to delete asset: ${filePathToDelete}`, e);\n }),\n ),\n );\n } catch (error) {\n // eslint-disable-next-line no-console\n console.error('Error deleting files after sourcemap upload:', error);\n }\n }\n};\n"],"names":["SentryCli","glob","rm"],"mappings":"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"}
|
|
@@ -273,7 +273,8 @@ function updateRootSpanRoute(routeName, hasPattern) {
|
|
|
273
273
|
if (!rootSpan) {
|
|
274
274
|
return;
|
|
275
275
|
}
|
|
276
|
-
const {
|
|
276
|
+
const { attributes } = spanToJSON(rootSpan);
|
|
277
|
+
const op = attributes[SENTRY_OP];
|
|
277
278
|
if (op !== "navigation" && op !== "pageload") {
|
|
278
279
|
return;
|
|
279
280
|
}
|
|
@@ -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 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":["result","client","navigationSpan"],"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 { attributes } = spanToJSON(rootSpan);\n const op = attributes[SENTRY_OP];\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":["result","client","navigationSpan"],"mappings":"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"}
|
|
@@ -3,7 +3,7 @@ import { GLOBAL_OBJ, spanToJSON, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, SEMANTIC_ATTR
|
|
|
3
3
|
import { DEBUG_BUILD } from '../common/debug-build.js';
|
|
4
4
|
import { isClientInstrumentationApiUsed } from './createClientInstrumentation.js';
|
|
5
5
|
import { getParameterizedRoute, normalizePathname, finalizeNavigationSpanFromRouterState, resolveNavigateAbsoluteUrl, resolveNavigateArg } from './utils.js';
|
|
6
|
-
import { URL_TEMPLATE, URL_PATH } from '@sentry/conventions/attributes';
|
|
6
|
+
import { URL_TEMPLATE, SENTRY_OP, URL_PATH } from '@sentry/conventions/attributes';
|
|
7
7
|
|
|
8
8
|
const GLOBAL_OBJ_WITH_DATA_ROUTER = GLOBAL_OBJ;
|
|
9
9
|
const WINDOW = GLOBAL_OBJ;
|
|
@@ -14,7 +14,7 @@ function instrumentHydratedRouter() {
|
|
|
14
14
|
if (router) {
|
|
15
15
|
const pageloadSpan = getActiveRootSpan();
|
|
16
16
|
if (pageloadSpan) {
|
|
17
|
-
const pageloadName = spanToJSON(pageloadSpan).
|
|
17
|
+
const pageloadName = spanToJSON(pageloadSpan).name;
|
|
18
18
|
const parameterizePageloadRoute = getParameterizedRoute(router.state);
|
|
19
19
|
if (pageloadName && // this event is for the currently active pageload
|
|
20
20
|
normalizePathname(router.state.location.pathname) === normalizePathname(pageloadName)) {
|
|
@@ -69,12 +69,13 @@ function instrumentHydratedRouter() {
|
|
|
69
69
|
return;
|
|
70
70
|
}
|
|
71
71
|
const rootSpanJson = spanToJSON(rootSpan);
|
|
72
|
-
|
|
72
|
+
const rootSpanAttributes = rootSpanJson.attributes;
|
|
73
|
+
if (rootSpanAttributes[SENTRY_OP] === "navigation" && isClientInstrumentationApiUsed() && rootSpanAttributes[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE] === "route") {
|
|
73
74
|
return;
|
|
74
75
|
}
|
|
75
|
-
const rootSpanName = rootSpanJson.
|
|
76
|
+
const rootSpanName = rootSpanJson.name;
|
|
76
77
|
const parameterizedRoute = getParameterizedRoute(newState);
|
|
77
|
-
const spanPathname =
|
|
78
|
+
const spanPathname = rootSpanAttributes[URL_PATH];
|
|
78
79
|
const destinationPathname = normalizePathname(newState.location.pathname);
|
|
79
80
|
if (rootSpanName && newState.navigation.state === "idle" && // navigation has completed
|
|
80
81
|
// this event is for the currently active root span
|
|
@@ -128,7 +129,7 @@ function getActiveRootSpan() {
|
|
|
128
129
|
return void 0;
|
|
129
130
|
}
|
|
130
131
|
const rootSpan = getRootSpan(activeSpan);
|
|
131
|
-
const op = spanToJSON(rootSpan).
|
|
132
|
+
const op = spanToJSON(rootSpan).attributes[SENTRY_OP];
|
|
132
133
|
return op === "navigation" || op === "pageload" ? rootSpan : void 0;
|
|
133
134
|
}
|
|
134
135
|
|
|
@@ -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({\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":[],"mappings":"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"}
|
|
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 { SENTRY_OP, 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).name;\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 const rootSpanAttributes = rootSpanJson.attributes;\n\n // When the instrumentation API is active, navigation roots are parameterized\n // by the native route hooks\n if (\n rootSpanAttributes[SENTRY_OP] === 'navigation' &&\n isClientInstrumentationApiUsed() &&\n rootSpanAttributes[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE] === 'route'\n ) {\n return;\n }\n\n const rootSpanName = rootSpanJson.name;\n const parameterizedRoute = getParameterizedRoute(newState);\n const spanPathname = rootSpanAttributes[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).attributes[SENTRY_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":[],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export * from '@sentry/node';
|
|
2
2
|
export { init } from './server/sdk.js';
|
|
3
|
-
export {
|
|
3
|
+
export { wrapSentryHandleRequest } from './server/wrapSentryHandleRequest.js';
|
|
4
4
|
export { createSentryHandleRequest } from './server/createSentryHandleRequest.js';
|
|
5
5
|
export { createSentryHandleError } from './server/createSentryHandleError.js';
|
|
6
6
|
export { getMetaTagTransformer } from './server/getMetaTagTransformer.js';
|
package/build/esm/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"type":"module","version":"11.0.0-alpha.
|
|
1
|
+
{"type":"module","version":"11.0.0-alpha.1"}
|
|
@@ -8,7 +8,7 @@ const LOW_QUALITY_TRANSACTIONS_FILTERS = [
|
|
|
8
8
|
// Filter by `http.target` instead, which carries the raw request path.
|
|
9
9
|
{ attributes: { "http.target": /\/__manifest/ } }
|
|
10
10
|
];
|
|
11
|
-
const _lowQualityTransactionsFilterIntegration = ((
|
|
11
|
+
const _lowQualityTransactionsFilterIntegration = (() => ({
|
|
12
12
|
name: "LowQualityTransactionsFilter",
|
|
13
13
|
beforeSetup(client) {
|
|
14
14
|
const opts = client.getOptions();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lowQualityTransactionsFilterIntegration.js","sources":["../../../../src/server/integration/lowQualityTransactionsFilterIntegration.ts"],"sourcesContent":["import type { IntegrationFn } from '@sentry/core';\nimport { defineIntegration } from '@sentry/core';\
|
|
1
|
+
{"version":3,"file":"lowQualityTransactionsFilterIntegration.js","sources":["../../../../src/server/integration/lowQualityTransactionsFilterIntegration.ts"],"sourcesContent":["import type { IntegrationFn } from '@sentry/core';\nimport { defineIntegration } from '@sentry/core';\n\nconst LOW_QUALITY_TRANSACTIONS_FILTERS = [\n /GET \\/node_modules\\//,\n /GET \\/favicon\\.ico/,\n /GET \\/@id\\//,\n // The span description for the `__manifest` endpoint is `GET *` (`http.route` resolves to `*`).\n // Filter by `http.target` instead, which carries the raw request path.\n { attributes: { 'http.target': /\\/__manifest/ } },\n];\n\nconst _lowQualityTransactionsFilterIntegration = (() => ({\n name: 'LowQualityTransactionsFilter' as const,\n beforeSetup(client) {\n const opts = client.getOptions();\n opts.ignoreSpans = [...(opts.ignoreSpans || []), ...LOW_QUALITY_TRANSACTIONS_FILTERS];\n },\n})) satisfies IntegrationFn;\n\n/**\n * Integration that filters out noisy http transactions such as requests to node_modules, favicon.ico, @id/, __manifest.\n * Adds entries to `ignoreSpans` so the filter applies in both static and streaming trace lifecycles.\n */\nexport const lowQualityTransactionsFilterIntegration = defineIntegration(_lowQualityTransactionsFilterIntegration);\n"],"names":[],"mappings":";;AAGA,MAAM,gCAAA,GAAmC;AAAA,EACvC,sBAAA;AAAA,EACA,oBAAA;AAAA,EACA,aAAA;AAAA;AAAA;AAAA,EAGA,EAAE,UAAA,EAAY,EAAE,aAAA,EAAe,gBAAe;AAChD,CAAA;AAEA,MAAM,4CAA4C,OAAO;AAAA,EACvD,IAAA,EAAM,8BAAA;AAAA,EACN,YAAY,MAAA,EAAQ;AAClB,IAAA,MAAM,IAAA,GAAO,OAAO,UAAA,EAAW;AAC/B,IAAA,IAAA,CAAK,WAAA,GAAc,CAAC,GAAI,IAAA,CAAK,eAAe,EAAC,EAAI,GAAG,gCAAgC,CAAA;AAAA,EACtF;AACF,CAAA,CAAA,CAAA;AAMO,MAAM,uCAAA,GAA0C,kBAAkB,wCAAwC;;;;"}
|
package/build/esm/server/sdk.js
CHANGED
|
@@ -7,7 +7,7 @@ import { reactRouterServerIntegration } from './integration/reactRouterServer.js
|
|
|
7
7
|
function getDefaultReactRouterServerIntegrations(options) {
|
|
8
8
|
return [
|
|
9
9
|
...getDefaultIntegrations(options),
|
|
10
|
-
lowQualityTransactionsFilterIntegration(
|
|
10
|
+
lowQualityTransactionsFilterIntegration(),
|
|
11
11
|
reactRouterServerIntegration()
|
|
12
12
|
];
|
|
13
13
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sdk.js","sources":["../../../src/server/sdk.ts"],"sourcesContent":["import type { Integration } from '@sentry/core';\nimport { applySdkMetadata, debug, setTag } from '@sentry/core';\nimport type { NodeClient, NodeOptions } from '@sentry/node';\nimport { getDefaultIntegrations as getNodeDefaultIntegrations, init as initNodeSdk } from '@sentry/node';\nimport { DEBUG_BUILD } from '../common/debug-build';\nimport { lowQualityTransactionsFilterIntegration } from './integration/lowQualityTransactionsFilterIntegration';\nimport { reactRouterServerIntegration } from './integration/reactRouterServer';\n\n/**\n * Returns the default integrations for the React Router SDK.\n * @param options The options for the SDK.\n */\nexport function getDefaultReactRouterServerIntegrations(options: NodeOptions): Integration[] {\n return [\n ...getNodeDefaultIntegrations(options),\n lowQualityTransactionsFilterIntegration(
|
|
1
|
+
{"version":3,"file":"sdk.js","sources":["../../../src/server/sdk.ts"],"sourcesContent":["import type { Integration } from '@sentry/core';\nimport { applySdkMetadata, debug, setTag } from '@sentry/core';\nimport type { NodeClient, NodeOptions } from '@sentry/node';\nimport { getDefaultIntegrations as getNodeDefaultIntegrations, init as initNodeSdk } from '@sentry/node';\nimport { DEBUG_BUILD } from '../common/debug-build';\nimport { lowQualityTransactionsFilterIntegration } from './integration/lowQualityTransactionsFilterIntegration';\nimport { reactRouterServerIntegration } from './integration/reactRouterServer';\n\n/**\n * Returns the default integrations for the React Router SDK.\n * @param options The options for the SDK.\n */\nexport function getDefaultReactRouterServerIntegrations(options: NodeOptions): Integration[] {\n return [\n ...getNodeDefaultIntegrations(options),\n lowQualityTransactionsFilterIntegration(),\n reactRouterServerIntegration(),\n ];\n}\n\n/**\n * Initializes the server side of the React Router SDK\n */\nexport function init(options: NodeOptions): NodeClient | undefined {\n const opts: NodeOptions = {\n ...options,\n defaultIntegrations: getDefaultReactRouterServerIntegrations(options),\n };\n\n DEBUG_BUILD && debug.log('Initializing SDK...');\n\n applySdkMetadata(opts, 'react-router', ['react-router', 'node']);\n\n const client = initNodeSdk(opts);\n\n setTag('runtime', 'node');\n\n DEBUG_BUILD && debug.log('SDK successfully initialized');\n\n return client;\n}\n"],"names":["getNodeDefaultIntegrations","initNodeSdk"],"mappings":";;;;;;AAYO,SAAS,wCAAwC,OAAA,EAAqC;AAC3F,EAAA,OAAO;AAAA,IACL,GAAGA,uBAA2B,OAAO,CAAA;AAAA,IACrC,uCAAA,EAAwC;AAAA,IACxC,4BAAA;AAA6B,GAC/B;AACF;AAKO,SAAS,KAAK,OAAA,EAA8C;AACjE,EAAA,MAAM,IAAA,GAAoB;AAAA,IACxB,GAAG,OAAA;AAAA,IACH,mBAAA,EAAqB,wCAAwC,OAAO;AAAA,GACtE;AAEA,EAAA,WAAA,IAAe,KAAA,CAAM,IAAI,qBAAqB,CAAA;AAE9C,EAAA,gBAAA,CAAiB,IAAA,EAAM,cAAA,EAAgB,CAAC,cAAA,EAAgB,MAAM,CAAC,CAAA;AAE/D,EAAA,MAAM,MAAA,GAASC,OAAY,IAAI,CAAA;AAE/B,EAAA,MAAA,CAAO,WAAW,MAAM,CAAA;AAExB,EAAA,WAAA,IAAe,KAAA,CAAM,IAAI,8BAA8B,CAAA;AAEvD,EAAA,OAAO,MAAA;AACT;;;;"}
|
|
@@ -51,7 +51,6 @@ function wrapSentryHandleRequest(originalHandle) {
|
|
|
51
51
|
}
|
|
52
52
|
};
|
|
53
53
|
}
|
|
54
|
-
const sentryHandleRequest = wrapSentryHandleRequest;
|
|
55
54
|
|
|
56
|
-
export {
|
|
55
|
+
export { wrapSentryHandleRequest };
|
|
57
56
|
//# sourceMappingURL=wrapSentryHandleRequest.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wrapSentryHandleRequest.js","sources":["../../../src/server/wrapSentryHandleRequest.ts"],"sourcesContent":["import { HTTP_ROUTE } from '@sentry/conventions/attributes';\nimport {\n flushIfServerless,\n getActiveSpan,\n getCurrentScope,\n getRootSpan,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n SEMANTIC_ATTRIBUTE_SENTRY_SOURCE,\n updateSpanName,\n} from '@sentry/core';\nimport type { AppLoadContext, EntryContext, RouterContextProvider } from 'react-router';\nimport { isInstrumentationApiUsed } from './serverGlobals';\n\ntype OriginalHandleRequestWithoutMiddleware = (\n request: Request,\n responseStatusCode: number,\n responseHeaders: Headers,\n routerContext: EntryContext,\n loadContext: AppLoadContext,\n) => Promise<unknown>;\n\ntype OriginalHandleRequestWithMiddleware = (\n request: Request,\n responseStatusCode: number,\n responseHeaders: Headers,\n routerContext: EntryContext,\n loadContext: RouterContextProvider,\n) => Promise<unknown>;\n\n/**\n * Wraps the original handleRequest function to add Sentry instrumentation.\n *\n * @param originalHandle - The original handleRequest function to wrap\n * @returns A wrapped version of the handle request function with Sentry instrumentation\n */\nexport function wrapSentryHandleRequest(\n originalHandle: OriginalHandleRequestWithoutMiddleware,\n): OriginalHandleRequestWithoutMiddleware;\n/**\n * Wraps the original handleRequest function to add Sentry instrumentation.\n *\n * @param originalHandle - The original handleRequest function to wrap\n * @returns A wrapped version of the handle request function with Sentry instrumentation\n */\nexport function wrapSentryHandleRequest(\n originalHandle: OriginalHandleRequestWithMiddleware,\n): OriginalHandleRequestWithMiddleware;\n/**\n * Wraps the original handleRequest function to add Sentry instrumentation.\n *\n * @param originalHandle - The original handleRequest function to wrap\n * @returns A wrapped version of the handle request function with Sentry instrumentation\n */\nexport function wrapSentryHandleRequest(\n originalHandle: OriginalHandleRequestWithoutMiddleware | OriginalHandleRequestWithMiddleware,\n): OriginalHandleRequestWithoutMiddleware | OriginalHandleRequestWithMiddleware {\n return async function sentryInstrumentedHandleRequest(\n request: Request,\n responseStatusCode: number,\n responseHeaders: Headers,\n routerContext: EntryContext,\n loadContext: AppLoadContext | RouterContextProvider,\n ) {\n const parameterizedPath =\n routerContext?.staticHandlerContext?.matches?.[routerContext.staticHandlerContext.matches.length - 1]?.route.path;\n\n const activeSpan = getActiveSpan();\n const rootSpan = activeSpan ? getRootSpan(activeSpan) : undefined;\n\n if (parameterizedPath && rootSpan) {\n // Normalize route name - avoid \"//\" for root routes\n const routeName = parameterizedPath.startsWith('/') ? parameterizedPath : `/${parameterizedPath}`;\n\n const transactionName = `${request.method} ${routeName}`;\n\n updateSpanName(rootSpan, transactionName);\n getCurrentScope().setTransactionName(transactionName);\n\n // Set route attributes - acts as fallback for lazy-only routes when using instrumentation API\n // Don't override origin when instrumentation API is used (preserve instrumentation_api origin)\n if (isInstrumentationApiUsed()) {\n rootSpan.setAttributes({\n [HTTP_ROUTE]: routeName,\n [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'route',\n });\n } else {\n rootSpan.setAttributes({\n [HTTP_ROUTE]: routeName,\n [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'route',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.react_router.request_handler',\n });\n }\n }\n\n try {\n // Type guard to call the correct overload based on loadContext type\n if (isRouterContextProvider(loadContext)) {\n // loadContext is RouterContextProvider\n return await (originalHandle as OriginalHandleRequestWithMiddleware)(\n request,\n responseStatusCode,\n responseHeaders,\n routerContext,\n loadContext,\n );\n } else {\n // loadContext is AppLoadContext\n return await (originalHandle as OriginalHandleRequestWithoutMiddleware)(\n request,\n responseStatusCode,\n responseHeaders,\n routerContext,\n loadContext,\n );\n }\n } finally {\n await flushIfServerless();\n }\n\n /**\n * Helper type guard to determine if the context is a RouterContextProvider.\n *\n * @param ctx - The context to check\n * @returns True if the context is a RouterContextProvider\n */\n function isRouterContextProvider(ctx: AppLoadContext | RouterContextProvider): ctx is RouterContextProvider {\n return typeof (ctx as RouterContextProvider)?.get === 'function';\n }\n };\n}\n
|
|
1
|
+
{"version":3,"file":"wrapSentryHandleRequest.js","sources":["../../../src/server/wrapSentryHandleRequest.ts"],"sourcesContent":["import { HTTP_ROUTE } from '@sentry/conventions/attributes';\nimport {\n flushIfServerless,\n getActiveSpan,\n getCurrentScope,\n getRootSpan,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n SEMANTIC_ATTRIBUTE_SENTRY_SOURCE,\n updateSpanName,\n} from '@sentry/core';\nimport type { AppLoadContext, EntryContext, RouterContextProvider } from 'react-router';\nimport { isInstrumentationApiUsed } from './serverGlobals';\n\ntype OriginalHandleRequestWithoutMiddleware = (\n request: Request,\n responseStatusCode: number,\n responseHeaders: Headers,\n routerContext: EntryContext,\n loadContext: AppLoadContext,\n) => Promise<unknown>;\n\ntype OriginalHandleRequestWithMiddleware = (\n request: Request,\n responseStatusCode: number,\n responseHeaders: Headers,\n routerContext: EntryContext,\n loadContext: RouterContextProvider,\n) => Promise<unknown>;\n\n/**\n * Wraps the original handleRequest function to add Sentry instrumentation.\n *\n * @param originalHandle - The original handleRequest function to wrap\n * @returns A wrapped version of the handle request function with Sentry instrumentation\n */\nexport function wrapSentryHandleRequest(\n originalHandle: OriginalHandleRequestWithoutMiddleware,\n): OriginalHandleRequestWithoutMiddleware;\n/**\n * Wraps the original handleRequest function to add Sentry instrumentation.\n *\n * @param originalHandle - The original handleRequest function to wrap\n * @returns A wrapped version of the handle request function with Sentry instrumentation\n */\nexport function wrapSentryHandleRequest(\n originalHandle: OriginalHandleRequestWithMiddleware,\n): OriginalHandleRequestWithMiddleware;\n/**\n * Wraps the original handleRequest function to add Sentry instrumentation.\n *\n * @param originalHandle - The original handleRequest function to wrap\n * @returns A wrapped version of the handle request function with Sentry instrumentation\n */\nexport function wrapSentryHandleRequest(\n originalHandle: OriginalHandleRequestWithoutMiddleware | OriginalHandleRequestWithMiddleware,\n): OriginalHandleRequestWithoutMiddleware | OriginalHandleRequestWithMiddleware {\n return async function sentryInstrumentedHandleRequest(\n request: Request,\n responseStatusCode: number,\n responseHeaders: Headers,\n routerContext: EntryContext,\n loadContext: AppLoadContext | RouterContextProvider,\n ) {\n const parameterizedPath =\n routerContext?.staticHandlerContext?.matches?.[routerContext.staticHandlerContext.matches.length - 1]?.route.path;\n\n const activeSpan = getActiveSpan();\n const rootSpan = activeSpan ? getRootSpan(activeSpan) : undefined;\n\n if (parameterizedPath && rootSpan) {\n // Normalize route name - avoid \"//\" for root routes\n const routeName = parameterizedPath.startsWith('/') ? parameterizedPath : `/${parameterizedPath}`;\n\n const transactionName = `${request.method} ${routeName}`;\n\n updateSpanName(rootSpan, transactionName);\n getCurrentScope().setTransactionName(transactionName);\n\n // Set route attributes - acts as fallback for lazy-only routes when using instrumentation API\n // Don't override origin when instrumentation API is used (preserve instrumentation_api origin)\n if (isInstrumentationApiUsed()) {\n rootSpan.setAttributes({\n [HTTP_ROUTE]: routeName,\n [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'route',\n });\n } else {\n rootSpan.setAttributes({\n [HTTP_ROUTE]: routeName,\n [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'route',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.react_router.request_handler',\n });\n }\n }\n\n try {\n // Type guard to call the correct overload based on loadContext type\n if (isRouterContextProvider(loadContext)) {\n // loadContext is RouterContextProvider\n return await (originalHandle as OriginalHandleRequestWithMiddleware)(\n request,\n responseStatusCode,\n responseHeaders,\n routerContext,\n loadContext,\n );\n } else {\n // loadContext is AppLoadContext\n return await (originalHandle as OriginalHandleRequestWithoutMiddleware)(\n request,\n responseStatusCode,\n responseHeaders,\n routerContext,\n loadContext,\n );\n }\n } finally {\n await flushIfServerless();\n }\n\n /**\n * Helper type guard to determine if the context is a RouterContextProvider.\n *\n * @param ctx - The context to check\n * @returns True if the context is a RouterContextProvider\n */\n function isRouterContextProvider(ctx: AppLoadContext | RouterContextProvider): ctx is RouterContextProvider {\n return typeof (ctx as RouterContextProvider)?.get === 'function';\n }\n };\n}\n"],"names":[],"mappings":";;;;AAqDO,SAAS,wBACd,cAAA,EAC8E;AAC9E,EAAA,OAAO,eAAe,+BAAA,CACpB,OAAA,EACA,kBAAA,EACA,eAAA,EACA,eACA,WAAA,EACA;AACA,IAAA,MAAM,iBAAA,GACJ,aAAA,EAAe,oBAAA,EAAsB,OAAA,GAAU,aAAA,CAAc,qBAAqB,OAAA,CAAQ,MAAA,GAAS,CAAC,CAAA,EAAG,KAAA,CAAM,IAAA;AAE/G,IAAA,MAAM,aAAa,aAAA,EAAc;AACjC,IAAA,MAAM,QAAA,GAAW,UAAA,GAAa,WAAA,CAAY,UAAU,CAAA,GAAI,MAAA;AAExD,IAAA,IAAI,qBAAqB,QAAA,EAAU;AAEjC,MAAA,MAAM,YAAY,iBAAA,CAAkB,UAAA,CAAW,GAAG,CAAA,GAAI,iBAAA,GAAoB,IAAI,iBAAiB,CAAA,CAAA;AAE/F,MAAA,MAAM,eAAA,GAAkB,CAAA,EAAG,OAAA,CAAQ,MAAM,IAAI,SAAS,CAAA,CAAA;AAEtD,MAAA,cAAA,CAAe,UAAU,eAAe,CAAA;AACxC,MAAA,eAAA,EAAgB,CAAE,mBAAmB,eAAe,CAAA;AAIpD,MAAA,IAAI,0BAAyB,EAAG;AAC9B,QAAA,QAAA,CAAS,aAAA,CAAc;AAAA,UACrB,CAAC,UAAU,GAAG,SAAA;AAAA,UACd,CAAC,gCAAgC,GAAG;AAAA,SACrC,CAAA;AAAA,MACH,CAAA,MAAO;AACL,QAAA,QAAA,CAAS,aAAA,CAAc;AAAA,UACrB,CAAC,UAAU,GAAG,SAAA;AAAA,UACd,CAAC,gCAAgC,GAAG,OAAA;AAAA,UACpC,CAAC,gCAAgC,GAAG;AAAA,SACrC,CAAA;AAAA,MACH;AAAA,IACF;AAEA,IAAA,IAAI;AAEF,MAAA,IAAI,uBAAA,CAAwB,WAAW,CAAA,EAAG;AAExC,QAAA,OAAO,MAAO,cAAA;AAAA,UACZ,OAAA;AAAA,UACA,kBAAA;AAAA,UACA,eAAA;AAAA,UACA,aAAA;AAAA,UACA;AAAA,SACF;AAAA,MACF,CAAA,MAAO;AAEL,QAAA,OAAO,MAAO,cAAA;AAAA,UACZ,OAAA;AAAA,UACA,kBAAA;AAAA,UACA,eAAA;AAAA,UACA,aAAA;AAAA,UACA;AAAA,SACF;AAAA,MACF;AAAA,IACF,CAAA,SAAE;AACA,MAAA,MAAM,iBAAA,EAAkB;AAAA,IAC1B;AAQA,IAAA,SAAS,wBAAwB,GAAA,EAA2E;AAC1G,MAAA,OAAO,OAAQ,KAA+B,GAAA,KAAQ,UAAA;AAAA,IACxD;AAAA,EACF,CAAA;AACF;;;;"}
|
|
@@ -9,18 +9,10 @@ function getSentryConfig(viteConfig) {
|
|
|
9
9
|
return viteConfig.sentryConfig;
|
|
10
10
|
}
|
|
11
11
|
function resolveSourceMapsDisable(sentryConfig) {
|
|
12
|
-
if (sentryConfig.sourceMapsUploadOptions?.enabled === false) {
|
|
13
|
-
return true;
|
|
14
|
-
}
|
|
15
12
|
return sentryConfig.sourcemaps?.disable ?? sentryConfig.unstable_sentryVitePluginOptions?.sourcemaps?.disable;
|
|
16
13
|
}
|
|
17
14
|
const sentryOnBuildEnd = async ({ reactRouterConfig, viteConfig }) => {
|
|
18
15
|
const sentryConfig = getSentryConfig(viteConfig);
|
|
19
|
-
const {
|
|
20
|
-
sourceMapsUploadOptions,
|
|
21
|
-
// extract to exclude from rest config
|
|
22
|
-
...sentryConfigWithoutDeprecatedSourceMapOption
|
|
23
|
-
} = sentryConfig;
|
|
24
16
|
const unstableSentryVitePluginOptions = sentryConfig.unstable_sentryVitePluginOptions;
|
|
25
17
|
const {
|
|
26
18
|
authToken,
|
|
@@ -31,19 +23,17 @@ const sentryOnBuildEnd = async ({ reactRouterConfig, viteConfig }) => {
|
|
|
31
23
|
debug = false
|
|
32
24
|
} = {
|
|
33
25
|
...unstableSentryVitePluginOptions,
|
|
34
|
-
...
|
|
35
|
-
// spread in the config without the deprecated sourceMapsUploadOptions
|
|
26
|
+
...sentryConfig,
|
|
36
27
|
sourcemaps: {
|
|
37
28
|
...unstableSentryVitePluginOptions?.sourcemaps,
|
|
38
29
|
...sentryConfig.sourcemaps,
|
|
39
|
-
...sourceMapsUploadOptions,
|
|
40
30
|
disable: resolveSourceMapsDisable(sentryConfig)
|
|
41
31
|
},
|
|
42
32
|
release: {
|
|
43
33
|
...unstableSentryVitePluginOptions?.release,
|
|
44
34
|
...sentryConfig.release
|
|
45
35
|
},
|
|
46
|
-
project: unstableSentryVitePluginOptions?.project ? Array.isArray(unstableSentryVitePluginOptions?.project) ? unstableSentryVitePluginOptions?.project[0] : unstableSentryVitePluginOptions?.project :
|
|
36
|
+
project: unstableSentryVitePluginOptions?.project ? Array.isArray(unstableSentryVitePluginOptions?.project) ? unstableSentryVitePluginOptions?.project[0] : unstableSentryVitePluginOptions?.project : sentryConfig.project
|
|
47
37
|
};
|
|
48
38
|
const cliInstance = new SentryCli(null, {
|
|
49
39
|
authToken,
|
|
@@ -93,7 +83,7 @@ const sentryOnBuildEnd = async ({ reactRouterConfig, viteConfig }) => {
|
|
|
93
83
|
updatedFilesToDeleteAfterUpload = [`${reactRouterConfig.buildDirectory}/**/*.map`];
|
|
94
84
|
debug && // eslint-disable-next-line no-console
|
|
95
85
|
console.info(
|
|
96
|
-
`[Sentry] Automatically setting \`
|
|
86
|
+
`[Sentry] Automatically setting \`sourcemaps.filesToDeleteAfterUpload: ${JSON.stringify(
|
|
97
87
|
updatedFilesToDeleteAfterUpload
|
|
98
88
|
)}\` to delete generated source maps after they were uploaded to Sentry.`
|
|
99
89
|
);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handleOnBuildEnd.js","sources":["../../../../src/vite/buildEnd/handleOnBuildEnd.ts"],"sourcesContent":["import { rm } from 'node:fs/promises';\nimport type { Config } from '@react-router/dev/config';\nimport SentryCli from '@sentry/cli';\nimport type { SentryVitePluginOptions } from '@sentry/bundler-plugins/vite';\nimport { glob } from 'glob';\nimport type { SentryReactRouterBuildOptions } from '../types';\n\ntype BuildEndHook = NonNullable<Config['buildEnd']>;\n\nfunction getSentryConfig(viteConfig: unknown): SentryReactRouterBuildOptions {\n if (!viteConfig || typeof viteConfig !== 'object' || !('sentryConfig' in viteConfig)) {\n // eslint-disable-next-line no-console\n console.error('[Sentry] sentryConfig not found - it needs to be passed to vite.config.ts');\n }\n\n return (viteConfig as { sentryConfig: SentryReactRouterBuildOptions }).sentryConfig;\n}\n\n/**\n * This hook is the only place that injects debug IDs and uploads source maps for React\n * Router, so `disable` has to be honoured wherever the user set it. Reading it from the\n * top-level config only would silently ignore `unstable_sentryVitePluginOptions`.\n */\nfunction resolveSourceMapsDisable(sentryConfig: SentryReactRouterBuildOptions): boolean | 'disable-upload' | undefined {\n // eslint-disable-next-line typescript/no-deprecated\n if (sentryConfig.sourceMapsUploadOptions?.enabled === false) {\n return true;\n }\n\n return sentryConfig.sourcemaps?.disable ?? sentryConfig.unstable_sentryVitePluginOptions?.sourcemaps?.disable;\n}\n\n/**\n * A build end hook that handles Sentry release creation and source map uploads.\n * It creates a new Sentry release if configured, uploads source maps to Sentry,\n * and optionally deletes the source map files after upload.\n */\nexport const sentryOnBuildEnd: BuildEndHook = async ({ reactRouterConfig, viteConfig }) => {\n const sentryConfig = getSentryConfig(viteConfig);\n\n // todo(v11): Remove deprecated sourceMapsUploadOptions support (no need for spread/pick anymore)\n const {\n sourceMapsUploadOptions, // extract to exclude from rest config\n ...sentryConfigWithoutDeprecatedSourceMapOption\n } = sentryConfig;\n\n const unstableSentryVitePluginOptions = sentryConfig.unstable_sentryVitePluginOptions;\n\n const {\n authToken,\n org,\n project,\n release,\n sourcemaps = { disable: false },\n debug = false,\n }: Omit<SentryReactRouterBuildOptions, 'sourcemaps' | 'sourceMapsUploadOptions'> &\n // Pick 'sourcemaps' from Vite plugin options as the types allow more (e.g. Promise values for `deleteFilesAfterUpload`)\n Pick<SentryVitePluginOptions, 'sourcemaps'> = {\n ...unstableSentryVitePluginOptions,\n ...sentryConfigWithoutDeprecatedSourceMapOption, // spread in the config without the deprecated sourceMapsUploadOptions\n sourcemaps: {\n ...unstableSentryVitePluginOptions?.sourcemaps,\n ...sentryConfig.sourcemaps,\n ...sourceMapsUploadOptions,\n disable: resolveSourceMapsDisable(sentryConfig),\n },\n release: {\n ...unstableSentryVitePluginOptions?.release,\n ...sentryConfig.release,\n },\n project: unstableSentryVitePluginOptions?.project\n ? Array.isArray(unstableSentryVitePluginOptions?.project)\n ? unstableSentryVitePluginOptions?.project[0]\n : unstableSentryVitePluginOptions?.project\n : sentryConfigWithoutDeprecatedSourceMapOption.project,\n };\n\n const cliInstance = new SentryCli(null, {\n authToken,\n org,\n ...sentryConfig.unstable_sentryVitePluginOptions,\n // same handling as in bundler plugins: https://github.com/getsentry/sentry-javascript-bundler-plugins/blob/05084f214c763a05137d863ff5a05ef38254f68d/packages/bundler-plugin-core/src/build-plugin-manager.ts#L102-L103\n project: Array.isArray(project) ? project[0] : project,\n });\n\n // check if release should be created\n if (release?.name) {\n try {\n await cliInstance.releases.new(release.name);\n } catch (error) {\n // eslint-disable-next-line no-console\n console.error('[Sentry] Could not create release', error);\n }\n }\n\n // `disable: 'disable-upload'` still injects debug IDs, so that source maps can be\n // uploaded manually at a later point - only `true` turns source maps off entirely.\n const sourceMapsFullyDisabled = sourcemaps?.disable === true;\n const uploadDisabled = sourceMapsFullyDisabled || sourcemaps?.disable === 'disable-upload';\n\n if (!sourceMapsFullyDisabled && viteConfig.build.sourcemap !== false) {\n // inject debugIds\n try {\n await cliInstance.execute(\n ['sourcemaps', 'inject', reactRouterConfig.buildDirectory],\n debug ? 'rejectOnError' : false,\n );\n } catch (error) {\n // eslint-disable-next-line no-console\n console.error('[Sentry] Could not inject debug ids', error);\n }\n\n if (!uploadDisabled) {\n // upload sourcemaps\n try {\n await cliInstance.releases.uploadSourceMaps(release?.name || 'undefined', {\n include: [\n {\n paths: [reactRouterConfig.buildDirectory],\n },\n ],\n live: 'rejectOnError',\n });\n } catch (error) {\n // eslint-disable-next-line no-console\n console.error('[Sentry] Could not upload sourcemaps', error);\n }\n }\n }\n\n // Only clean up source maps that were actually uploaded. Deleting them after skipping\n // the upload would leave the user with neither, breaking a manual upload.\n if (uploadDisabled) {\n return;\n }\n\n // delete sourcemaps after upload\n let updatedFilesToDeleteAfterUpload = await sourcemaps?.filesToDeleteAfterUpload;\n\n // set a default value no option was set\n if (typeof updatedFilesToDeleteAfterUpload === 'undefined') {\n updatedFilesToDeleteAfterUpload = [`${reactRouterConfig.buildDirectory}/**/*.map`];\n debug &&\n // eslint-disable-next-line no-console\n console.info(\n `[Sentry] Automatically setting \\`sourceMapsUploadOptions.filesToDeleteAfterUpload: ${JSON.stringify(\n updatedFilesToDeleteAfterUpload,\n )}\\` to delete generated source maps after they were uploaded to Sentry.`,\n );\n }\n if (updatedFilesToDeleteAfterUpload) {\n try {\n const filePathsToDelete = await glob(updatedFilesToDeleteAfterUpload, {\n absolute: true,\n nodir: true,\n });\n if (debug) {\n filePathsToDelete.forEach(filePathToDelete => {\n // eslint-disable-next-line no-console\n console.info(`Deleting asset after upload: ${filePathToDelete}`);\n });\n }\n await Promise.all(\n filePathsToDelete.map(filePathToDelete =>\n rm(filePathToDelete, { force: true }).catch((e: unknown) => {\n // This is allowed to fail - we just don't do anything\n debug &&\n // eslint-disable-next-line no-console\n console.debug(`An error occurred while attempting to delete asset: ${filePathToDelete}`, e);\n }),\n ),\n );\n } catch (error) {\n // eslint-disable-next-line no-console\n console.error('Error deleting files after sourcemap upload:', error);\n }\n }\n};\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"handleOnBuildEnd.js","sources":["../../../../src/vite/buildEnd/handleOnBuildEnd.ts"],"sourcesContent":["import { rm } from 'node:fs/promises';\nimport type { Config } from '@react-router/dev/config';\nimport SentryCli from '@sentry/cli';\nimport type { SentryVitePluginOptions } from '@sentry/bundler-plugins/vite';\nimport { glob } from 'glob';\nimport type { SentryReactRouterBuildOptions } from '../types';\n\ntype BuildEndHook = NonNullable<Config['buildEnd']>;\n\nfunction getSentryConfig(viteConfig: unknown): SentryReactRouterBuildOptions {\n if (!viteConfig || typeof viteConfig !== 'object' || !('sentryConfig' in viteConfig)) {\n // eslint-disable-next-line no-console\n console.error('[Sentry] sentryConfig not found - it needs to be passed to vite.config.ts');\n }\n\n return (viteConfig as { sentryConfig: SentryReactRouterBuildOptions }).sentryConfig;\n}\n\n/**\n * This hook is the only place that injects debug IDs and uploads source maps for React\n * Router, so `disable` has to be honoured wherever the user set it. Reading it from the\n * top-level config only would silently ignore `unstable_sentryVitePluginOptions`.\n */\nfunction resolveSourceMapsDisable(sentryConfig: SentryReactRouterBuildOptions): boolean | 'disable-upload' | undefined {\n return sentryConfig.sourcemaps?.disable ?? sentryConfig.unstable_sentryVitePluginOptions?.sourcemaps?.disable;\n}\n\n/**\n * A build end hook that handles Sentry release creation and source map uploads.\n * It creates a new Sentry release if configured, uploads source maps to Sentry,\n * and optionally deletes the source map files after upload.\n */\nexport const sentryOnBuildEnd: BuildEndHook = async ({ reactRouterConfig, viteConfig }) => {\n const sentryConfig = getSentryConfig(viteConfig);\n\n const unstableSentryVitePluginOptions = sentryConfig.unstable_sentryVitePluginOptions;\n\n const {\n authToken,\n org,\n project,\n release,\n sourcemaps = { disable: false },\n debug = false,\n }: Omit<SentryReactRouterBuildOptions, 'sourcemaps'> &\n // Pick 'sourcemaps' from Vite plugin options as the types allow more (e.g. Promise values for `deleteFilesAfterUpload`)\n Pick<SentryVitePluginOptions, 'sourcemaps'> = {\n ...unstableSentryVitePluginOptions,\n ...sentryConfig,\n sourcemaps: {\n ...unstableSentryVitePluginOptions?.sourcemaps,\n ...sentryConfig.sourcemaps,\n disable: resolveSourceMapsDisable(sentryConfig),\n },\n release: {\n ...unstableSentryVitePluginOptions?.release,\n ...sentryConfig.release,\n },\n project: unstableSentryVitePluginOptions?.project\n ? Array.isArray(unstableSentryVitePluginOptions?.project)\n ? unstableSentryVitePluginOptions?.project[0]\n : unstableSentryVitePluginOptions?.project\n : sentryConfig.project,\n };\n\n const cliInstance = new SentryCli(null, {\n authToken,\n org,\n ...sentryConfig.unstable_sentryVitePluginOptions,\n // same handling as in bundler plugins: https://github.com/getsentry/sentry-javascript-bundler-plugins/blob/05084f214c763a05137d863ff5a05ef38254f68d/packages/bundler-plugin-core/src/build-plugin-manager.ts#L102-L103\n project: Array.isArray(project) ? project[0] : project,\n });\n\n // check if release should be created\n if (release?.name) {\n try {\n await cliInstance.releases.new(release.name);\n } catch (error) {\n // eslint-disable-next-line no-console\n console.error('[Sentry] Could not create release', error);\n }\n }\n\n // `disable: 'disable-upload'` still injects debug IDs, so that source maps can be\n // uploaded manually at a later point - only `true` turns source maps off entirely.\n const sourceMapsFullyDisabled = sourcemaps?.disable === true;\n const uploadDisabled = sourceMapsFullyDisabled || sourcemaps?.disable === 'disable-upload';\n\n if (!sourceMapsFullyDisabled && viteConfig.build.sourcemap !== false) {\n // inject debugIds\n try {\n await cliInstance.execute(\n ['sourcemaps', 'inject', reactRouterConfig.buildDirectory],\n debug ? 'rejectOnError' : false,\n );\n } catch (error) {\n // eslint-disable-next-line no-console\n console.error('[Sentry] Could not inject debug ids', error);\n }\n\n if (!uploadDisabled) {\n // upload sourcemaps\n try {\n await cliInstance.releases.uploadSourceMaps(release?.name || 'undefined', {\n include: [\n {\n paths: [reactRouterConfig.buildDirectory],\n },\n ],\n live: 'rejectOnError',\n });\n } catch (error) {\n // eslint-disable-next-line no-console\n console.error('[Sentry] Could not upload sourcemaps', error);\n }\n }\n }\n\n // Only clean up source maps that were actually uploaded. Deleting them after skipping\n // the upload would leave the user with neither, breaking a manual upload.\n if (uploadDisabled) {\n return;\n }\n\n // delete sourcemaps after upload\n let updatedFilesToDeleteAfterUpload = await sourcemaps?.filesToDeleteAfterUpload;\n\n // set a default value no option was set\n if (typeof updatedFilesToDeleteAfterUpload === 'undefined') {\n updatedFilesToDeleteAfterUpload = [`${reactRouterConfig.buildDirectory}/**/*.map`];\n debug &&\n // eslint-disable-next-line no-console\n console.info(\n `[Sentry] Automatically setting \\`sourcemaps.filesToDeleteAfterUpload: ${JSON.stringify(\n updatedFilesToDeleteAfterUpload,\n )}\\` to delete generated source maps after they were uploaded to Sentry.`,\n );\n }\n if (updatedFilesToDeleteAfterUpload) {\n try {\n const filePathsToDelete = await glob(updatedFilesToDeleteAfterUpload, {\n absolute: true,\n nodir: true,\n });\n if (debug) {\n filePathsToDelete.forEach(filePathToDelete => {\n // eslint-disable-next-line no-console\n console.info(`Deleting asset after upload: ${filePathToDelete}`);\n });\n }\n await Promise.all(\n filePathsToDelete.map(filePathToDelete =>\n rm(filePathToDelete, { force: true }).catch((e: unknown) => {\n // This is allowed to fail - we just don't do anything\n debug &&\n // eslint-disable-next-line no-console\n console.debug(`An error occurred while attempting to delete asset: ${filePathToDelete}`, e);\n }),\n ),\n );\n } catch (error) {\n // eslint-disable-next-line no-console\n console.error('Error deleting files after sourcemap upload:', error);\n }\n }\n};\n"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createClientInstrumentation.d.ts","sourceRoot":"","sources":["../../../src/client/createClientInstrumentation.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAE,qBAAqB,EAA6C,MAAM,iBAAiB,CAAC;AAgCxG;;GAEG;AACH,MAAM,WAAW,wCAAwC;IACvD;;;;OAIG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED;;GAEG;AACH,wBAAgB,iCAAiC,CAC/C,OAAO,GAAE,wCAA6C,GACrD,qBAAqB,CAuSvB;
|
|
1
|
+
{"version":3,"file":"createClientInstrumentation.d.ts","sourceRoot":"","sources":["../../../src/client/createClientInstrumentation.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAE,qBAAqB,EAA6C,MAAM,iBAAiB,CAAC;AAgCxG;;GAEG;AACH,MAAM,WAAW,wCAAwC;IACvD;;;;OAIG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED;;GAEG;AACH,wBAAgB,iCAAiC,CAC/C,OAAO,GAAE,wCAA6C,GACrD,qBAAqB,CAuSvB;AA2BD;;GAEG;AACH,wBAAgB,8BAA8B,IAAI,OAAO,CAExD;AAED;;GAEG;AACH,wBAAgB,qBAAqB,IAAI,OAAO,CAE/C"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hydratedRouter.d.ts","sourceRoot":"","sources":["../../../src/client/hydratedRouter.ts"],"names":[],"mappings":"AAkCA;;;;;;;GAOG;AACH,wBAAgB,wBAAwB,IAAI,IAAI,
|
|
1
|
+
{"version":3,"file":"hydratedRouter.d.ts","sourceRoot":"","sources":["../../../src/client/hydratedRouter.ts"],"names":[],"mappings":"AAkCA;;;;;;;GAOG;AACH,wBAAgB,wBAAwB,IAAI,IAAI,CAwI/C"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export * from '@sentry/node';
|
|
2
2
|
export { init } from './sdk';
|
|
3
|
-
export { wrapSentryHandleRequest
|
|
3
|
+
export { wrapSentryHandleRequest } from './wrapSentryHandleRequest';
|
|
4
4
|
export { createSentryHandleRequest, type SentryHandleRequestOptions } from './createSentryHandleRequest';
|
|
5
5
|
export { createSentryHandleError, type SentryHandleErrorOptions } from './createSentryHandleError';
|
|
6
6
|
export { getMetaTagTransformer } from './getMetaTagTransformer';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/server/index.ts"],"names":[],"mappings":"AAGA,cAAc,cAAc,CAAC;AAE7B,OAAO,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/server/index.ts"],"names":[],"mappings":"AAGA,cAAc,cAAc,CAAC;AAE7B,OAAO,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC;AAC7B,OAAO,EAAE,uBAAuB,EAAE,MAAM,2BAA2B,CAAC;AACpE,OAAO,EAAE,yBAAyB,EAAE,KAAK,0BAA0B,EAAE,MAAM,6BAA6B,CAAC;AACzG,OAAO,EAAE,uBAAuB,EAAE,KAAK,wBAAwB,EAAE,MAAM,2BAA2B,CAAC;AACnG,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAGhE,OAAO,EACL,iCAAiC,EACjC,wBAAwB,EACxB,KAAK,wCAAwC,GAC9C,MAAM,+BAA+B,CAAC"}
|
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import type { NodeOptions } from '@sentry/node';
|
|
2
1
|
/**
|
|
3
2
|
* Integration that filters out noisy http transactions such as requests to node_modules, favicon.ico, @id/, __manifest.
|
|
4
3
|
* Adds entries to `ignoreSpans` so the filter applies in both static and streaming trace lifecycles.
|
|
5
4
|
*/
|
|
6
|
-
export declare const lowQualityTransactionsFilterIntegration: (
|
|
5
|
+
export declare const lowQualityTransactionsFilterIntegration: () => import("@sentry/core").Integration & {
|
|
7
6
|
name: "LowQualityTransactionsFilter";
|
|
8
7
|
};
|
|
9
8
|
//# sourceMappingURL=lowQualityTransactionsFilterIntegration.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lowQualityTransactionsFilterIntegration.d.ts","sourceRoot":"","sources":["../../../../src/server/integration/lowQualityTransactionsFilterIntegration.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"lowQualityTransactionsFilterIntegration.d.ts","sourceRoot":"","sources":["../../../../src/server/integration/lowQualityTransactionsFilterIntegration.ts"],"names":[],"mappings":"AAoBA;;;GAGG;AACH,eAAO,MAAM,uCAAuC;;CAA8D,CAAC"}
|
|
@@ -15,7 +15,5 @@ export declare function wrapSentryHandleRequest(originalHandle: OriginalHandleRe
|
|
|
15
15
|
* @returns A wrapped version of the handle request function with Sentry instrumentation
|
|
16
16
|
*/
|
|
17
17
|
export declare function wrapSentryHandleRequest(originalHandle: OriginalHandleRequestWithMiddleware): OriginalHandleRequestWithMiddleware;
|
|
18
|
-
/** @deprecated Use `wrapSentryHandleRequest` instead. */
|
|
19
|
-
export declare const sentryHandleRequest: typeof wrapSentryHandleRequest;
|
|
20
18
|
export {};
|
|
21
19
|
//# sourceMappingURL=wrapSentryHandleRequest.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wrapSentryHandleRequest.d.ts","sourceRoot":"","sources":["../../../src/server/wrapSentryHandleRequest.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,cAAc,EAAE,YAAY,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AAGxF,KAAK,sCAAsC,GAAG,CAC5C,OAAO,EAAE,OAAO,EAChB,kBAAkB,EAAE,MAAM,EAC1B,eAAe,EAAE,OAAO,EACxB,aAAa,EAAE,YAAY,EAC3B,WAAW,EAAE,cAAc,KACxB,OAAO,CAAC,OAAO,CAAC,CAAC;AAEtB,KAAK,mCAAmC,GAAG,CACzC,OAAO,EAAE,OAAO,EAChB,kBAAkB,EAAE,MAAM,EAC1B,eAAe,EAAE,OAAO,EACxB,aAAa,EAAE,YAAY,EAC3B,WAAW,EAAE,qBAAqB,KAC/B,OAAO,CAAC,OAAO,CAAC,CAAC;AAEtB;;;;;GAKG;AACH,wBAAgB,uBAAuB,CACrC,cAAc,EAAE,sCAAsC,GACrD,sCAAsC,CAAC;AAC1C;;;;;GAKG;AACH,wBAAgB,uBAAuB,CACrC,cAAc,EAAE,mCAAmC,GAClD,mCAAmC,CAAC
|
|
1
|
+
{"version":3,"file":"wrapSentryHandleRequest.d.ts","sourceRoot":"","sources":["../../../src/server/wrapSentryHandleRequest.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,cAAc,EAAE,YAAY,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AAGxF,KAAK,sCAAsC,GAAG,CAC5C,OAAO,EAAE,OAAO,EAChB,kBAAkB,EAAE,MAAM,EAC1B,eAAe,EAAE,OAAO,EACxB,aAAa,EAAE,YAAY,EAC3B,WAAW,EAAE,cAAc,KACxB,OAAO,CAAC,OAAO,CAAC,CAAC;AAEtB,KAAK,mCAAmC,GAAG,CACzC,OAAO,EAAE,OAAO,EAChB,kBAAkB,EAAE,MAAM,EAC1B,eAAe,EAAE,OAAO,EACxB,aAAa,EAAE,YAAY,EAC3B,WAAW,EAAE,qBAAqB,KAC/B,OAAO,CAAC,OAAO,CAAC,CAAC;AAEtB;;;;;GAKG;AACH,wBAAgB,uBAAuB,CACrC,cAAc,EAAE,sCAAsC,GACrD,sCAAsC,CAAC;AAC1C;;;;;GAKG;AACH,wBAAgB,uBAAuB,CACrC,cAAc,EAAE,mCAAmC,GAClD,mCAAmC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handleOnBuildEnd.d.ts","sourceRoot":"","sources":["../../../../src/vite/buildEnd/handleOnBuildEnd.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,0BAA0B,CAAC;AAMvD,KAAK,YAAY,GAAG,WAAW,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"handleOnBuildEnd.d.ts","sourceRoot":"","sources":["../../../../src/vite/buildEnd/handleOnBuildEnd.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,0BAA0B,CAAC;AAMvD,KAAK,YAAY,GAAG,WAAW,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC;AAoBpD;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,EAAE,YAqI9B,CAAC"}
|
|
@@ -1,47 +1,5 @@
|
|
|
1
1
|
import type { BuildTimeOptionsBase, UnstableVitePluginOptions } from '@sentry/core';
|
|
2
2
|
import type { SentryVitePluginOptions } from '@sentry/bundler-plugins/vite';
|
|
3
|
-
type SourceMapsOptions = {
|
|
4
|
-
/**
|
|
5
|
-
* If this flag is `true`, and an auth token is detected, the Sentry SDK will
|
|
6
|
-
* automatically generate and upload source maps to Sentry during a production build.
|
|
7
|
-
*
|
|
8
|
-
* @default true
|
|
9
|
-
* @deprecated Use `sourcemaps.disable` option instead of `sourceMapsUploadOptions.enabled`.
|
|
10
|
-
*/
|
|
11
|
-
enabled?: boolean;
|
|
12
|
-
/**
|
|
13
|
-
* A glob or an array of globs that specifies the build artifacts that should be deleted after the artifact
|
|
14
|
-
* upload to Sentry has been completed.
|
|
15
|
-
*
|
|
16
|
-
* @default [] - By default no files are deleted.
|
|
17
|
-
*
|
|
18
|
-
* The globbing patterns follow the implementation of the glob package. (https://www.npmjs.com/package/glob)
|
|
19
|
-
*
|
|
20
|
-
* @deprecated Use `sourcemaps.filesToDeleteAfterUpload` option instead of `sourceMapsUploadOptions.filesToDeleteAfterUpload`.
|
|
21
|
-
*/
|
|
22
|
-
filesToDeleteAfterUpload?: string | Array<string>;
|
|
23
|
-
/**
|
|
24
|
-
* Options related to managing the Sentry releases for a build.
|
|
25
|
-
*
|
|
26
|
-
* More info: https://docs.sentry.io/product/releases/
|
|
27
|
-
*
|
|
28
|
-
* @deprecated Use the `release` option at the root of `SentryVitePluginOptions` instead.
|
|
29
|
-
*/
|
|
30
|
-
release?: {
|
|
31
|
-
/**
|
|
32
|
-
* Unique identifier for the release you want to create.
|
|
33
|
-
*
|
|
34
|
-
* This value can also be specified via the `SENTRY_RELEASE` environment variable.
|
|
35
|
-
*
|
|
36
|
-
* Defaults to automatically detecting a value for your environment.
|
|
37
|
-
* This includes values for Cordova, Heroku, AWS CodeBuild, CircleCI, Xcode, and Gradle, and otherwise uses the git `HEAD`'s commit SHA.
|
|
38
|
-
* (the latter requires access to git CLI and for the root directory to be a valid repository)
|
|
39
|
-
*
|
|
40
|
-
* If you didn't provide a value and the plugin can't automatically detect one, no release will be created.
|
|
41
|
-
*/
|
|
42
|
-
name?: string;
|
|
43
|
-
};
|
|
44
|
-
};
|
|
45
3
|
export type SentryReactRouterBuildOptions = BuildTimeOptionsBase & UnstableVitePluginOptions<Partial<SentryVitePluginOptions>> & {
|
|
46
4
|
/**
|
|
47
5
|
* Options related to react component name annotations.
|
|
@@ -60,11 +18,5 @@ export type SentryReactRouterBuildOptions = BuildTimeOptionsBase & UnstableViteP
|
|
|
60
18
|
*/
|
|
61
19
|
ignoredComponents?: string[];
|
|
62
20
|
};
|
|
63
|
-
/**
|
|
64
|
-
* Options for the Sentry Vite plugin to customize the source maps upload process.
|
|
65
|
-
*
|
|
66
|
-
*/
|
|
67
|
-
sourceMapsUploadOptions?: SourceMapsOptions;
|
|
68
21
|
};
|
|
69
|
-
export {};
|
|
70
22
|
//# sourceMappingURL=types.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/vite/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,yBAAyB,EAAE,MAAM,cAAc,CAAC;AACpF,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;AAE5E,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/vite/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,yBAAyB,EAAE,MAAM,cAAc,CAAC;AACpF,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;AAE5E,MAAM,MAAM,6BAA6B,GAAG,oBAAoB,GAC9D,yBAAyB,CAAC,OAAO,CAAC,uBAAuB,CAAC,CAAC,GAAG;IAC5D;;;;;;OAMG;IACH,wBAAwB,CAAC,EAAE;QACzB;;WAEG;QACH,OAAO,CAAC,EAAE,OAAO,CAAC;QAElB;;WAEG;QACH,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;KAC9B,CAAC;CACH,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sentry/react-router",
|
|
3
|
-
"version": "11.0.0-alpha.
|
|
3
|
+
"version": "11.0.0-alpha.1",
|
|
4
4
|
"description": "Official Sentry SDK for React Router (Framework)",
|
|
5
5
|
"repository": "git://github.com/getsentry/sentry-javascript.git",
|
|
6
6
|
"homepage": "https://github.com/getsentry/sentry-javascript/tree/master/packages/react-router",
|
|
@@ -46,14 +46,14 @@
|
|
|
46
46
|
},
|
|
47
47
|
"dependencies": {
|
|
48
48
|
"@opentelemetry/api": "^1.9.1",
|
|
49
|
-
"@sentry/browser": "11.0.0-alpha.
|
|
49
|
+
"@sentry/browser": "11.0.0-alpha.1",
|
|
50
50
|
"@sentry/cli": "^2.58.6",
|
|
51
|
-
"@sentry/conventions": "^0.
|
|
52
|
-
"@sentry/core": "11.0.0-alpha.
|
|
53
|
-
"@sentry/node": "11.0.0-alpha.
|
|
54
|
-
"@sentry/react": "11.0.0-alpha.
|
|
55
|
-
"@sentry/server-utils": "11.0.0-alpha.
|
|
56
|
-
"@sentry/bundler-plugins": "11.0.0-alpha.
|
|
51
|
+
"@sentry/conventions": "^0.19.0",
|
|
52
|
+
"@sentry/core": "11.0.0-alpha.1",
|
|
53
|
+
"@sentry/node": "11.0.0-alpha.1",
|
|
54
|
+
"@sentry/react": "11.0.0-alpha.1",
|
|
55
|
+
"@sentry/server-utils": "11.0.0-alpha.1",
|
|
56
|
+
"@sentry/bundler-plugins": "11.0.0-alpha.1",
|
|
57
57
|
"glob": "^13.0.6"
|
|
58
58
|
},
|
|
59
59
|
"devDependencies": {
|