@sentry/react-router 10.53.1 → 10.54.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/cjs/client/createClientInstrumentation.js +104 -175
- package/build/cjs/client/createClientInstrumentation.js.map +1 -1
- package/build/cjs/client/hydratedRouter.js +27 -74
- package/build/cjs/client/hydratedRouter.js.map +1 -1
- package/build/cjs/client/sdk.js +5 -16
- package/build/cjs/client/sdk.js.map +1 -1
- package/build/cjs/client/sentryOnError.js +4 -27
- package/build/cjs/client/sentryOnError.js.map +1 -1
- package/build/cjs/client/tracingIntegration.js +4 -18
- package/build/cjs/client/tracingIntegration.js.map +1 -1
- package/build/cjs/client/utils.js +5 -17
- package/build/cjs/client/utils.js.map +1 -1
- package/build/cjs/cloudflare/index.js +2 -15
- package/build/cjs/cloudflare/index.js.map +1 -1
- package/build/cjs/common/debug-build.js +0 -5
- package/build/cjs/common/debug-build.js.map +1 -1
- package/build/cjs/common/utils.js +8 -33
- package/build/cjs/common/utils.js.map +1 -1
- package/build/cjs/server/createSentryHandleError.js +4 -13
- package/build/cjs/server/createSentryHandleError.js.map +1 -1
- package/build/cjs/server/createSentryHandleRequest.js +14 -49
- package/build/cjs/server/createSentryHandleRequest.js.map +1 -1
- package/build/cjs/server/createServerInstrumentation.js +76 -114
- package/build/cjs/server/createServerInstrumentation.js.map +1 -1
- package/build/cjs/server/getMetaTagTransformer.js +2 -8
- package/build/cjs/server/getMetaTagTransformer.js.map +1 -1
- package/build/cjs/server/instrumentation/reactRouter.js +21 -47
- package/build/cjs/server/instrumentation/reactRouter.js.map +1 -1
- package/build/cjs/server/instrumentation/util.js +5 -41
- package/build/cjs/server/instrumentation/util.js.map +1 -1
- package/build/cjs/server/integration/lowQualityTransactionsFilterIntegration.js +5 -12
- package/build/cjs/server/integration/lowQualityTransactionsFilterIntegration.js.map +1 -1
- package/build/cjs/server/integration/reactRouterServer.js +10 -42
- package/build/cjs/server/integration/reactRouterServer.js.map +1 -1
- package/build/cjs/server/sdk.js +6 -20
- package/build/cjs/server/sdk.js.map +1 -1
- package/build/cjs/server/serverBuild.js +6 -31
- package/build/cjs/server/serverBuild.js.map +1 -1
- package/build/cjs/server/serverGlobals.js +6 -26
- package/build/cjs/server/serverGlobals.js.map +1 -1
- package/build/cjs/server/wrapSentryHandleRequest.js +13 -53
- package/build/cjs/server/wrapSentryHandleRequest.js.map +1 -1
- package/build/cjs/server/wrapServerAction.js +12 -44
- package/build/cjs/server/wrapServerAction.js.map +1 -1
- package/build/cjs/server/wrapServerLoader.js +12 -44
- package/build/cjs/server/wrapServerLoader.js.map +1 -1
- package/build/cjs/vite/buildEnd/handleOnBuildEnd.js +38 -72
- package/build/cjs/vite/buildEnd/handleOnBuildEnd.js.map +1 -1
- package/build/cjs/vite/makeConfigInjectorPlugin.js +4 -12
- package/build/cjs/vite/makeConfigInjectorPlugin.js.map +1 -1
- package/build/cjs/vite/makeCustomSentryVitePlugins.js +10 -15
- package/build/cjs/vite/makeCustomSentryVitePlugins.js.map +1 -1
- package/build/cjs/vite/makeEnableSourceMapsPlugin.js +19 -51
- package/build/cjs/vite/makeEnableSourceMapsPlugin.js.map +1 -1
- package/build/cjs/vite/makeServerBuildCapturePlugin.js +4 -15
- package/build/cjs/vite/makeServerBuildCapturePlugin.js.map +1 -1
- package/build/cjs/vite/plugin.js +3 -16
- package/build/cjs/vite/plugin.js.map +1 -1
- package/build/esm/client/createClientInstrumentation.js +104 -175
- package/build/esm/client/createClientInstrumentation.js.map +1 -1
- package/build/esm/client/hydratedRouter.js +27 -74
- package/build/esm/client/hydratedRouter.js.map +1 -1
- package/build/esm/client/sdk.js +5 -16
- package/build/esm/client/sdk.js.map +1 -1
- package/build/esm/client/sentryOnError.js +4 -27
- package/build/esm/client/sentryOnError.js.map +1 -1
- package/build/esm/client/tracingIntegration.js +4 -18
- package/build/esm/client/tracingIntegration.js.map +1 -1
- package/build/esm/client/utils.js +5 -17
- package/build/esm/client/utils.js.map +1 -1
- package/build/esm/cloudflare/index.js +2 -15
- package/build/esm/cloudflare/index.js.map +1 -1
- package/build/esm/common/debug-build.js +0 -5
- package/build/esm/common/debug-build.js.map +1 -1
- package/build/esm/common/utils.js +8 -33
- package/build/esm/common/utils.js.map +1 -1
- package/build/esm/package.json +1 -1
- package/build/esm/server/createSentryHandleError.js +4 -13
- package/build/esm/server/createSentryHandleError.js.map +1 -1
- package/build/esm/server/createSentryHandleRequest.js +14 -49
- package/build/esm/server/createSentryHandleRequest.js.map +1 -1
- package/build/esm/server/createServerInstrumentation.js +76 -114
- package/build/esm/server/createServerInstrumentation.js.map +1 -1
- package/build/esm/server/getMetaTagTransformer.js +2 -8
- package/build/esm/server/getMetaTagTransformer.js.map +1 -1
- package/build/esm/server/instrumentation/reactRouter.js +21 -47
- package/build/esm/server/instrumentation/reactRouter.js.map +1 -1
- package/build/esm/server/instrumentation/util.js +5 -41
- package/build/esm/server/instrumentation/util.js.map +1 -1
- package/build/esm/server/integration/lowQualityTransactionsFilterIntegration.js +5 -12
- package/build/esm/server/integration/lowQualityTransactionsFilterIntegration.js.map +1 -1
- package/build/esm/server/integration/reactRouterServer.js +10 -42
- package/build/esm/server/integration/reactRouterServer.js.map +1 -1
- package/build/esm/server/sdk.js +6 -20
- package/build/esm/server/sdk.js.map +1 -1
- package/build/esm/server/serverBuild.js +6 -31
- package/build/esm/server/serverBuild.js.map +1 -1
- package/build/esm/server/serverGlobals.js +6 -26
- package/build/esm/server/serverGlobals.js.map +1 -1
- package/build/esm/server/wrapSentryHandleRequest.js +13 -53
- package/build/esm/server/wrapSentryHandleRequest.js.map +1 -1
- package/build/esm/server/wrapServerAction.js +12 -44
- package/build/esm/server/wrapServerAction.js.map +1 -1
- package/build/esm/server/wrapServerLoader.js +12 -44
- package/build/esm/server/wrapServerLoader.js.map +1 -1
- package/build/esm/vite/buildEnd/handleOnBuildEnd.js +38 -72
- package/build/esm/vite/buildEnd/handleOnBuildEnd.js.map +1 -1
- package/build/esm/vite/makeConfigInjectorPlugin.js +4 -12
- package/build/esm/vite/makeConfigInjectorPlugin.js.map +1 -1
- package/build/esm/vite/makeCustomSentryVitePlugins.js +10 -15
- package/build/esm/vite/makeCustomSentryVitePlugins.js.map +1 -1
- package/build/esm/vite/makeEnableSourceMapsPlugin.js +19 -51
- package/build/esm/vite/makeEnableSourceMapsPlugin.js.map +1 -1
- package/build/esm/vite/makeServerBuildCapturePlugin.js +4 -15
- package/build/esm/vite/makeServerBuildCapturePlugin.js.map +1 -1
- package/build/esm/vite/plugin.js +3 -16
- package/build/esm/vite/plugin.js.map +1 -1
- package/build/types/client/hydratedRouter.d.ts.map +1 -1
- package/package.json +5 -5
|
@@ -4,93 +4,58 @@ import { DEBUG_BUILD } from '../common/debug-build.js';
|
|
|
4
4
|
import { isClientInstrumentationApiUsed } from './createClientInstrumentation.js';
|
|
5
5
|
import { resolveNavigateArg } from './utils.js';
|
|
6
6
|
|
|
7
|
-
const GLOBAL_OBJ_WITH_DATA_ROUTER = GLOBAL_OBJ
|
|
8
|
-
|
|
9
|
-
;
|
|
10
|
-
|
|
11
|
-
const MAX_RETRIES = 40; // 2 seconds at 50ms interval
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Instruments the React Router Data Router for pageloads and navigation.
|
|
15
|
-
*
|
|
16
|
-
* This function waits for the router to be available after hydration, then:
|
|
17
|
-
* 1. Updates the pageload transaction with parameterized route info
|
|
18
|
-
* 2. Patches router.navigate() to create navigation transactions
|
|
19
|
-
* 3. Subscribes to router state changes to update navigation transactions with parameterized routes
|
|
20
|
-
*/
|
|
7
|
+
const GLOBAL_OBJ_WITH_DATA_ROUTER = GLOBAL_OBJ;
|
|
8
|
+
const MAX_RETRIES = 40;
|
|
21
9
|
function instrumentHydratedRouter() {
|
|
22
10
|
function trySubscribe() {
|
|
23
11
|
const router = GLOBAL_OBJ_WITH_DATA_ROUTER.__reactRouterDataRouter;
|
|
24
|
-
|
|
25
12
|
if (router) {
|
|
26
|
-
// The first time we hit the router, we try to update the pageload transaction
|
|
27
13
|
const pageloadSpan = getActiveRootSpan();
|
|
28
|
-
|
|
29
14
|
if (pageloadSpan) {
|
|
30
15
|
const pageloadName = spanToJSON(pageloadSpan).description;
|
|
31
16
|
const parameterizePageloadRoute = getParameterizedRoute(router.state);
|
|
32
|
-
if (
|
|
33
|
-
|
|
34
|
-
// this event is for the currently active pageload
|
|
35
|
-
normalizePathname(router.state.location.pathname) === normalizePathname(pageloadName)
|
|
36
|
-
) {
|
|
17
|
+
if (pageloadName && // this event is for the currently active pageload
|
|
18
|
+
normalizePathname(router.state.location.pathname) === normalizePathname(pageloadName)) {
|
|
37
19
|
pageloadSpan.updateName(parameterizePageloadRoute);
|
|
38
20
|
pageloadSpan.setAttributes({
|
|
39
|
-
[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]:
|
|
40
|
-
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]:
|
|
21
|
+
[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: "route",
|
|
22
|
+
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: "auto.pageload.react_router"
|
|
41
23
|
});
|
|
42
24
|
}
|
|
43
25
|
}
|
|
44
|
-
|
|
45
|
-
// Patching navigate for creating accurate navigation transactions
|
|
46
|
-
if (typeof router.navigate === 'function') {
|
|
26
|
+
if (typeof router.navigate === "function") {
|
|
47
27
|
const originalNav = router.navigate.bind(router);
|
|
48
28
|
router.navigate = function sentryPatchedNavigate(...args) {
|
|
49
|
-
// Skip if instrumentation API is enabled (it handles navigation spans itself)
|
|
50
29
|
if (!isClientInstrumentationApiUsed()) {
|
|
51
|
-
maybeCreateNavigationTransaction(resolveNavigateArg(args[0]) ||
|
|
30
|
+
maybeCreateNavigationTransaction(resolveNavigateArg(args[0]) || "<unknown route>", "url");
|
|
52
31
|
}
|
|
53
32
|
return originalNav(...args);
|
|
54
33
|
};
|
|
55
34
|
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
const navigationSpan = getActiveRootSpan();
|
|
60
|
-
|
|
61
|
-
if (!navigationSpan) {
|
|
35
|
+
router.subscribe((newState) => {
|
|
36
|
+
const rootSpan = getActiveRootSpan();
|
|
37
|
+
if (!rootSpan) {
|
|
62
38
|
return;
|
|
63
39
|
}
|
|
64
|
-
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
// this event is for the currently active navigation
|
|
72
|
-
normalizePathname(newState.location.pathname) === normalizePathname(navigationSpanName)
|
|
73
|
-
) {
|
|
74
|
-
navigationSpan.updateName(parameterizedNavRoute);
|
|
75
|
-
navigationSpan.setAttributes({
|
|
76
|
-
[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'route',
|
|
77
|
-
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.navigation.react_router',
|
|
78
|
-
});
|
|
40
|
+
const rootSpanName = spanToJSON(rootSpan).description;
|
|
41
|
+
const parameterizedRoute = getParameterizedRoute(newState);
|
|
42
|
+
if (rootSpanName && newState.navigation.state === "idle" && // navigation has completed
|
|
43
|
+
// this event is for the currently active root span
|
|
44
|
+
normalizePathname(newState.location.pathname) === normalizePathname(rootSpanName)) {
|
|
45
|
+
rootSpan.updateName(parameterizedRoute);
|
|
46
|
+
rootSpan.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, "route");
|
|
79
47
|
}
|
|
80
48
|
});
|
|
81
49
|
return true;
|
|
82
50
|
}
|
|
83
51
|
return false;
|
|
84
52
|
}
|
|
85
|
-
|
|
86
|
-
// Wait until the router is available (since the SDK loads before hydration)
|
|
87
53
|
if (!trySubscribe()) {
|
|
88
54
|
let retryCount = 0;
|
|
89
|
-
// Retry until the router is available or max retries reached
|
|
90
55
|
const interval = setInterval(() => {
|
|
91
56
|
if (trySubscribe() || retryCount >= MAX_RETRIES) {
|
|
92
57
|
if (retryCount >= MAX_RETRIES) {
|
|
93
|
-
DEBUG_BUILD && debug.warn(
|
|
58
|
+
DEBUG_BUILD && debug.warn("Unable to instrument React Router: router not found after hydration.");
|
|
94
59
|
}
|
|
95
60
|
clearInterval(interval);
|
|
96
61
|
}
|
|
@@ -98,48 +63,36 @@ function instrumentHydratedRouter() {
|
|
|
98
63
|
}, 50);
|
|
99
64
|
}
|
|
100
65
|
}
|
|
101
|
-
|
|
102
66
|
function maybeCreateNavigationTransaction(name, source) {
|
|
103
67
|
const client = getClient();
|
|
104
|
-
|
|
105
68
|
if (!client) {
|
|
106
|
-
return
|
|
69
|
+
return void 0;
|
|
107
70
|
}
|
|
108
|
-
|
|
109
71
|
return startBrowserTracingNavigationSpan(client, {
|
|
110
72
|
name,
|
|
111
73
|
attributes: {
|
|
112
74
|
[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: source,
|
|
113
|
-
[SEMANTIC_ATTRIBUTE_SENTRY_OP]:
|
|
114
|
-
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]:
|
|
115
|
-
}
|
|
75
|
+
[SEMANTIC_ATTRIBUTE_SENTRY_OP]: "navigation",
|
|
76
|
+
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: "auto.navigation.react_router"
|
|
77
|
+
}
|
|
116
78
|
});
|
|
117
79
|
}
|
|
118
|
-
|
|
119
80
|
function getActiveRootSpan() {
|
|
120
81
|
const activeSpan = getActiveSpan();
|
|
121
82
|
if (!activeSpan) {
|
|
122
|
-
return
|
|
83
|
+
return void 0;
|
|
123
84
|
}
|
|
124
|
-
|
|
125
85
|
const rootSpan = getRootSpan(activeSpan);
|
|
126
|
-
|
|
127
86
|
const op = spanToJSON(rootSpan).op;
|
|
128
|
-
|
|
129
|
-
// Only use this root span if it is a pageload or navigation span
|
|
130
|
-
return op === 'navigation' || op === 'pageload' ? rootSpan : undefined;
|
|
87
|
+
return op === "navigation" || op === "pageload" ? rootSpan : void 0;
|
|
131
88
|
}
|
|
132
|
-
|
|
133
89
|
function getParameterizedRoute(routerState) {
|
|
134
90
|
const lastMatch = routerState.matches[routerState.matches.length - 1];
|
|
135
91
|
return normalizePathname(lastMatch?.route.path ?? routerState.location.pathname);
|
|
136
92
|
}
|
|
137
|
-
|
|
138
93
|
function normalizePathname(pathname) {
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
// Remove trailing slash unless it's the root
|
|
142
|
-
if (normalized.length > 1 && normalized.endsWith('/')) {
|
|
94
|
+
let normalized = pathname.startsWith("/") ? pathname : `/${pathname}`;
|
|
95
|
+
if (normalized.length > 1 && normalized.endsWith("/")) {
|
|
143
96
|
normalized = normalized.slice(0, -1);
|
|
144
97
|
}
|
|
145
98
|
return normalized;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hydratedRouter.js","sources":["../../../src/client/hydratedRouter.ts"],"sourcesContent":["import { 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} from '@sentry/core';\nimport type { DataRouter, RouterState } from 'react-router';\nimport { DEBUG_BUILD } from '../common/debug-build';\nimport { isClientInstrumentationApiUsed } from './createClientInstrumentation';\nimport { resolveNavigateArg } from './utils';\n\nconst GLOBAL_OBJ_WITH_DATA_ROUTER = GLOBAL_OBJ as typeof GLOBAL_OBJ & {\n __reactRouterDataRouter?: DataRouter;\n};\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 });\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 maybeCreateNavigationTransaction(resolveNavigateArg(args[0]) || '<unknown route>', 'url');\n }\n return originalNav(...args);\n };\n }\n\n // Subscribe to router state changes to update navigation transactions
|
|
1
|
+
{"version":3,"file":"hydratedRouter.js","sources":["../../../src/client/hydratedRouter.ts"],"sourcesContent":["import { 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} from '@sentry/core';\nimport type { DataRouter, RouterState } from 'react-router';\nimport { DEBUG_BUILD } from '../common/debug-build';\nimport { isClientInstrumentationApiUsed } from './createClientInstrumentation';\nimport { resolveNavigateArg } from './utils';\n\nconst GLOBAL_OBJ_WITH_DATA_ROUTER = GLOBAL_OBJ as typeof GLOBAL_OBJ & {\n __reactRouterDataRouter?: DataRouter;\n};\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 });\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 maybeCreateNavigationTransaction(resolveNavigateArg(args[0]) || '<unknown route>', 'url');\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 rootSpanName = spanToJSON(rootSpan).description;\n const parameterizedRoute = getParameterizedRoute(newState);\n\n if (\n rootSpanName &&\n newState.navigation.state === 'idle' && // navigation has completed\n // this event is for the currently active root span\n normalizePathname(newState.location.pathname) === normalizePathname(rootSpanName)\n ) {\n rootSpan.updateName(parameterizedRoute);\n rootSpan.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, 'route');\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, source: 'url' | 'route'): Span | undefined {\n const client = getClient();\n\n if (!client) {\n return undefined;\n }\n\n return startBrowserTracingNavigationSpan(client, {\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 },\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\nfunction getParameterizedRoute(routerState: RouterState): string {\n const lastMatch = routerState.matches[routerState.matches.length - 1];\n return normalizePathname(lastMatch?.route.path ?? routerState.location.pathname);\n}\n\nfunction normalizePathname(pathname: string): string {\n // Ensure it starts with a single slash\n let normalized = pathname.startsWith('/') ? pathname : `/${pathname}`;\n // Remove trailing slash unless it's the root\n if (normalized.length > 1 && normalized.endsWith('/')) {\n normalized = normalized.slice(0, -1);\n }\n return normalized;\n}\n"],"names":[],"mappings":"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"}
|
package/build/esm/client/sdk.js
CHANGED
|
@@ -1,34 +1,23 @@
|
|
|
1
1
|
import { init as init$1 } from '@sentry/browser';
|
|
2
2
|
import { consoleSandbox, applySdkMetadata, setTag } from '@sentry/core';
|
|
3
3
|
|
|
4
|
-
const BROWSER_TRACING_INTEGRATION_ID =
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Initializes the client side of the React Router SDK.
|
|
8
|
-
*/
|
|
4
|
+
const BROWSER_TRACING_INTEGRATION_ID = "BrowserTracing";
|
|
9
5
|
function init(options) {
|
|
10
|
-
// If BrowserTracing integration was passed to options, emit a warning
|
|
11
6
|
if (options.integrations && Array.isArray(options.integrations)) {
|
|
12
7
|
const hasBrowserTracing = options.integrations.some(
|
|
13
|
-
integration => integration.name === BROWSER_TRACING_INTEGRATION_ID
|
|
8
|
+
(integration) => integration.name === BROWSER_TRACING_INTEGRATION_ID
|
|
14
9
|
);
|
|
15
|
-
|
|
16
10
|
if (hasBrowserTracing) {
|
|
17
11
|
consoleSandbox(() => {
|
|
18
|
-
// eslint-disable-next-line no-console
|
|
19
12
|
console.warn(
|
|
20
|
-
|
|
13
|
+
"browserTracingIntegration is not fully compatible with @sentry/react-router. Please use reactRouterTracingIntegration instead."
|
|
21
14
|
);
|
|
22
15
|
});
|
|
23
16
|
}
|
|
24
17
|
}
|
|
25
|
-
|
|
26
|
-
applySdkMetadata(options, 'react-router', ['react-router', 'browser']);
|
|
27
|
-
|
|
18
|
+
applySdkMetadata(options, "react-router", ["react-router", "browser"]);
|
|
28
19
|
const client = init$1(options);
|
|
29
|
-
|
|
30
|
-
setTag('runtime', 'browser');
|
|
31
|
-
|
|
20
|
+
setTag("runtime", "browser");
|
|
32
21
|
return client;
|
|
33
22
|
}
|
|
34
23
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sdk.js","sources":["../../../src/client/sdk.ts"],"sourcesContent":["import type { BrowserOptions } from '@sentry/browser';\nimport { init as browserInit } from '@sentry/browser';\nimport type { Client } from '@sentry/core';\nimport { applySdkMetadata, consoleSandbox, setTag } from '@sentry/core';\n\nconst BROWSER_TRACING_INTEGRATION_ID = 'BrowserTracing';\n\n/**\n * Initializes the client side of the React Router SDK.\n */\nexport function init(options: BrowserOptions): Client | undefined {\n // If BrowserTracing integration was passed to options, emit a warning\n if (options.integrations && Array.isArray(options.integrations)) {\n const hasBrowserTracing = options.integrations.some(\n integration => integration.name === BROWSER_TRACING_INTEGRATION_ID,\n );\n\n if (hasBrowserTracing) {\n consoleSandbox(() => {\n // eslint-disable-next-line no-console\n console.warn(\n 'browserTracingIntegration is not fully compatible with @sentry/react-router. Please use reactRouterTracingIntegration instead.',\n );\n });\n }\n }\n\n applySdkMetadata(options, 'react-router', ['react-router', 'browser']);\n\n const client = browserInit(options);\n\n setTag('runtime', 'browser');\n\n return client;\n}\n"],"names":["browserInit"],"mappings":";;;AAKA,MAAM,8BAAA,GAAiC,
|
|
1
|
+
{"version":3,"file":"sdk.js","sources":["../../../src/client/sdk.ts"],"sourcesContent":["import type { BrowserOptions } from '@sentry/browser';\nimport { init as browserInit } from '@sentry/browser';\nimport type { Client } from '@sentry/core';\nimport { applySdkMetadata, consoleSandbox, setTag } from '@sentry/core';\n\nconst BROWSER_TRACING_INTEGRATION_ID = 'BrowserTracing';\n\n/**\n * Initializes the client side of the React Router SDK.\n */\nexport function init(options: BrowserOptions): Client | undefined {\n // If BrowserTracing integration was passed to options, emit a warning\n if (options.integrations && Array.isArray(options.integrations)) {\n const hasBrowserTracing = options.integrations.some(\n integration => integration.name === BROWSER_TRACING_INTEGRATION_ID,\n );\n\n if (hasBrowserTracing) {\n consoleSandbox(() => {\n // eslint-disable-next-line no-console\n console.warn(\n 'browserTracingIntegration is not fully compatible with @sentry/react-router. Please use reactRouterTracingIntegration instead.',\n );\n });\n }\n }\n\n applySdkMetadata(options, 'react-router', ['react-router', 'browser']);\n\n const client = browserInit(options);\n\n setTag('runtime', 'browser');\n\n return client;\n}\n"],"names":["browserInit"],"mappings":";;;AAKA,MAAM,8BAAA,GAAiC,gBAAA;AAKhC,SAAS,KAAK,OAAA,EAA6C;AAEhE,EAAA,IAAI,QAAQ,YAAA,IAAgB,KAAA,CAAM,OAAA,CAAQ,OAAA,CAAQ,YAAY,CAAA,EAAG;AAC/D,IAAA,MAAM,iBAAA,GAAoB,QAAQ,YAAA,CAAa,IAAA;AAAA,MAC7C,CAAA,WAAA,KAAe,YAAY,IAAA,KAAS;AAAA,KACtC;AAEA,IAAA,IAAI,iBAAA,EAAmB;AACrB,MAAA,cAAA,CAAe,MAAM;AAEnB,QAAA,OAAA,CAAQ,IAAA;AAAA,UACN;AAAA,SACF;AAAA,MACF,CAAC,CAAA;AAAA,IACH;AAAA,EACF;AAEA,EAAA,gBAAA,CAAiB,OAAA,EAAS,cAAA,EAAgB,CAAC,cAAA,EAAgB,SAAS,CAAC,CAAA;AAErE,EAAA,MAAM,MAAA,GAASA,OAAY,OAAO,CAAA;AAElC,EAAA,MAAA,CAAO,WAAW,SAAS,CAAA;AAE3B,EAAA,OAAO,MAAA;AACT;;;;"}
|
|
@@ -1,33 +1,10 @@
|
|
|
1
1
|
import { captureException } from '@sentry/core';
|
|
2
2
|
import { captureReactException } from '@sentry/react';
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
*
|
|
9
|
-
* @example (entry.client.tsx)
|
|
10
|
-
* ```tsx
|
|
11
|
-
* import { sentryOnError } from '@sentry/react-router';
|
|
12
|
-
*
|
|
13
|
-
* startTransition(() => {
|
|
14
|
-
* hydrateRoot(
|
|
15
|
-
* document,
|
|
16
|
-
* <HydratedRouter onError={sentryOnError} />
|
|
17
|
-
* );
|
|
18
|
-
* });
|
|
19
|
-
* ```
|
|
20
|
-
*/
|
|
21
|
-
function sentryOnError(
|
|
22
|
-
error,
|
|
23
|
-
{
|
|
24
|
-
errorInfo,
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
,
|
|
28
|
-
) {
|
|
29
|
-
const mechanism = { handled: false, type: 'auto.function.react_router.on_error' };
|
|
30
|
-
|
|
4
|
+
function sentryOnError(error, {
|
|
5
|
+
errorInfo
|
|
6
|
+
}) {
|
|
7
|
+
const mechanism = { handled: false, type: "auto.function.react_router.on_error" };
|
|
31
8
|
if (errorInfo) {
|
|
32
9
|
captureReactException(error, errorInfo, { mechanism });
|
|
33
10
|
} else {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sentryOnError.js","sources":["../../../src/client/sentryOnError.ts"],"sourcesContent":["import { captureException } from '@sentry/core';\nimport { captureReactException } from '@sentry/react';\n\n/**\n * A handler function for React Router's `onError` prop on `HydratedRouter`.\n *\n * Reports errors to Sentry.\n *\n * @example (entry.client.tsx)\n * ```tsx\n * import { sentryOnError } from '@sentry/react-router';\n *\n * startTransition(() => {\n * hydrateRoot(\n * document,\n * <HydratedRouter onError={sentryOnError} />\n * );\n * });\n * ```\n */\nexport function sentryOnError(\n error: unknown,\n {\n errorInfo,\n }: {\n errorInfo?: React.ErrorInfo;\n },\n): void {\n const mechanism = { handled: false, type: 'auto.function.react_router.on_error' };\n\n if (errorInfo) {\n captureReactException(error, errorInfo, { mechanism });\n } else {\n captureException(error, { mechanism });\n }\n}\n"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"sentryOnError.js","sources":["../../../src/client/sentryOnError.ts"],"sourcesContent":["import { captureException } from '@sentry/core';\nimport { captureReactException } from '@sentry/react';\n\n/**\n * A handler function for React Router's `onError` prop on `HydratedRouter`.\n *\n * Reports errors to Sentry.\n *\n * @example (entry.client.tsx)\n * ```tsx\n * import { sentryOnError } from '@sentry/react-router';\n *\n * startTransition(() => {\n * hydrateRoot(\n * document,\n * <HydratedRouter onError={sentryOnError} />\n * );\n * });\n * ```\n */\nexport function sentryOnError(\n error: unknown,\n {\n errorInfo,\n }: {\n errorInfo?: React.ErrorInfo;\n },\n): void {\n const mechanism = { handled: false, type: 'auto.function.react_router.on_error' };\n\n if (errorInfo) {\n captureReactException(error, errorInfo, { mechanism });\n } else {\n captureException(error, { mechanism });\n }\n}\n"],"names":[],"mappings":";;;AAoBO,SAAS,cACd,KAAA,EACA;AAAA,EACE;AACF,CAAA,EAGM;AACN,EAAA,MAAM,SAAA,GAAY,EAAE,OAAA,EAAS,KAAA,EAAO,MAAM,qCAAA,EAAsC;AAEhF,EAAA,IAAI,SAAA,EAAW;AACb,IAAA,qBAAA,CAAsB,KAAA,EAAO,SAAA,EAAW,EAAE,SAAA,EAAW,CAAA;AAAA,EACvD,CAAA,MAAO;AACL,IAAA,gBAAA,CAAiB,KAAA,EAAO,EAAE,SAAA,EAAW,CAAA;AAAA,EACvC;AACF;;;;"}
|
|
@@ -2,45 +2,31 @@ import { browserTracingIntegration } from '@sentry/browser';
|
|
|
2
2
|
import { createSentryClientInstrumentation } from './createClientInstrumentation.js';
|
|
3
3
|
import { instrumentHydratedRouter } from './hydratedRouter.js';
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
* Options for the React Router tracing integration.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Browser tracing integration for React Router (Framework) applications.
|
|
11
|
-
* This integration will create navigation spans and enhance transaction names with parameterized routes.
|
|
12
|
-
*/
|
|
13
|
-
function reactRouterTracingIntegration(
|
|
14
|
-
options = {},
|
|
15
|
-
) {
|
|
5
|
+
function reactRouterTracingIntegration(options = {}) {
|
|
16
6
|
const browserTracingIntegrationInstance = browserTracingIntegration({
|
|
17
7
|
// Navigation transactions are started within the hydrated router instrumentation
|
|
18
|
-
instrumentNavigation: false
|
|
8
|
+
instrumentNavigation: false
|
|
19
9
|
});
|
|
20
|
-
|
|
21
10
|
let clientInstrumentationInstance;
|
|
22
|
-
|
|
23
11
|
if (options.useInstrumentationAPI || options.instrumentationOptions) {
|
|
24
12
|
clientInstrumentationInstance = createSentryClientInstrumentation(options.instrumentationOptions);
|
|
25
13
|
}
|
|
26
|
-
|
|
27
14
|
const getClientInstrumentation = () => {
|
|
28
15
|
if (!clientInstrumentationInstance) {
|
|
29
16
|
clientInstrumentationInstance = createSentryClientInstrumentation(options.instrumentationOptions);
|
|
30
17
|
}
|
|
31
18
|
return clientInstrumentationInstance;
|
|
32
19
|
};
|
|
33
|
-
|
|
34
20
|
return {
|
|
35
21
|
...browserTracingIntegrationInstance,
|
|
36
|
-
name:
|
|
22
|
+
name: "ReactRouterTracingIntegration",
|
|
37
23
|
afterAllSetup(client) {
|
|
38
24
|
browserTracingIntegrationInstance.afterAllSetup(client);
|
|
39
25
|
instrumentHydratedRouter();
|
|
40
26
|
},
|
|
41
27
|
get clientInstrumentation() {
|
|
42
28
|
return getClientInstrumentation();
|
|
43
|
-
}
|
|
29
|
+
}
|
|
44
30
|
};
|
|
45
31
|
}
|
|
46
32
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tracingIntegration.js","sources":["../../../src/client/tracingIntegration.ts"],"sourcesContent":["import { browserTracingIntegration as originalBrowserTracingIntegration } from '@sentry/browser';\nimport type { Integration } from '@sentry/core';\nimport type { ClientInstrumentation } from '../common/types';\nimport {\n createSentryClientInstrumentation,\n type CreateSentryClientInstrumentationOptions,\n} from './createClientInstrumentation';\nimport { instrumentHydratedRouter } from './hydratedRouter';\n\n/**\n * Options for the React Router tracing integration.\n */\nexport interface ReactRouterTracingIntegrationOptions {\n /**\n * Options for React Router's instrumentation API.\n * @experimental\n */\n instrumentationOptions?: CreateSentryClientInstrumentationOptions;\n\n /**\n * Enable React Router's instrumentation API.\n * When true, prepares for use with HydratedRouter's `instrumentations` prop.\n * @experimental\n * @default false\n */\n useInstrumentationAPI?: boolean;\n}\n\n/**\n * React Router tracing integration with support for the instrumentation API.\n */\nexport interface ReactRouterTracingIntegration extends Integration {\n /**\n * Client instrumentation for React Router's instrumentation API.\n * Lazily initialized on first access.\n * @experimental HydratedRouter doesn't invoke these hooks in Framework Mode yet.\n */\n readonly clientInstrumentation: ClientInstrumentation;\n}\n\n/**\n * Browser tracing integration for React Router (Framework) applications.\n * This integration will create navigation spans and enhance transaction names with parameterized routes.\n */\nexport function reactRouterTracingIntegration(\n options: ReactRouterTracingIntegrationOptions = {},\n): ReactRouterTracingIntegration {\n const browserTracingIntegrationInstance = originalBrowserTracingIntegration({\n // Navigation transactions are started within the hydrated router instrumentation\n instrumentNavigation: false,\n });\n\n let clientInstrumentationInstance: ClientInstrumentation | undefined;\n\n if (options.useInstrumentationAPI || options.instrumentationOptions) {\n clientInstrumentationInstance = createSentryClientInstrumentation(options.instrumentationOptions);\n }\n\n const getClientInstrumentation = (): ClientInstrumentation => {\n if (!clientInstrumentationInstance) {\n clientInstrumentationInstance = createSentryClientInstrumentation(options.instrumentationOptions);\n }\n return clientInstrumentationInstance;\n };\n\n return {\n ...browserTracingIntegrationInstance,\n name: 'ReactRouterTracingIntegration',\n afterAllSetup(client) {\n browserTracingIntegrationInstance.afterAllSetup(client);\n instrumentHydratedRouter();\n },\n get clientInstrumentation(): ClientInstrumentation {\n return getClientInstrumentation();\n },\n };\n}\n"],"names":["originalBrowserTracingIntegration"],"mappings":";;;;
|
|
1
|
+
{"version":3,"file":"tracingIntegration.js","sources":["../../../src/client/tracingIntegration.ts"],"sourcesContent":["import { browserTracingIntegration as originalBrowserTracingIntegration } from '@sentry/browser';\nimport type { Integration } from '@sentry/core';\nimport type { ClientInstrumentation } from '../common/types';\nimport {\n createSentryClientInstrumentation,\n type CreateSentryClientInstrumentationOptions,\n} from './createClientInstrumentation';\nimport { instrumentHydratedRouter } from './hydratedRouter';\n\n/**\n * Options for the React Router tracing integration.\n */\nexport interface ReactRouterTracingIntegrationOptions {\n /**\n * Options for React Router's instrumentation API.\n * @experimental\n */\n instrumentationOptions?: CreateSentryClientInstrumentationOptions;\n\n /**\n * Enable React Router's instrumentation API.\n * When true, prepares for use with HydratedRouter's `instrumentations` prop.\n * @experimental\n * @default false\n */\n useInstrumentationAPI?: boolean;\n}\n\n/**\n * React Router tracing integration with support for the instrumentation API.\n */\nexport interface ReactRouterTracingIntegration extends Integration {\n /**\n * Client instrumentation for React Router's instrumentation API.\n * Lazily initialized on first access.\n * @experimental HydratedRouter doesn't invoke these hooks in Framework Mode yet.\n */\n readonly clientInstrumentation: ClientInstrumentation;\n}\n\n/**\n * Browser tracing integration for React Router (Framework) applications.\n * This integration will create navigation spans and enhance transaction names with parameterized routes.\n */\nexport function reactRouterTracingIntegration(\n options: ReactRouterTracingIntegrationOptions = {},\n): ReactRouterTracingIntegration {\n const browserTracingIntegrationInstance = originalBrowserTracingIntegration({\n // Navigation transactions are started within the hydrated router instrumentation\n instrumentNavigation: false,\n });\n\n let clientInstrumentationInstance: ClientInstrumentation | undefined;\n\n if (options.useInstrumentationAPI || options.instrumentationOptions) {\n clientInstrumentationInstance = createSentryClientInstrumentation(options.instrumentationOptions);\n }\n\n const getClientInstrumentation = (): ClientInstrumentation => {\n if (!clientInstrumentationInstance) {\n clientInstrumentationInstance = createSentryClientInstrumentation(options.instrumentationOptions);\n }\n return clientInstrumentationInstance;\n };\n\n return {\n ...browserTracingIntegrationInstance,\n name: 'ReactRouterTracingIntegration',\n afterAllSetup(client) {\n browserTracingIntegrationInstance.afterAllSetup(client);\n instrumentHydratedRouter();\n },\n get clientInstrumentation(): ClientInstrumentation {\n return getClientInstrumentation();\n },\n };\n}\n"],"names":["originalBrowserTracingIntegration"],"mappings":";;;;AA4CO,SAAS,6BAAA,CACd,OAAA,GAAgD,EAAC,EAClB;AAC/B,EAAA,MAAM,oCAAoCA,yBAAA,CAAkC;AAAA;AAAA,IAE1E,oBAAA,EAAsB;AAAA,GACvB,CAAA;AAED,EAAA,IAAI,6BAAA;AAEJ,EAAA,IAAI,OAAA,CAAQ,qBAAA,IAAyB,OAAA,CAAQ,sBAAA,EAAwB;AACnE,IAAA,6BAAA,GAAgC,iCAAA,CAAkC,QAAQ,sBAAsB,CAAA;AAAA,EAClG;AAEA,EAAA,MAAM,2BAA2B,MAA6B;AAC5D,IAAA,IAAI,CAAC,6BAAA,EAA+B;AAClC,MAAA,6BAAA,GAAgC,iCAAA,CAAkC,QAAQ,sBAAsB,CAAA;AAAA,IAClG;AACA,IAAA,OAAO,6BAAA;AAAA,EACT,CAAA;AAEA,EAAA,OAAO;AAAA,IACL,GAAG,iCAAA;AAAA,IACH,IAAA,EAAM,+BAAA;AAAA,IACN,cAAc,MAAA,EAAQ;AACpB,MAAA,iCAAA,CAAkC,cAAc,MAAM,CAAA;AACtD,MAAA,wBAAA,EAAyB;AAAA,IAC3B,CAAA;AAAA,IACA,IAAI,qBAAA,GAA+C;AACjD,MAAA,OAAO,wBAAA,EAAyB;AAAA,IAClC;AAAA,GACF;AACF;;;;"}
|
|
@@ -1,26 +1,14 @@
|
|
|
1
1
|
import { GLOBAL_OBJ } from '@sentry/core';
|
|
2
2
|
|
|
3
|
-
/**
|
|
4
|
-
* Resolves a navigate argument to a pathname string.
|
|
5
|
-
*
|
|
6
|
-
* React Router's navigate() accepts a string, number, or a To object ({ pathname, search, hash }).
|
|
7
|
-
* All fields in the To object are optional (Partial<Path>), so we need to detect object args
|
|
8
|
-
* to avoid "[object Object]" transaction names.
|
|
9
|
-
*/
|
|
10
3
|
function resolveNavigateArg(target) {
|
|
11
|
-
if (typeof target !==
|
|
12
|
-
// string or number
|
|
4
|
+
if (typeof target !== "object" || target === null) {
|
|
13
5
|
return String(target);
|
|
14
6
|
}
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
if (typeof pathname === 'string') {
|
|
19
|
-
return pathname || '/';
|
|
7
|
+
const pathname = target.pathname;
|
|
8
|
+
if (typeof pathname === "string") {
|
|
9
|
+
return pathname || "/";
|
|
20
10
|
}
|
|
21
|
-
|
|
22
|
-
// Object `to` without pathname - navigation stays on current path
|
|
23
|
-
return (GLOBAL_OBJ ).location?.pathname || '/';
|
|
11
|
+
return GLOBAL_OBJ.location?.pathname || "/";
|
|
24
12
|
}
|
|
25
13
|
|
|
26
14
|
export { resolveNavigateArg };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","sources":["../../../src/client/utils.ts"],"sourcesContent":["import { GLOBAL_OBJ } from '@sentry/core';\n\n/**\n * Resolves a navigate argument to a pathname string.\n *\n * React Router's navigate() accepts a string, number, or a To object ({ pathname, search, hash }).\n * All fields in the To object are optional (Partial<Path>), so we need to detect object args\n * to avoid \"[object Object]\" transaction names.\n */\nexport function resolveNavigateArg(target: unknown): string {\n if (typeof target !== 'object' || target === null) {\n // string or number\n return String(target);\n }\n\n // Object `to` with pathname\n const pathname = (target as Record<string, unknown>).pathname;\n if (typeof pathname === 'string') {\n return pathname || '/';\n }\n\n // Object `to` without pathname - navigation stays on current path\n return (GLOBAL_OBJ as typeof GLOBAL_OBJ & Window).location?.pathname || '/';\n}\n"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"utils.js","sources":["../../../src/client/utils.ts"],"sourcesContent":["import { GLOBAL_OBJ } from '@sentry/core';\n\n/**\n * Resolves a navigate argument to a pathname string.\n *\n * React Router's navigate() accepts a string, number, or a To object ({ pathname, search, hash }).\n * All fields in the To object are optional (Partial<Path>), so we need to detect object args\n * to avoid \"[object Object]\" transaction names.\n */\nexport function resolveNavigateArg(target: unknown): string {\n if (typeof target !== 'object' || target === null) {\n // string or number\n return String(target);\n }\n\n // Object `to` with pathname\n const pathname = (target as Record<string, unknown>).pathname;\n if (typeof pathname === 'string') {\n return pathname || '/';\n }\n\n // Object `to` without pathname - navigation stays on current path\n return (GLOBAL_OBJ as typeof GLOBAL_OBJ & Window).location?.pathname || '/';\n}\n"],"names":[],"mappings":";;AASO,SAAS,mBAAmB,MAAA,EAAyB;AAC1D,EAAA,IAAI,OAAO,MAAA,KAAW,QAAA,IAAY,MAAA,KAAW,IAAA,EAAM;AAEjD,IAAA,OAAO,OAAO,MAAM,CAAA;AAAA,EACtB;AAGA,EAAA,MAAM,WAAY,MAAA,CAAmC,QAAA;AACrD,EAAA,IAAI,OAAO,aAAa,QAAA,EAAU;AAChC,IAAA,OAAO,QAAA,IAAY,GAAA;AAAA,EACrB;AAGA,EAAA,OAAQ,UAAA,CAA0C,UAAU,QAAA,IAAY,GAAA;AAC1E;;;;"}
|
|
@@ -7,39 +7,26 @@ export { createSentryClientInstrumentation, isClientInstrumentationApiUsed, isNa
|
|
|
7
7
|
export { sentryOnError } from '../client/sentryOnError.js';
|
|
8
8
|
export { wrapSentryHandleRequest } from '../server/wrapSentryHandleRequest.js';
|
|
9
9
|
|
|
10
|
-
/**
|
|
11
|
-
* Injects Sentry trace meta tags into the HTML response by transforming the ReadableStream.
|
|
12
|
-
* This enables distributed tracing by adding trace context to the HTML document head.
|
|
13
|
-
* @param body - ReadableStream containing the HTML response body to modify
|
|
14
|
-
* @returns A new ReadableStream with Sentry trace meta tags injected into the head section
|
|
15
|
-
*/
|
|
16
10
|
function injectTraceMetaTags(body) {
|
|
17
|
-
const headClosingTag =
|
|
18
|
-
|
|
11
|
+
const headClosingTag = "</head>";
|
|
19
12
|
const reader = body.getReader();
|
|
20
13
|
const stream = new ReadableStream({
|
|
21
14
|
async pull(controller) {
|
|
22
15
|
const { done, value } = await reader.read();
|
|
23
|
-
|
|
24
16
|
if (done) {
|
|
25
17
|
controller.close();
|
|
26
18
|
return;
|
|
27
19
|
}
|
|
28
|
-
|
|
29
20
|
const encoder = new TextEncoder();
|
|
30
21
|
const html = value instanceof Uint8Array ? new TextDecoder().decode(value) : String(value);
|
|
31
|
-
|
|
32
22
|
if (html.includes(headClosingTag)) {
|
|
33
23
|
const modifiedHtml = html.replace(headClosingTag, `${getTraceMetaTags()}${headClosingTag}`);
|
|
34
|
-
|
|
35
24
|
controller.enqueue(encoder.encode(modifiedHtml));
|
|
36
25
|
return;
|
|
37
26
|
}
|
|
38
|
-
|
|
39
27
|
controller.enqueue(encoder.encode(html));
|
|
40
|
-
}
|
|
28
|
+
}
|
|
41
29
|
});
|
|
42
|
-
|
|
43
30
|
return stream;
|
|
44
31
|
}
|
|
45
32
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../../../src/cloudflare/index.ts"],"sourcesContent":["import { getTraceMetaTags } from '@sentry/core';\n\nexport * from '../client';\n\nexport { wrapSentryHandleRequest } from '../server/wrapSentryHandleRequest';\n\n/**\n * Injects Sentry trace meta tags into the HTML response by transforming the ReadableStream.\n * This enables distributed tracing by adding trace context to the HTML document head.\n * @param body - ReadableStream containing the HTML response body to modify\n * @returns A new ReadableStream with Sentry trace meta tags injected into the head section\n */\nexport function injectTraceMetaTags(body: ReadableStream): ReadableStream {\n const headClosingTag = '</head>';\n\n const reader = body.getReader();\n const stream = new ReadableStream({\n async pull(controller) {\n const { done, value } = await reader.read();\n\n if (done) {\n controller.close();\n return;\n }\n\n const encoder = new TextEncoder();\n const html = value instanceof Uint8Array ? new TextDecoder().decode(value) : String(value);\n\n if (html.includes(headClosingTag)) {\n const modifiedHtml = html.replace(headClosingTag, `${getTraceMetaTags()}${headClosingTag}`);\n\n controller.enqueue(encoder.encode(modifiedHtml));\n return;\n }\n\n controller.enqueue(encoder.encode(html));\n },\n });\n\n return stream;\n}\n"],"names":[],"mappings":";;;;;;;;;
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../../src/cloudflare/index.ts"],"sourcesContent":["import { getTraceMetaTags } from '@sentry/core';\n\nexport * from '../client';\n\nexport { wrapSentryHandleRequest } from '../server/wrapSentryHandleRequest';\n\n/**\n * Injects Sentry trace meta tags into the HTML response by transforming the ReadableStream.\n * This enables distributed tracing by adding trace context to the HTML document head.\n * @param body - ReadableStream containing the HTML response body to modify\n * @returns A new ReadableStream with Sentry trace meta tags injected into the head section\n */\nexport function injectTraceMetaTags(body: ReadableStream): ReadableStream {\n const headClosingTag = '</head>';\n\n const reader = body.getReader();\n const stream = new ReadableStream({\n async pull(controller) {\n const { done, value } = await reader.read();\n\n if (done) {\n controller.close();\n return;\n }\n\n const encoder = new TextEncoder();\n const html = value instanceof Uint8Array ? new TextDecoder().decode(value) : String(value);\n\n if (html.includes(headClosingTag)) {\n const modifiedHtml = html.replace(headClosingTag, `${getTraceMetaTags()}${headClosingTag}`);\n\n controller.enqueue(encoder.encode(modifiedHtml));\n return;\n }\n\n controller.enqueue(encoder.encode(html));\n },\n });\n\n return stream;\n}\n"],"names":[],"mappings":";;;;;;;;;AAYO,SAAS,oBAAoB,IAAA,EAAsC;AACxE,EAAA,MAAM,cAAA,GAAiB,SAAA;AAEvB,EAAA,MAAM,MAAA,GAAS,KAAK,SAAA,EAAU;AAC9B,EAAA,MAAM,MAAA,GAAS,IAAI,cAAA,CAAe;AAAA,IAChC,MAAM,KAAK,UAAA,EAAY;AACrB,MAAA,MAAM,EAAE,IAAA,EAAM,KAAA,EAAM,GAAI,MAAM,OAAO,IAAA,EAAK;AAE1C,MAAA,IAAI,IAAA,EAAM;AACR,QAAA,UAAA,CAAW,KAAA,EAAM;AACjB,QAAA;AAAA,MACF;AAEA,MAAA,MAAM,OAAA,GAAU,IAAI,WAAA,EAAY;AAChC,MAAA,MAAM,IAAA,GAAO,KAAA,YAAiB,UAAA,GAAa,IAAI,WAAA,GAAc,MAAA,CAAO,KAAK,CAAA,GAAI,MAAA,CAAO,KAAK,CAAA;AAEzF,MAAA,IAAI,IAAA,CAAK,QAAA,CAAS,cAAc,CAAA,EAAG;AACjC,QAAA,MAAM,YAAA,GAAe,KAAK,OAAA,CAAQ,cAAA,EAAgB,GAAG,gBAAA,EAAkB,CAAA,EAAG,cAAc,CAAA,CAAE,CAAA;AAE1F,QAAA,UAAA,CAAW,OAAA,CAAQ,OAAA,CAAQ,MAAA,CAAO,YAAY,CAAC,CAAA;AAC/C,QAAA;AAAA,MACF;AAEA,MAAA,UAAA,CAAW,OAAA,CAAQ,OAAA,CAAQ,MAAA,CAAO,IAAI,CAAC,CAAA;AAAA,IACzC;AAAA,GACD,CAAA;AAED,EAAA,OAAO,MAAA;AACT;;;;"}
|
|
@@ -1,8 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* This serves as a build time flag that will be true by default, but false in non-debug builds or if users replace `__SENTRY_DEBUG__` in their generated code.
|
|
3
|
-
*
|
|
4
|
-
* ATTENTION: This constant must never cross package boundaries (i.e. be exported) to guarantee that it can be used for tree shaking.
|
|
5
|
-
*/
|
|
6
1
|
const DEBUG_BUILD = (typeof __SENTRY_DEBUG__ === 'undefined' || __SENTRY_DEBUG__);
|
|
7
2
|
|
|
8
3
|
export { DEBUG_BUILD };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"debug-build.js","sources":["../../../src/common/debug-build.ts"],"sourcesContent":["declare const __DEBUG_BUILD__: boolean;\n\n/**\n * This serves as a build time flag that will be true by default, but false in non-debug builds or if users replace `__SENTRY_DEBUG__` in their generated code.\n *\n * ATTENTION: This constant must never cross package boundaries (i.e. be exported) to guarantee that it can be used for tree shaking.\n */\nexport const DEBUG_BUILD = __DEBUG_BUILD__;\n"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"debug-build.js","sources":["../../../src/common/debug-build.ts"],"sourcesContent":["declare const __DEBUG_BUILD__: boolean;\n\n/**\n * This serves as a build time flag that will be true by default, but false in non-debug builds or if users replace `__SENTRY_DEBUG__` in their generated code.\n *\n * ATTENTION: This constant must never cross package boundaries (i.e. be exported) to guarantee that it can be used for tree shaking.\n */\nexport const DEBUG_BUILD = __DEBUG_BUILD__;\n"],"names":[],"mappings":"AAOO,MAAM,WAAA,IAAc,OAAA,gBAAA,KAAA,WAAA,IAAA,gBAAA;;;;"}
|
|
@@ -1,60 +1,35 @@
|
|
|
1
1
|
import { captureException, debug } from '@sentry/core';
|
|
2
2
|
import { DEBUG_BUILD } from './debug-build.js';
|
|
3
3
|
|
|
4
|
-
/**
|
|
5
|
-
* Extracts pathname from request URL.
|
|
6
|
-
* Falls back to '<unknown>' with DEBUG warning if URL cannot be parsed.
|
|
7
|
-
*/
|
|
8
4
|
function getPathFromRequest(request) {
|
|
9
5
|
try {
|
|
10
6
|
return new URL(request.url).pathname;
|
|
11
7
|
} catch {
|
|
12
8
|
try {
|
|
13
|
-
|
|
14
|
-
return new URL(request.url, 'http://example.com').pathname;
|
|
9
|
+
return new URL(request.url, "http://example.com").pathname;
|
|
15
10
|
} catch (error) {
|
|
16
|
-
DEBUG_BUILD && debug.warn(
|
|
17
|
-
return
|
|
11
|
+
DEBUG_BUILD && debug.warn("Failed to parse URL from request:", request.url, error);
|
|
12
|
+
return "<unknown>";
|
|
18
13
|
}
|
|
19
14
|
}
|
|
20
15
|
}
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Extracts route pattern from instrumentation info.
|
|
24
|
-
* Prefers `pattern` (planned for v8) over `unstable_pattern` (v7.x).
|
|
25
|
-
*/
|
|
26
16
|
function getPattern(info) {
|
|
27
17
|
return info.pattern ?? info.unstable_pattern;
|
|
28
18
|
}
|
|
29
|
-
|
|
30
|
-
/**
|
|
31
|
-
* Normalizes route path by ensuring it starts with a slash.
|
|
32
|
-
* Returns undefined if the input is falsy.
|
|
33
|
-
*/
|
|
34
19
|
function normalizeRoutePath(pattern) {
|
|
35
20
|
if (!pattern) {
|
|
36
|
-
return
|
|
21
|
+
return void 0;
|
|
37
22
|
}
|
|
38
|
-
return pattern.startsWith(
|
|
23
|
+
return pattern.startsWith("/") ? pattern : `/${pattern}`;
|
|
39
24
|
}
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Captures an error from instrumentation result.
|
|
43
|
-
* Caller must verify result contains an Error before calling.
|
|
44
|
-
*/
|
|
45
|
-
function captureInstrumentationError(
|
|
46
|
-
result,
|
|
47
|
-
captureErrors,
|
|
48
|
-
mechanismType,
|
|
49
|
-
data,
|
|
50
|
-
) {
|
|
25
|
+
function captureInstrumentationError(result, captureErrors, mechanismType, data) {
|
|
51
26
|
if (captureErrors) {
|
|
52
27
|
captureException(result.error, {
|
|
53
28
|
mechanism: {
|
|
54
29
|
type: mechanismType,
|
|
55
30
|
handled: false,
|
|
56
|
-
data
|
|
57
|
-
}
|
|
31
|
+
data
|
|
32
|
+
}
|
|
58
33
|
});
|
|
59
34
|
}
|
|
60
35
|
}
|