@sentry/react-router 10.41.0-beta.0 → 10.41.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/cjs/client/createClientInstrumentation.js +18 -1
- package/build/cjs/client/createClientInstrumentation.js.map +1 -1
- package/build/cjs/server/createServerInstrumentation.js +73 -49
- package/build/cjs/server/createServerInstrumentation.js.map +1 -1
- package/build/cjs/server/instrumentation/reactRouter.js +23 -7
- package/build/cjs/server/instrumentation/reactRouter.js.map +1 -1
- package/build/cjs/server/integration/reactRouterServer.js +11 -8
- package/build/cjs/server/integration/reactRouterServer.js.map +1 -1
- package/build/cjs/server/serverBuild.js +54 -0
- package/build/cjs/server/serverBuild.js.map +1 -0
- package/build/cjs/server/serverGlobals.js +19 -0
- package/build/cjs/server/serverGlobals.js.map +1 -1
- package/build/cjs/vite/makeServerBuildCapturePlugin.js +43 -0
- package/build/cjs/vite/makeServerBuildCapturePlugin.js.map +1 -0
- package/build/cjs/vite/plugin.js +2 -0
- package/build/cjs/vite/plugin.js.map +1 -1
- package/build/esm/client/createClientInstrumentation.js +18 -1
- package/build/esm/client/createClientInstrumentation.js.map +1 -1
- package/build/esm/package.json +1 -1
- package/build/esm/server/createServerInstrumentation.js +74 -50
- package/build/esm/server/createServerInstrumentation.js.map +1 -1
- package/build/esm/server/instrumentation/reactRouter.js +25 -9
- package/build/esm/server/instrumentation/reactRouter.js.map +1 -1
- package/build/esm/server/integration/reactRouterServer.js +12 -9
- package/build/esm/server/integration/reactRouterServer.js.map +1 -1
- package/build/esm/server/serverBuild.js +48 -0
- package/build/esm/server/serverBuild.js.map +1 -0
- package/build/esm/server/serverGlobals.js +18 -1
- package/build/esm/server/serverGlobals.js.map +1 -1
- package/build/esm/vite/makeServerBuildCapturePlugin.js +41 -0
- package/build/esm/vite/makeServerBuildCapturePlugin.js.map +1 -0
- package/build/esm/vite/plugin.js +2 -0
- package/build/esm/vite/plugin.js.map +1 -1
- package/build/types/client/createClientInstrumentation.d.ts.map +1 -1
- package/build/types/server/createServerInstrumentation.d.ts.map +1 -1
- package/build/types/server/instrumentation/reactRouter.d.ts.map +1 -1
- package/build/types/server/integration/reactRouterServer.d.ts.map +1 -1
- package/build/types/server/serverBuild.d.ts +28 -0
- package/build/types/server/serverBuild.d.ts.map +1 -0
- package/build/types/server/serverGlobals.d.ts +10 -0
- package/build/types/server/serverGlobals.d.ts.map +1 -1
- package/build/types/vite/makeServerBuildCapturePlugin.d.ts +6 -0
- package/build/types/vite/makeServerBuildCapturePlugin.d.ts.map +1 -0
- package/build/types/vite/plugin.d.ts.map +1 -1
- package/package.json +5 -5
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
|
|
3
|
+
const core = require('@sentry/core');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Subset of ServerBuild shape for middleware name lookup.
|
|
7
|
+
* The official React Router types don't expose `middleware` on route modules yet.
|
|
8
|
+
* @internal
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/** @internal */
|
|
12
|
+
const GLOBAL_KEY = '__sentrySetServerBuild';
|
|
13
|
+
|
|
14
|
+
// ServerBuild reference for middleware name lookup. Updated on each createRequestHandler call.
|
|
15
|
+
let _serverBuild;
|
|
16
|
+
|
|
17
|
+
/** @internal */
|
|
18
|
+
function isServerBuildLike(build) {
|
|
19
|
+
return (
|
|
20
|
+
build !== null &&
|
|
21
|
+
typeof build === 'object' &&
|
|
22
|
+
'routes' in build &&
|
|
23
|
+
build.routes !== null &&
|
|
24
|
+
typeof build.routes === 'object'
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** @internal */
|
|
29
|
+
function setServerBuild(build) {
|
|
30
|
+
_serverBuild = build;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** @internal */
|
|
34
|
+
function getMiddlewareName(routeId, index) {
|
|
35
|
+
if (!_serverBuild?.routes) return undefined;
|
|
36
|
+
|
|
37
|
+
const route = _serverBuild.routes[routeId];
|
|
38
|
+
if (!route?.module?.middleware) return undefined;
|
|
39
|
+
|
|
40
|
+
const middlewareFn = route.module.middleware[index];
|
|
41
|
+
return middlewareFn?.name || undefined;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** @internal */
|
|
45
|
+
function registerServerBuildGlobal() {
|
|
46
|
+
(core.GLOBAL_OBJ )[GLOBAL_KEY] = setServerBuild;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
exports.GLOBAL_KEY = GLOBAL_KEY;
|
|
50
|
+
exports.getMiddlewareName = getMiddlewareName;
|
|
51
|
+
exports.isServerBuildLike = isServerBuildLike;
|
|
52
|
+
exports.registerServerBuildGlobal = registerServerBuildGlobal;
|
|
53
|
+
exports.setServerBuild = setServerBuild;
|
|
54
|
+
//# sourceMappingURL=serverBuild.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serverBuild.js","sources":["../../../src/server/serverBuild.ts"],"sourcesContent":["import { GLOBAL_OBJ } from '@sentry/core';\n\n/**\n * Subset of ServerBuild shape for middleware name lookup.\n * The official React Router types don't expose `middleware` on route modules yet.\n * @internal\n */\ninterface ServerBuildLike {\n routes?: Record<\n string,\n {\n module?: {\n middleware?: Array<{ name?: string }>;\n };\n }\n >;\n}\n\n/** @internal */\nexport const GLOBAL_KEY = '__sentrySetServerBuild';\n\ntype GlobalObjWithBuildCapture = typeof GLOBAL_OBJ & {\n [GLOBAL_KEY]?: (build: ServerBuildLike) => void;\n};\n\n// ServerBuild reference for middleware name lookup. Updated on each createRequestHandler call.\nlet _serverBuild: ServerBuildLike | undefined;\n\n/** @internal */\nexport function isServerBuildLike(build: unknown): build is ServerBuildLike {\n return (\n build !== null &&\n typeof build === 'object' &&\n 'routes' in build &&\n build.routes !== null &&\n typeof build.routes === 'object'\n );\n}\n\n/** @internal */\nexport function setServerBuild(build: ServerBuildLike): void {\n _serverBuild = build;\n}\n\n/** @internal */\nexport function getMiddlewareName(routeId: string, index: number): string | undefined {\n if (!_serverBuild?.routes) return undefined;\n\n const route = _serverBuild.routes[routeId];\n if (!route?.module?.middleware) return undefined;\n\n const middlewareFn = route.module.middleware[index];\n return middlewareFn?.name || undefined;\n}\n\n/** @internal */\nexport function registerServerBuildGlobal(): void {\n (GLOBAL_OBJ as GlobalObjWithBuildCapture)[GLOBAL_KEY] = setServerBuild;\n}\n\n/** @internal Exported for testing. */\nexport function _resetServerBuild(): void {\n _serverBuild = undefined;\n // eslint-disable-next-line @typescript-eslint/no-dynamic-delete\n delete (GLOBAL_OBJ as GlobalObjWithBuildCapture)[GLOBAL_KEY];\n}\n"],"names":["GLOBAL_OBJ"],"mappings":";;;;AAEA;AACA;AACA;AACA;AACA;;AAYA;AACO,MAAM,UAAA,GAAa;;AAM1B;AACA,IAAI,YAAY;;AAEhB;AACO,SAAS,iBAAiB,CAAC,KAAK,EAAqC;AAC5E,EAAE;AACF,IAAI,KAAA,KAAU,IAAA;AACd,IAAI,OAAO,KAAA,KAAU,QAAA;AACrB,IAAI,QAAA,IAAY,KAAA;AAChB,IAAI,KAAK,CAAC,MAAA,KAAW,IAAA;AACrB,IAAI,OAAO,KAAK,CAAC,MAAA,KAAW;AAC5B;AACA;;AAEA;AACO,SAAS,cAAc,CAAC,KAAK,EAAyB;AAC7D,EAAE,YAAA,GAAe,KAAK;AACtB;;AAEA;AACO,SAAS,iBAAiB,CAAC,OAAO,EAAU,KAAK,EAA8B;AACtF,EAAE,IAAI,CAAC,YAAY,EAAE,MAAM,EAAE,OAAO,SAAS;;AAE7C,EAAE,MAAM,QAAQ,YAAY,CAAC,MAAM,CAAC,OAAO,CAAC;AAC5C,EAAE,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,SAAS;;AAElD,EAAE,MAAM,YAAA,GAAe,KAAK,CAAC,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC;AACrD,EAAE,OAAO,YAAY,EAAE,IAAA,IAAQ,SAAS;AACxC;;AAEA;AACO,SAAS,yBAAyB,GAAS;AAClD,EAAE,CAACA,eAAA,GAAyC,UAAU,CAAA,GAAI,cAAc;AACxE;;;;;;;;"}
|
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
|
3
3
|
const core = require('@sentry/core');
|
|
4
4
|
|
|
5
5
|
const SENTRY_SERVER_INSTRUMENTATION_FLAG = '__sentryReactRouterServerInstrumentationUsed';
|
|
6
|
+
const SENTRY_OTEL_SPAN_CREATION_FLAG = '__sentryReactRouterOtelSpanCreationEnabled';
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* Mark that the React Router instrumentation API is being used on the server.
|
|
@@ -20,6 +21,24 @@ function isInstrumentationApiUsed() {
|
|
|
20
21
|
return !!(core.GLOBAL_OBJ )[SENTRY_SERVER_INSTRUMENTATION_FLAG];
|
|
21
22
|
}
|
|
22
23
|
|
|
24
|
+
/**
|
|
25
|
+
* Enable OTEL data-loader span creation for React Router server.
|
|
26
|
+
* @internal
|
|
27
|
+
*/
|
|
28
|
+
function enableOtelDataLoaderSpanCreation() {
|
|
29
|
+
(core.GLOBAL_OBJ )[SENTRY_OTEL_SPAN_CREATION_FLAG] = true;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Check if OTEL data-loader span creation is enabled for React Router server.
|
|
34
|
+
* @internal
|
|
35
|
+
*/
|
|
36
|
+
function isOtelDataLoaderSpanCreationEnabled() {
|
|
37
|
+
return !!(core.GLOBAL_OBJ )[SENTRY_OTEL_SPAN_CREATION_FLAG];
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
exports.enableOtelDataLoaderSpanCreation = enableOtelDataLoaderSpanCreation;
|
|
23
41
|
exports.isInstrumentationApiUsed = isInstrumentationApiUsed;
|
|
42
|
+
exports.isOtelDataLoaderSpanCreationEnabled = isOtelDataLoaderSpanCreationEnabled;
|
|
24
43
|
exports.markInstrumentationApiUsed = markInstrumentationApiUsed;
|
|
25
44
|
//# sourceMappingURL=serverGlobals.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"serverGlobals.js","sources":["../../../src/server/serverGlobals.ts"],"sourcesContent":["import { GLOBAL_OBJ } from '@sentry/core';\n\nconst SENTRY_SERVER_INSTRUMENTATION_FLAG = '__sentryReactRouterServerInstrumentationUsed';\n\ntype GlobalObjWithFlag = typeof GLOBAL_OBJ & {\n [SENTRY_SERVER_INSTRUMENTATION_FLAG]?: boolean;\n};\n\n/**\n * Mark that the React Router instrumentation API is being used on the server.\n * @internal\n */\nexport function markInstrumentationApiUsed(): void {\n (GLOBAL_OBJ as GlobalObjWithFlag)[SENTRY_SERVER_INSTRUMENTATION_FLAG] = true;\n}\n\n/**\n * Check if React Router's instrumentation API is being used on the server.\n * @experimental\n */\nexport function isInstrumentationApiUsed(): boolean {\n return !!(GLOBAL_OBJ as GlobalObjWithFlag)[SENTRY_SERVER_INSTRUMENTATION_FLAG];\n}\n"],"names":["GLOBAL_OBJ"],"mappings":";;;;AAEA,MAAM,kCAAA,GAAqC,8CAA8C;;
|
|
1
|
+
{"version":3,"file":"serverGlobals.js","sources":["../../../src/server/serverGlobals.ts"],"sourcesContent":["import { GLOBAL_OBJ } from '@sentry/core';\n\nconst SENTRY_SERVER_INSTRUMENTATION_FLAG = '__sentryReactRouterServerInstrumentationUsed';\nconst SENTRY_OTEL_SPAN_CREATION_FLAG = '__sentryReactRouterOtelSpanCreationEnabled';\n\ntype GlobalObjWithFlag = typeof GLOBAL_OBJ & {\n [SENTRY_SERVER_INSTRUMENTATION_FLAG]?: boolean;\n [SENTRY_OTEL_SPAN_CREATION_FLAG]?: boolean;\n};\n\n/**\n * Mark that the React Router instrumentation API is being used on the server.\n * @internal\n */\nexport function markInstrumentationApiUsed(): void {\n (GLOBAL_OBJ as GlobalObjWithFlag)[SENTRY_SERVER_INSTRUMENTATION_FLAG] = true;\n}\n\n/**\n * Check if React Router's instrumentation API is being used on the server.\n * @experimental\n */\nexport function isInstrumentationApiUsed(): boolean {\n return !!(GLOBAL_OBJ as GlobalObjWithFlag)[SENTRY_SERVER_INSTRUMENTATION_FLAG];\n}\n\n/**\n * Enable OTEL data-loader span creation for React Router server.\n * @internal\n */\nexport function enableOtelDataLoaderSpanCreation(): void {\n (GLOBAL_OBJ as GlobalObjWithFlag)[SENTRY_OTEL_SPAN_CREATION_FLAG] = true;\n}\n\n/**\n * Check if OTEL data-loader span creation is enabled for React Router server.\n * @internal\n */\nexport function isOtelDataLoaderSpanCreationEnabled(): boolean {\n return !!(GLOBAL_OBJ as GlobalObjWithFlag)[SENTRY_OTEL_SPAN_CREATION_FLAG];\n}\n"],"names":["GLOBAL_OBJ"],"mappings":";;;;AAEA,MAAM,kCAAA,GAAqC,8CAA8C;AACzF,MAAM,8BAAA,GAAiC,4CAA4C;;AAOnF;AACA;AACA;AACA;AACO,SAAS,0BAA0B,GAAS;AACnD,EAAE,CAACA,eAAA,GAAiC,kCAAkC,CAAA,GAAI,IAAI;AAC9E;;AAEA;AACA;AACA;AACA;AACO,SAAS,wBAAwB,GAAY;AACpD,EAAE,OAAO,CAAC,CAAC,CAACA,kBAAiC,kCAAkC,CAAC;AAChF;;AAEA;AACA;AACA;AACA;AACO,SAAS,gCAAgC,GAAS;AACzD,EAAE,CAACA,eAAA,GAAiC,8BAA8B,CAAA,GAAI,IAAI;AAC1E;;AAEA;AACA;AACA;AACA;AACO,SAAS,mCAAmC,GAAY;AAC/D,EAAE,OAAO,CAAC,CAAC,CAACA,kBAAiC,8BAA8B,CAAC;AAC5E;;;;;;;"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
|
|
3
|
+
const serverBuild = require('../server/serverBuild.js');
|
|
4
|
+
|
|
5
|
+
const SERVER_BUILD_MODULE_ID = 'virtual:react-router/server-build';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* A Sentry plugin for React Router to capture the server build for middleware name resolution.
|
|
9
|
+
*/
|
|
10
|
+
function makeServerBuildCapturePlugin() {
|
|
11
|
+
let isSsrBuild = false;
|
|
12
|
+
|
|
13
|
+
return {
|
|
14
|
+
name: 'sentry-react-router-server-build-capture',
|
|
15
|
+
enforce: 'post',
|
|
16
|
+
|
|
17
|
+
configResolved(config) {
|
|
18
|
+
isSsrBuild = !!config.build.ssr;
|
|
19
|
+
},
|
|
20
|
+
|
|
21
|
+
transform(code, id) {
|
|
22
|
+
if (!isSsrBuild) {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (!id.includes(SERVER_BUILD_MODULE_ID)) {
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// `routes` is a module-scope export in the virtual:react-router/server-build module
|
|
31
|
+
const injectedCode = `${code}
|
|
32
|
+
if (typeof globalThis !== 'undefined' && typeof globalThis["${serverBuild.GLOBAL_KEY}"] === 'function') {
|
|
33
|
+
globalThis["${serverBuild.GLOBAL_KEY}"]({ routes });
|
|
34
|
+
}
|
|
35
|
+
`;
|
|
36
|
+
|
|
37
|
+
return { code: injectedCode, map: null };
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
exports.makeServerBuildCapturePlugin = makeServerBuildCapturePlugin;
|
|
43
|
+
//# sourceMappingURL=makeServerBuildCapturePlugin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"makeServerBuildCapturePlugin.js","sources":["../../../src/vite/makeServerBuildCapturePlugin.ts"],"sourcesContent":["import { type Plugin } from 'vite';\nimport { GLOBAL_KEY } from '../server/serverBuild';\n\nconst SERVER_BUILD_MODULE_ID = 'virtual:react-router/server-build';\n\n/**\n * A Sentry plugin for React Router to capture the server build for middleware name resolution.\n */\nexport function makeServerBuildCapturePlugin(): Plugin {\n let isSsrBuild = false;\n\n return {\n name: 'sentry-react-router-server-build-capture',\n enforce: 'post',\n\n configResolved(config) {\n isSsrBuild = !!config.build.ssr;\n },\n\n transform(code, id) {\n if (!isSsrBuild) {\n return null;\n }\n\n if (!id.includes(SERVER_BUILD_MODULE_ID)) {\n return null;\n }\n\n // `routes` is a module-scope export in the virtual:react-router/server-build module\n const injectedCode = `${code}\nif (typeof globalThis !== 'undefined' && typeof globalThis[\"${GLOBAL_KEY}\"] === 'function') {\n globalThis[\"${GLOBAL_KEY}\"]({ routes });\n}\n`;\n\n return { code: injectedCode, map: null };\n },\n };\n}\n"],"names":["GLOBAL_KEY"],"mappings":";;;;AAGA,MAAM,sBAAA,GAAyB,mCAAmC;;AAElE;AACA;AACA;AACO,SAAS,4BAA4B,GAAW;AACvD,EAAE,IAAI,UAAA,GAAa,KAAK;;AAExB,EAAE,OAAO;AACT,IAAI,IAAI,EAAE,0CAA0C;AACpD,IAAI,OAAO,EAAE,MAAM;;AAEnB,IAAI,cAAc,CAAC,MAAM,EAAE;AAC3B,MAAM,UAAA,GAAa,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG;AACrC,IAAI,CAAC;;AAEL,IAAI,SAAS,CAAC,IAAI,EAAE,EAAE,EAAE;AACxB,MAAM,IAAI,CAAC,UAAU,EAAE;AACvB,QAAQ,OAAO,IAAI;AACnB,MAAM;;AAEN,MAAM,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,sBAAsB,CAAC,EAAE;AAChD,QAAQ,OAAO,IAAI;AACnB,MAAM;;AAEN;AACA,MAAM,MAAM,YAAA,GAAe,CAAC,EAAA,IAAA;AACA,4DAAA,EAAAA,sBAAA,CAAA;AACA,cAAA,EAAAA,sBAAA,CAAA;AACA;AACA,CAAA;;AAEA,MAAA,OAAA,EAAA,IAAA,EAAA,YAAA,EAAA,GAAA,EAAA,IAAA,EAAA;AACA,IAAA,CAAA;AACA,GAAA;AACA;;;;"}
|
package/build/cjs/vite/plugin.js
CHANGED
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
|
3
3
|
const makeConfigInjectorPlugin = require('./makeConfigInjectorPlugin.js');
|
|
4
4
|
const makeCustomSentryVitePlugins = require('./makeCustomSentryVitePlugins.js');
|
|
5
5
|
const makeEnableSourceMapsPlugin = require('./makeEnableSourceMapsPlugin.js');
|
|
6
|
+
const makeServerBuildCapturePlugin = require('./makeServerBuildCapturePlugin.js');
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* A Vite plugin for Sentry that handles source map uploads and bundle size optimizations.
|
|
@@ -18,6 +19,7 @@ async function sentryReactRouter(
|
|
|
18
19
|
const plugins = [];
|
|
19
20
|
|
|
20
21
|
plugins.push(makeConfigInjectorPlugin.makeConfigInjectorPlugin(options));
|
|
22
|
+
plugins.push(makeServerBuildCapturePlugin.makeServerBuildCapturePlugin());
|
|
21
23
|
|
|
22
24
|
if (process.env.NODE_ENV !== 'development' && viteConfig.command === 'build' && viteConfig.mode !== 'development') {
|
|
23
25
|
plugins.push(makeEnableSourceMapsPlugin.makeEnableSourceMapsPlugin(options));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.js","sources":["../../../src/vite/plugin.ts"],"sourcesContent":["import type { ConfigEnv, Plugin } from 'vite';\nimport { makeConfigInjectorPlugin } from './makeConfigInjectorPlugin';\nimport { makeCustomSentryVitePlugins } from './makeCustomSentryVitePlugins';\nimport { makeEnableSourceMapsPlugin } from './makeEnableSourceMapsPlugin';\nimport type { SentryReactRouterBuildOptions } from './types';\n\n/**\n * A Vite plugin for Sentry that handles source map uploads and bundle size optimizations.\n *\n * @param options - Configuration options for the Sentry Vite plugin\n * @param viteConfig - The Vite user config object\n * @returns An array of Vite plugins\n */\nexport async function sentryReactRouter(\n options: SentryReactRouterBuildOptions = {},\n viteConfig: ConfigEnv,\n): Promise<Plugin[]> {\n const plugins: Plugin[] = [];\n\n plugins.push(makeConfigInjectorPlugin(options));\n\n if (process.env.NODE_ENV !== 'development' && viteConfig.command === 'build' && viteConfig.mode !== 'development') {\n plugins.push(makeEnableSourceMapsPlugin(options));\n plugins.push(...(await makeCustomSentryVitePlugins(options)));\n }\n\n return plugins;\n}\n"],"names":["makeConfigInjectorPlugin","makeEnableSourceMapsPlugin","makeCustomSentryVitePlugins"],"mappings":"
|
|
1
|
+
{"version":3,"file":"plugin.js","sources":["../../../src/vite/plugin.ts"],"sourcesContent":["import type { ConfigEnv, Plugin } from 'vite';\nimport { makeConfigInjectorPlugin } from './makeConfigInjectorPlugin';\nimport { makeCustomSentryVitePlugins } from './makeCustomSentryVitePlugins';\nimport { makeEnableSourceMapsPlugin } from './makeEnableSourceMapsPlugin';\nimport { makeServerBuildCapturePlugin } from './makeServerBuildCapturePlugin';\nimport type { SentryReactRouterBuildOptions } from './types';\n\n/**\n * A Vite plugin for Sentry that handles source map uploads and bundle size optimizations.\n *\n * @param options - Configuration options for the Sentry Vite plugin\n * @param viteConfig - The Vite user config object\n * @returns An array of Vite plugins\n */\nexport async function sentryReactRouter(\n options: SentryReactRouterBuildOptions = {},\n viteConfig: ConfigEnv,\n): Promise<Plugin[]> {\n const plugins: Plugin[] = [];\n\n plugins.push(makeConfigInjectorPlugin(options));\n plugins.push(makeServerBuildCapturePlugin());\n\n if (process.env.NODE_ENV !== 'development' && viteConfig.command === 'build' && viteConfig.mode !== 'development') {\n plugins.push(makeEnableSourceMapsPlugin(options));\n plugins.push(...(await makeCustomSentryVitePlugins(options)));\n }\n\n return plugins;\n}\n"],"names":["makeConfigInjectorPlugin","makeServerBuildCapturePlugin","makeEnableSourceMapsPlugin","makeCustomSentryVitePlugins"],"mappings":";;;;;;;AAOA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,eAAe,iBAAiB;AACvC,EAAE,OAAO,GAAkC,EAAE;AAC7C,EAAE,UAAU;AACZ,EAAqB;AACrB,EAAE,MAAM,OAAO,GAAa,EAAE;;AAE9B,EAAE,OAAO,CAAC,IAAI,CAACA,iDAAwB,CAAC,OAAO,CAAC,CAAC;AACjD,EAAE,OAAO,CAAC,IAAI,CAACC,yDAA4B,EAAE,CAAC;;AAE9C,EAAE,IAAI,OAAO,CAAC,GAAG,CAAC,QAAA,KAAa,aAAA,IAAiB,UAAU,CAAC,OAAA,KAAY,OAAA,IAAW,UAAU,CAAC,IAAA,KAAS,aAAa,EAAE;AACrH,IAAI,OAAO,CAAC,IAAI,CAACC,qDAA0B,CAAC,OAAO,CAAC,CAAC;AACrD,IAAI,OAAO,CAAC,IAAI,CAAC,IAAI,MAAMC,uDAA2B,CAAC,OAAO,CAAC,CAAC,CAAC;AACjE,EAAE;;AAEF,EAAE,OAAO,OAAO;AAChB;;;;"}
|
|
@@ -8,6 +8,9 @@ const WINDOW = GLOBAL_OBJ ;
|
|
|
8
8
|
// Tracks active numeric navigation span to prevent duplicate spans when popstate fires
|
|
9
9
|
let currentNumericNavigationSpan;
|
|
10
10
|
|
|
11
|
+
// Per-request middleware counters, keyed by Request
|
|
12
|
+
const middlewareCountersMap = new WeakMap();
|
|
13
|
+
|
|
11
14
|
const SENTRY_CLIENT_INSTRUMENTATION_FLAG = '__sentryReactRouterClientInstrumentationUsed';
|
|
12
15
|
// Intentionally never reset - once set, instrumentation API handles all navigations for the session.
|
|
13
16
|
const SENTRY_NAVIGATE_HOOK_INVOKED_FLAG = '__sentryReactRouterNavigateHookInvoked';
|
|
@@ -189,6 +192,8 @@ function createSentryClientInstrumentation(
|
|
|
189
192
|
},
|
|
190
193
|
|
|
191
194
|
route(route) {
|
|
195
|
+
const routeId = route.id;
|
|
196
|
+
|
|
192
197
|
route.instrument({
|
|
193
198
|
async loader(callLoader, info) {
|
|
194
199
|
const urlPath = getPathFromRequest(info.request);
|
|
@@ -242,12 +247,24 @@ function createSentryClientInstrumentation(
|
|
|
242
247
|
const urlPath = getPathFromRequest(info.request);
|
|
243
248
|
const routePattern = normalizeRoutePath(getPattern(info)) || urlPath;
|
|
244
249
|
|
|
250
|
+
let counters = middlewareCountersMap.get(info.request);
|
|
251
|
+
if (!counters) {
|
|
252
|
+
counters = {};
|
|
253
|
+
middlewareCountersMap.set(info.request, counters);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
const middlewareIndex = counters[routeId] ?? 0;
|
|
257
|
+
counters[routeId] = middlewareIndex + 1;
|
|
258
|
+
|
|
245
259
|
await startSpan(
|
|
246
260
|
{
|
|
247
|
-
name:
|
|
261
|
+
name: `middleware ${routeId}`,
|
|
248
262
|
attributes: {
|
|
249
263
|
[SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'function.react_router.client_middleware',
|
|
250
264
|
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.react_router.instrumentation_api',
|
|
265
|
+
'react_router.route.id': routeId,
|
|
266
|
+
'http.route': routePattern,
|
|
267
|
+
'react_router.middleware.index': middlewareIndex,
|
|
251
268
|
},
|
|
252
269
|
},
|
|
253
270
|
async span => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createClientInstrumentation.js","sources":["../../../src/client/createClientInstrumentation.ts"],"sourcesContent":["import { startBrowserTracingNavigationSpan } from '@sentry/browser';\nimport type { Span } from '@sentry/core';\nimport {\n debug,\n getClient,\n GLOBAL_OBJ,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n SEMANTIC_ATTRIBUTE_SENTRY_SOURCE,\n SPAN_STATUS_ERROR,\n startSpan,\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';\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\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 * @experimental\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 currentNumericNavigationSpan.updateName(pathname);\n }\n currentNumericNavigationSpan = undefined;\n return;\n }\n\n // Only create a new span for actual browser back/forward button clicks\n startBrowserTracingNavigationSpan(client, {\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 });\n\n DEBUG_BUILD && debug.log('React Router popstate listener registered for browser back/forward navigation.');\n }\n\n router.instrument({\n async navigate(callNavigate, info) {\n // navigate(0) triggers a page reload - skip span creation, but still capture errors\n // (navigation can be rejected before reload, e.g., by a navigation guard)\n if (info.to === 0) {\n const result = await callNavigate();\n if (result.status === 'error' && result.error instanceof Error) {\n captureInstrumentationError(result, captureErrors, 'react_router.navigate', {\n 'http.url': info.currentUrl,\n });\n }\n return;\n }\n\n GLOBAL_WITH_FLAGS[SENTRY_NAVIGATE_HOOK_INVOKED_FLAG] = true;\n\n // Handle numeric navigations (navigate(-1), navigate(1), etc.)\n if (typeof info.to === 'number') {\n const client = getClient();\n let navigationSpan;\n\n if (client) {\n const navigationType = info.to < 0 ? 'router.back' : 'router.forward';\n const currentPathname = WINDOW.location?.pathname || info.currentUrl;\n\n navigationSpan = startBrowserTracingNavigationSpan(client, {\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\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 navigationSpan.updateName(WINDOW.location.pathname);\n }\n\n if (result.status === 'error' && result.error instanceof Error) {\n if (navigationSpan) {\n navigationSpan.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n }\n captureInstrumentationError(result, captureErrors, 'react_router.navigate', {\n 'http.url': WINDOW.location?.pathname || info.currentUrl,\n });\n }\n } finally {\n currentNumericNavigationSpan = undefined;\n }\n return;\n }\n\n // Handle string navigations (e.g., navigate('/about'))\n const client = getClient();\n const toPath = String(info.to);\n let navigationSpan;\n\n if (client) {\n navigationSpan = startBrowserTracingNavigationSpan(client, {\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 }\n\n const result = await callNavigate();\n if (result.status === 'error' && result.error instanceof Error) {\n if (navigationSpan) {\n navigationSpan.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n }\n captureInstrumentationError(result, captureErrors, 'react_router.navigate', {\n 'http.url': toPath,\n });\n }\n return;\n },\n\n async fetch(callFetch, info) {\n await startSpan(\n {\n name: `Fetcher ${info.fetcherKey}`,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'function.react_router.fetcher',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.react_router.instrumentation_api',\n },\n },\n async span => {\n const result = await callFetch();\n if (result.status === 'error' && result.error instanceof Error) {\n span.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n captureInstrumentationError(result, captureErrors, 'react_router.fetcher', {\n 'http.url': info.href,\n });\n }\n },\n );\n },\n });\n },\n\n route(route: InstrumentableRoute) {\n route.instrument({\n async loader(callLoader, info) {\n const urlPath = getPathFromRequest(info.request);\n const routePattern = normalizeRoutePath(getPattern(info)) || urlPath;\n\n await startSpan(\n {\n name: routePattern,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'function.react_router.client_loader',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.react_router.instrumentation_api',\n },\n },\n async span => {\n const result = await callLoader();\n if (result.status === 'error' && result.error instanceof Error) {\n span.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n captureInstrumentationError(result, captureErrors, 'react_router.client_loader', {\n 'http.url': urlPath,\n });\n }\n },\n );\n },\n\n async action(callAction, info) {\n const urlPath = getPathFromRequest(info.request);\n const routePattern = normalizeRoutePath(getPattern(info)) || urlPath;\n\n await startSpan(\n {\n name: routePattern,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'function.react_router.client_action',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.react_router.instrumentation_api',\n },\n },\n async span => {\n const result = await callAction();\n if (result.status === 'error' && result.error instanceof Error) {\n span.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n captureInstrumentationError(result, captureErrors, 'react_router.client_action', {\n 'http.url': urlPath,\n });\n }\n },\n );\n },\n\n async middleware(callMiddleware, info) {\n const urlPath = getPathFromRequest(info.request);\n const routePattern = normalizeRoutePath(getPattern(info)) || urlPath;\n\n await startSpan(\n {\n name: routePattern,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'function.react_router.client_middleware',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.react_router.instrumentation_api',\n },\n },\n async span => {\n const result = await callMiddleware();\n if (result.status === 'error' && result.error instanceof Error) {\n span.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n captureInstrumentationError(result, captureErrors, 'react_router.client_middleware', {\n 'http.url': urlPath,\n });\n }\n },\n );\n },\n\n async lazy(callLazy) {\n await startSpan(\n {\n name: 'Lazy Route Load',\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'function.react_router.client_lazy',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.react_router.instrumentation_api',\n },\n },\n async span => {\n const result = await callLazy();\n if (result.status === 'error' && result.error instanceof Error) {\n span.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n captureInstrumentationError(result, captureErrors, 'react_router.client_lazy', {});\n }\n },\n );\n },\n });\n },\n };\n}\n\n/**\n * Check if React Router's instrumentation API is being used on the client.\n * @experimental\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 * @experimental\n */\nexport function isNavigateHookInvoked(): boolean {\n return !!GLOBAL_WITH_FLAGS[SENTRY_NAVIGATE_HOOK_INVOKED_FLAG];\n}\n"],"names":[],"mappings":";;;;;AAgBA,MAAM,MAAA,GAAS,UAAA;;AAEf;AACA,IAAI,4BAA4B;;AAEhC,MAAM,kCAAA,GAAqC,8CAA8C;AACzF;AACA,MAAM,iCAAA,GAAoC,wCAAwC;AAClF,MAAM,mCAAA,GAAsC,0CAA0C;;AAQtF,MAAM,iBAAA,GAAoB,UAAA;;AAE1B;AACA;AACA;;AAUA;AACA;AACA;AACA;AACO,SAAS,iCAAiC;AACjD,EAAE,OAAO,GAA6C,EAAE;AACxD,EAAyB;AACzB,EAAE,MAAM,EAAE,aAAA,GAAgB,IAAA,EAAK,GAAI,OAAO;;AAE1C,EAAE,eAAe,KAAK,CAAC,GAAG,CAAC,kDAAkD,CAAC;;AAE9E,EAAE,OAAO;AACT,IAAI,MAAM,CAAC,MAAM,EAAwB;AACzC;AACA;AACA;AACA;AACA,MAAM,iBAAiB,CAAC,kCAAkC,CAAA,GAAI,IAAI;AAClE,MAAM,eAAe,KAAK,CAAC,GAAG,CAAC,iEAAiE,CAAC;;AAEjG;AACA,MAAM,IAAI,CAAC,iBAAiB,CAAC,mCAAmC,CAAA,IAAK,MAAM,CAAC,gBAAgB,EAAE;AAC9F,QAAQ,iBAAiB,CAAC,mCAAmC,CAAA,GAAI,IAAI;;AAErE,QAAQ,MAAM,CAAC,gBAAgB,CAAC,UAAU,EAAE,MAAM;AAClD,UAAU,MAAM,MAAA,GAAS,SAAS,EAAE;AACpC,UAAU,IAAI,CAAC,MAAM,EAAE;AACvB,YAAY,4BAAA,GAA+B,SAAS;AACpD,YAAY;AACZ,UAAU;;AAEV,UAAU,MAAM,WAAW,MAAM,CAAC,QAAQ,EAAE,QAAA,IAAY,GAAG;;AAE3D;AACA,UAAU,IAAI,4BAA4B,EAAE;AAC5C,YAAY,IAAI,4BAA4B,CAAC,WAAW,EAAE,EAAE;AAC5D,cAAc,4BAA4B,CAAC,UAAU,CAAC,QAAQ,CAAC;AAC/D,YAAY;AACZ,YAAY,4BAAA,GAA+B,SAAS;AACpD,YAAY;AACZ,UAAU;;AAEV;AACA,UAAU,iCAAiC,CAAC,MAAM,EAAE;AACpD,YAAY,IAAI,EAAE,QAAQ;AAC1B,YAAY,UAAU,EAAE;AACxB,cAAc,CAAC,gCAAgC,GAAG,KAAK;AACvD,cAAc,CAAC,4BAA4B,GAAG,YAAY;AAC1D,cAAc,CAAC,gCAAgC,GAAG,kDAAkD;AACpG,cAAc,iBAAiB,EAAE,kBAAkB;AACnD,aAAa;AACb,WAAW,CAAC;AACZ,QAAQ,CAAC,CAAC;;AAEV,QAAQ,eAAe,KAAK,CAAC,GAAG,CAAC,gFAAgF,CAAC;AAClH,MAAM;;AAEN,MAAM,MAAM,CAAC,UAAU,CAAC;AACxB,QAAQ,MAAM,QAAQ,CAAC,YAAY,EAAE,IAAI,EAAE;AAC3C;AACA;AACA,UAAU,IAAI,IAAI,CAAC,EAAA,KAAO,CAAC,EAAE;AAC7B,YAAY,MAAM,MAAA,GAAS,MAAM,YAAY,EAAE;AAC/C,YAAY,IAAI,MAAM,CAAC,MAAA,KAAW,OAAA,IAAW,MAAM,CAAC,KAAA,YAAiB,KAAK,EAAE;AAC5E,cAAc,2BAA2B,CAAC,MAAM,EAAE,aAAa,EAAE,uBAAuB,EAAE;AAC1F,gBAAgB,UAAU,EAAE,IAAI,CAAC,UAAU;AAC3C,eAAe,CAAC;AAChB,YAAY;AACZ,YAAY;AACZ,UAAU;;AAEV,UAAU,iBAAiB,CAAC,iCAAiC,CAAA,GAAI,IAAI;;AAErE;AACA,UAAU,IAAI,OAAO,IAAI,CAAC,EAAA,KAAO,QAAQ,EAAE;AAC3C,YAAY,MAAM,MAAA,GAAS,SAAS,EAAE;AACtC,YAAY,IAAI,cAAc;;AAE9B,YAAY,IAAI,MAAM,EAAE;AACxB,cAAc,MAAM,cAAA,GAAiB,IAAI,CAAC,EAAA,GAAK,CAAA,GAAI,aAAA,GAAgB,gBAAgB;AACnF,cAAc,MAAM,eAAA,GAAkB,MAAM,CAAC,QAAQ,EAAE,QAAA,IAAY,IAAI,CAAC,UAAU;;AAElF,cAAc,cAAA,GAAiB,iCAAiC,CAAC,MAAM,EAAE;AACzE,gBAAgB,IAAI,EAAE,eAAe;AACrC,gBAAgB,UAAU,EAAE;AAC5B,kBAAkB,CAAC,gCAAgC,GAAG,KAAK;AAC3D,kBAAkB,CAAC,4BAA4B,GAAG,YAAY;AAC9D,kBAAkB,CAAC,gCAAgC,GAAG,kDAAkD;AACxG,kBAAkB,iBAAiB,EAAE,cAAc;AACnD,iBAAiB;AACjB,eAAe,CAAC;;AAEhB;AACA,cAAc,4BAAA,GAA+B,cAAc;AAC3D,YAAY;;AAEZ,YAAY,IAAI;AAChB,cAAc,MAAM,MAAA,GAAS,MAAM,YAAY,EAAE;;AAEjD,cAAc,IAAI,cAAA,IAAkB,MAAM,CAAC,QAAQ,EAAE;AACrD,gBAAgB,cAAc,CAAC,UAAU,CAAC,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC;AACnE,cAAc;;AAEd,cAAc,IAAI,MAAM,CAAC,MAAA,KAAW,OAAA,IAAW,MAAM,CAAC,KAAA,YAAiB,KAAK,EAAE;AAC9E,gBAAgB,IAAI,cAAc,EAAE;AACpC,kBAAkB,cAAc,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,iBAAiB,EAAE,OAAO,EAAE,gBAAA,EAAkB,CAAC;AAClG,gBAAgB;AAChB,gBAAgB,2BAA2B,CAAC,MAAM,EAAE,aAAa,EAAE,uBAAuB,EAAE;AAC5F,kBAAkB,UAAU,EAAE,MAAM,CAAC,QAAQ,EAAE,QAAA,IAAY,IAAI,CAAC,UAAU;AAC1E,iBAAiB,CAAC;AAClB,cAAc;AACd,YAAY,UAAU;AACtB,cAAc,4BAAA,GAA+B,SAAS;AACtD,YAAY;AACZ,YAAY;AACZ,UAAU;;AAEV;AACA,UAAU,MAAM,MAAA,GAAS,SAAS,EAAE;AACpC,UAAU,MAAM,SAAS,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;AACxC,UAAU,IAAI,cAAc;;AAE5B,UAAU,IAAI,MAAM,EAAE;AACtB,YAAY,cAAA,GAAiB,iCAAiC,CAAC,MAAM,EAAE;AACvE,cAAc,IAAI,EAAE,MAAM;AAC1B,cAAc,UAAU,EAAE;AAC1B,gBAAgB,CAAC,gCAAgC,GAAG,KAAK;AACzD,gBAAgB,CAAC,4BAA4B,GAAG,YAAY;AAC5D,gBAAgB,CAAC,gCAAgC,GAAG,kDAAkD;AACtG,gBAAgB,iBAAiB,EAAE,iBAAiB;AACpD,eAAe;AACf,aAAa,CAAC;AACd,UAAU;;AAEV,UAAU,MAAM,MAAA,GAAS,MAAM,YAAY,EAAE;AAC7C,UAAU,IAAI,MAAM,CAAC,MAAA,KAAW,OAAA,IAAW,MAAM,CAAC,KAAA,YAAiB,KAAK,EAAE;AAC1E,YAAY,IAAI,cAAc,EAAE;AAChC,cAAc,cAAc,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,iBAAiB,EAAE,OAAO,EAAE,gBAAA,EAAkB,CAAC;AAC9F,YAAY;AACZ,YAAY,2BAA2B,CAAC,MAAM,EAAE,aAAa,EAAE,uBAAuB,EAAE;AACxF,cAAc,UAAU,EAAE,MAAM;AAChC,aAAa,CAAC;AACd,UAAU;AACV,UAAU;AACV,QAAQ,CAAC;;AAET,QAAQ,MAAM,KAAK,CAAC,SAAS,EAAE,IAAI,EAAE;AACrC,UAAU,MAAM,SAAS;AACzB,YAAY;AACZ,cAAc,IAAI,EAAE,CAAC,QAAQ,EAAE,IAAI,CAAC,UAAU,CAAC,CAAA;AACA,cAAA,UAAA,EAAA;AACA,gBAAA,CAAA,4BAAA,GAAA,+BAAA;AACA,gBAAA,CAAA,gCAAA,GAAA,gDAAA;AACA,eAAA;AACA,aAAA;AACA,YAAA,MAAA,IAAA,IAAA;AACA,cAAA,MAAA,MAAA,GAAA,MAAA,SAAA,EAAA;AACA,cAAA,IAAA,MAAA,CAAA,MAAA,KAAA,OAAA,IAAA,MAAA,CAAA,KAAA,YAAA,KAAA,EAAA;AACA,gBAAA,IAAA,CAAA,SAAA,CAAA,EAAA,IAAA,EAAA,iBAAA,EAAA,OAAA,EAAA,gBAAA,EAAA,CAAA;AACA,gBAAA,2BAAA,CAAA,MAAA,EAAA,aAAA,EAAA,sBAAA,EAAA;AACA,kBAAA,UAAA,EAAA,IAAA,CAAA,IAAA;AACA,iBAAA,CAAA;AACA,cAAA;AACA,YAAA,CAAA;AACA,WAAA;AACA,QAAA,CAAA;AACA,OAAA,CAAA;AACA,IAAA,CAAA;;AAEA,IAAA,KAAA,CAAA,KAAA,EAAA;AACA,MAAA,KAAA,CAAA,UAAA,CAAA;AACA,QAAA,MAAA,MAAA,CAAA,UAAA,EAAA,IAAA,EAAA;AACA,UAAA,MAAA,OAAA,GAAA,kBAAA,CAAA,IAAA,CAAA,OAAA,CAAA;AACA,UAAA,MAAA,YAAA,GAAA,kBAAA,CAAA,UAAA,CAAA,IAAA,CAAA,CAAA,IAAA,OAAA;;AAEA,UAAA,MAAA,SAAA;AACA,YAAA;AACA,cAAA,IAAA,EAAA,YAAA;AACA,cAAA,UAAA,EAAA;AACA,gBAAA,CAAA,4BAAA,GAAA,qCAAA;AACA,gBAAA,CAAA,gCAAA,GAAA,gDAAA;AACA,eAAA;AACA,aAAA;AACA,YAAA,MAAA,IAAA,IAAA;AACA,cAAA,MAAA,MAAA,GAAA,MAAA,UAAA,EAAA;AACA,cAAA,IAAA,MAAA,CAAA,MAAA,KAAA,OAAA,IAAA,MAAA,CAAA,KAAA,YAAA,KAAA,EAAA;AACA,gBAAA,IAAA,CAAA,SAAA,CAAA,EAAA,IAAA,EAAA,iBAAA,EAAA,OAAA,EAAA,gBAAA,EAAA,CAAA;AACA,gBAAA,2BAAA,CAAA,MAAA,EAAA,aAAA,EAAA,4BAAA,EAAA;AACA,kBAAA,UAAA,EAAA,OAAA;AACA,iBAAA,CAAA;AACA,cAAA;AACA,YAAA,CAAA;AACA,WAAA;AACA,QAAA,CAAA;;AAEA,QAAA,MAAA,MAAA,CAAA,UAAA,EAAA,IAAA,EAAA;AACA,UAAA,MAAA,OAAA,GAAA,kBAAA,CAAA,IAAA,CAAA,OAAA,CAAA;AACA,UAAA,MAAA,YAAA,GAAA,kBAAA,CAAA,UAAA,CAAA,IAAA,CAAA,CAAA,IAAA,OAAA;;AAEA,UAAA,MAAA,SAAA;AACA,YAAA;AACA,cAAA,IAAA,EAAA,YAAA;AACA,cAAA,UAAA,EAAA;AACA,gBAAA,CAAA,4BAAA,GAAA,qCAAA;AACA,gBAAA,CAAA,gCAAA,GAAA,gDAAA;AACA,eAAA;AACA,aAAA;AACA,YAAA,MAAA,IAAA,IAAA;AACA,cAAA,MAAA,MAAA,GAAA,MAAA,UAAA,EAAA;AACA,cAAA,IAAA,MAAA,CAAA,MAAA,KAAA,OAAA,IAAA,MAAA,CAAA,KAAA,YAAA,KAAA,EAAA;AACA,gBAAA,IAAA,CAAA,SAAA,CAAA,EAAA,IAAA,EAAA,iBAAA,EAAA,OAAA,EAAA,gBAAA,EAAA,CAAA;AACA,gBAAA,2BAAA,CAAA,MAAA,EAAA,aAAA,EAAA,4BAAA,EAAA;AACA,kBAAA,UAAA,EAAA,OAAA;AACA,iBAAA,CAAA;AACA,cAAA;AACA,YAAA,CAAA;AACA,WAAA;AACA,QAAA,CAAA;;AAEA,QAAA,MAAA,UAAA,CAAA,cAAA,EAAA,IAAA,EAAA;AACA,UAAA,MAAA,OAAA,GAAA,kBAAA,CAAA,IAAA,CAAA,OAAA,CAAA;AACA,UAAA,MAAA,YAAA,GAAA,kBAAA,CAAA,UAAA,CAAA,IAAA,CAAA,CAAA,IAAA,OAAA;;AAEA,UAAA,MAAA,SAAA;AACA,YAAA;AACA,cAAA,IAAA,EAAA,YAAA;AACA,cAAA,UAAA,EAAA;AACA,gBAAA,CAAA,4BAAA,GAAA,yCAAA;AACA,gBAAA,CAAA,gCAAA,GAAA,gDAAA;AACA,eAAA;AACA,aAAA;AACA,YAAA,MAAA,IAAA,IAAA;AACA,cAAA,MAAA,MAAA,GAAA,MAAA,cAAA,EAAA;AACA,cAAA,IAAA,MAAA,CAAA,MAAA,KAAA,OAAA,IAAA,MAAA,CAAA,KAAA,YAAA,KAAA,EAAA;AACA,gBAAA,IAAA,CAAA,SAAA,CAAA,EAAA,IAAA,EAAA,iBAAA,EAAA,OAAA,EAAA,gBAAA,EAAA,CAAA;AACA,gBAAA,2BAAA,CAAA,MAAA,EAAA,aAAA,EAAA,gCAAA,EAAA;AACA,kBAAA,UAAA,EAAA,OAAA;AACA,iBAAA,CAAA;AACA,cAAA;AACA,YAAA,CAAA;AACA,WAAA;AACA,QAAA,CAAA;;AAEA,QAAA,MAAA,IAAA,CAAA,QAAA,EAAA;AACA,UAAA,MAAA,SAAA;AACA,YAAA;AACA,cAAA,IAAA,EAAA,iBAAA;AACA,cAAA,UAAA,EAAA;AACA,gBAAA,CAAA,4BAAA,GAAA,mCAAA;AACA,gBAAA,CAAA,gCAAA,GAAA,gDAAA;AACA,eAAA;AACA,aAAA;AACA,YAAA,MAAA,IAAA,IAAA;AACA,cAAA,MAAA,MAAA,GAAA,MAAA,QAAA,EAAA;AACA,cAAA,IAAA,MAAA,CAAA,MAAA,KAAA,OAAA,IAAA,MAAA,CAAA,KAAA,YAAA,KAAA,EAAA;AACA,gBAAA,IAAA,CAAA,SAAA,CAAA,EAAA,IAAA,EAAA,iBAAA,EAAA,OAAA,EAAA,gBAAA,EAAA,CAAA;AACA,gBAAA,2BAAA,CAAA,MAAA,EAAA,aAAA,EAAA,0BAAA,EAAA,EAAA,CAAA;AACA,cAAA;AACA,YAAA,CAAA;AACA,WAAA;AACA,QAAA,CAAA;AACA,OAAA,CAAA;AACA,IAAA,CAAA;AACA,GAAA;AACA;;AAEA;AACA;AACA;AACA;AACA,SAAA,8BAAA,GAAA;AACA,EAAA,OAAA,CAAA,CAAA,iBAAA,CAAA,kCAAA,CAAA;AACA;;AAEA;AACA;AACA;AACA;AACA,SAAA,qBAAA,GAAA;AACA,EAAA,OAAA,CAAA,CAAA,iBAAA,CAAA,iCAAA,CAAA;AACA;;;;"}
|
|
1
|
+
{"version":3,"file":"createClientInstrumentation.js","sources":["../../../src/client/createClientInstrumentation.ts"],"sourcesContent":["import { startBrowserTracingNavigationSpan } from '@sentry/browser';\nimport type { Span } from '@sentry/core';\nimport {\n debug,\n getClient,\n GLOBAL_OBJ,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n SEMANTIC_ATTRIBUTE_SENTRY_SOURCE,\n SPAN_STATUS_ERROR,\n startSpan,\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';\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 * @experimental\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 currentNumericNavigationSpan.updateName(pathname);\n }\n currentNumericNavigationSpan = undefined;\n return;\n }\n\n // Only create a new span for actual browser back/forward button clicks\n startBrowserTracingNavigationSpan(client, {\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 });\n\n DEBUG_BUILD && debug.log('React Router popstate listener registered for browser back/forward navigation.');\n }\n\n router.instrument({\n async navigate(callNavigate, info) {\n // navigate(0) triggers a page reload - skip span creation, but still capture errors\n // (navigation can be rejected before reload, e.g., by a navigation guard)\n if (info.to === 0) {\n const result = await callNavigate();\n if (result.status === 'error' && result.error instanceof Error) {\n captureInstrumentationError(result, captureErrors, 'react_router.navigate', {\n 'http.url': info.currentUrl,\n });\n }\n return;\n }\n\n GLOBAL_WITH_FLAGS[SENTRY_NAVIGATE_HOOK_INVOKED_FLAG] = true;\n\n // Handle numeric navigations (navigate(-1), navigate(1), etc.)\n if (typeof info.to === 'number') {\n const client = getClient();\n let navigationSpan;\n\n if (client) {\n const navigationType = info.to < 0 ? 'router.back' : 'router.forward';\n const currentPathname = WINDOW.location?.pathname || info.currentUrl;\n\n navigationSpan = startBrowserTracingNavigationSpan(client, {\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\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 navigationSpan.updateName(WINDOW.location.pathname);\n }\n\n if (result.status === 'error' && result.error instanceof Error) {\n if (navigationSpan) {\n navigationSpan.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n }\n captureInstrumentationError(result, captureErrors, 'react_router.navigate', {\n 'http.url': WINDOW.location?.pathname || info.currentUrl,\n });\n }\n } finally {\n currentNumericNavigationSpan = undefined;\n }\n return;\n }\n\n // Handle string navigations (e.g., navigate('/about'))\n const client = getClient();\n const toPath = String(info.to);\n let navigationSpan;\n\n if (client) {\n navigationSpan = startBrowserTracingNavigationSpan(client, {\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 }\n\n const result = await callNavigate();\n if (result.status === 'error' && result.error instanceof Error) {\n if (navigationSpan) {\n navigationSpan.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n }\n captureInstrumentationError(result, captureErrors, 'react_router.navigate', {\n 'http.url': toPath,\n });\n }\n return;\n },\n\n async fetch(callFetch, info) {\n await startSpan(\n {\n name: `Fetcher ${info.fetcherKey}`,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'function.react_router.fetcher',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.react_router.instrumentation_api',\n },\n },\n async span => {\n const result = await callFetch();\n if (result.status === 'error' && result.error instanceof Error) {\n span.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n captureInstrumentationError(result, captureErrors, 'react_router.fetcher', {\n 'http.url': info.href,\n });\n }\n },\n );\n },\n });\n },\n\n route(route: InstrumentableRoute) {\n const routeId = route.id;\n\n route.instrument({\n async loader(callLoader, info) {\n const urlPath = getPathFromRequest(info.request);\n const routePattern = normalizeRoutePath(getPattern(info)) || urlPath;\n\n await startSpan(\n {\n name: routePattern,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'function.react_router.client_loader',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.react_router.instrumentation_api',\n },\n },\n async span => {\n const result = await callLoader();\n if (result.status === 'error' && result.error instanceof Error) {\n span.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n captureInstrumentationError(result, captureErrors, 'react_router.client_loader', {\n 'http.url': urlPath,\n });\n }\n },\n );\n },\n\n async action(callAction, info) {\n const urlPath = getPathFromRequest(info.request);\n const routePattern = normalizeRoutePath(getPattern(info)) || urlPath;\n\n await startSpan(\n {\n name: routePattern,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'function.react_router.client_action',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.react_router.instrumentation_api',\n },\n },\n async span => {\n const result = await callAction();\n if (result.status === 'error' && result.error instanceof Error) {\n span.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n captureInstrumentationError(result, captureErrors, 'react_router.client_action', {\n 'http.url': urlPath,\n });\n }\n },\n );\n },\n\n async middleware(callMiddleware, info) {\n const urlPath = getPathFromRequest(info.request);\n const routePattern = normalizeRoutePath(getPattern(info)) || urlPath;\n\n let counters = middlewareCountersMap.get(info.request);\n if (!counters) {\n counters = {};\n middlewareCountersMap.set(info.request, counters);\n }\n\n const middlewareIndex = counters[routeId] ?? 0;\n counters[routeId] = middlewareIndex + 1;\n\n await startSpan(\n {\n name: `middleware ${routeId}`,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'function.react_router.client_middleware',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.react_router.instrumentation_api',\n 'react_router.route.id': routeId,\n 'http.route': routePattern,\n 'react_router.middleware.index': middlewareIndex,\n },\n },\n async span => {\n const result = await callMiddleware();\n if (result.status === 'error' && result.error instanceof Error) {\n span.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n captureInstrumentationError(result, captureErrors, 'react_router.client_middleware', {\n 'http.url': urlPath,\n });\n }\n },\n );\n },\n\n async lazy(callLazy) {\n await startSpan(\n {\n name: 'Lazy Route Load',\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'function.react_router.client_lazy',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.react_router.instrumentation_api',\n },\n },\n async span => {\n const result = await callLazy();\n if (result.status === 'error' && result.error instanceof Error) {\n span.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n captureInstrumentationError(result, captureErrors, 'react_router.client_lazy', {});\n }\n },\n );\n },\n });\n },\n };\n}\n\n/**\n * Check if React Router's instrumentation API is being used on the client.\n * @experimental\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 * @experimental\n */\nexport function isNavigateHookInvoked(): boolean {\n return !!GLOBAL_WITH_FLAGS[SENTRY_NAVIGATE_HOOK_INVOKED_FLAG];\n}\n"],"names":[],"mappings":"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"}
|
package/build/esm/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"type":"module","version":"10.41.0
|
|
1
|
+
{"type":"module","version":"10.41.0"}
|
|
@@ -1,12 +1,15 @@
|
|
|
1
|
-
import { context } from '@opentelemetry/api';
|
|
1
|
+
import { createContextKey, context } from '@opentelemetry/api';
|
|
2
2
|
import { getRPCMetadata, RPCType } from '@opentelemetry/core';
|
|
3
3
|
import { ATTR_HTTP_ROUTE } from '@opentelemetry/semantic-conventions';
|
|
4
4
|
import { debug, startSpan, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, SEMANTIC_ATTRIBUTE_SENTRY_OP, SPAN_STATUS_ERROR, getActiveSpan, getRootSpan, updateSpanName, SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, flushIfServerless, getCurrentScope } from '@sentry/core';
|
|
5
5
|
import { DEBUG_BUILD } from '../common/debug-build.js';
|
|
6
6
|
import { captureInstrumentationError, getPathFromRequest, getPattern, normalizeRoutePath } from '../common/utils.js';
|
|
7
|
+
import { getMiddlewareName } from './serverBuild.js';
|
|
7
8
|
import { markInstrumentationApiUsed } from './serverGlobals.js';
|
|
8
9
|
export { isInstrumentationApiUsed } from './serverGlobals.js';
|
|
9
10
|
|
|
11
|
+
const MIDDLEWARE_COUNTER_KEY = createContextKey('sentry_react_router_middleware_counter');
|
|
12
|
+
|
|
10
13
|
/**
|
|
11
14
|
* Options for creating Sentry server instrumentation.
|
|
12
15
|
*/
|
|
@@ -31,61 +34,68 @@ function createSentryServerInstrumentation(
|
|
|
31
34
|
const activeSpan = getActiveSpan();
|
|
32
35
|
const existingRootSpan = activeSpan ? getRootSpan(activeSpan) : undefined;
|
|
33
36
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
37
|
+
const counterStore = { counters: {} };
|
|
38
|
+
const ctx = context.active().setValue(MIDDLEWARE_COUNTER_KEY, counterStore);
|
|
39
|
+
|
|
40
|
+
await context.with(ctx, async () => {
|
|
41
|
+
if (existingRootSpan) {
|
|
42
|
+
updateSpanName(existingRootSpan, `${info.request.method} ${pathname}`);
|
|
43
|
+
existingRootSpan.setAttributes({
|
|
44
|
+
[SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'http.server',
|
|
45
|
+
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.react_router.instrumentation_api',
|
|
46
|
+
[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'url',
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
try {
|
|
50
|
+
const result = await handleRequest();
|
|
51
|
+
if (result.status === 'error' && result.error instanceof Error) {
|
|
52
|
+
existingRootSpan.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });
|
|
53
|
+
captureInstrumentationError(result, captureErrors, 'react_router.request_handler', {
|
|
54
|
+
'http.method': info.request.method,
|
|
55
|
+
'http.url': pathname,
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
} finally {
|
|
59
|
+
await flushIfServerless();
|
|
50
60
|
}
|
|
51
|
-
}
|
|
52
|
-
await
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
'url.path': pathname,
|
|
65
|
-
'url.full': info.request.url,
|
|
61
|
+
} else {
|
|
62
|
+
await startSpan(
|
|
63
|
+
{
|
|
64
|
+
name: `${info.request.method} ${pathname}`,
|
|
65
|
+
forceTransaction: true,
|
|
66
|
+
attributes: {
|
|
67
|
+
[SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'http.server',
|
|
68
|
+
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.react_router.instrumentation_api',
|
|
69
|
+
[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'url',
|
|
70
|
+
'http.request.method': info.request.method,
|
|
71
|
+
'url.path': pathname,
|
|
72
|
+
'url.full': info.request.url,
|
|
73
|
+
},
|
|
66
74
|
},
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
}
|
|
75
|
+
async span => {
|
|
76
|
+
try {
|
|
77
|
+
const result = await handleRequest();
|
|
78
|
+
if (result.status === 'error' && result.error instanceof Error) {
|
|
79
|
+
span.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });
|
|
80
|
+
captureInstrumentationError(result, captureErrors, 'react_router.request_handler', {
|
|
81
|
+
'http.method': info.request.method,
|
|
82
|
+
'http.url': pathname,
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
} finally {
|
|
86
|
+
await flushIfServerless();
|
|
77
87
|
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
);
|
|
83
|
-
}
|
|
88
|
+
},
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
});
|
|
84
92
|
},
|
|
85
93
|
});
|
|
86
94
|
},
|
|
87
95
|
|
|
88
96
|
route(route) {
|
|
97
|
+
const routeId = route.id;
|
|
98
|
+
|
|
89
99
|
route.instrument({
|
|
90
100
|
async loader(callLoader, info) {
|
|
91
101
|
const urlPath = getPathFromRequest(info.request);
|
|
@@ -146,15 +156,29 @@ function createSentryServerInstrumentation(
|
|
|
146
156
|
const pattern = getPattern(info);
|
|
147
157
|
const routePattern = normalizeRoutePath(pattern) || urlPath;
|
|
148
158
|
|
|
149
|
-
// Update root span with parameterized route (same as loader/action)
|
|
150
159
|
updateRootSpanWithRoute(info.request.method, pattern, urlPath);
|
|
151
160
|
|
|
161
|
+
const counterStore = context.active().getValue(MIDDLEWARE_COUNTER_KEY)
|
|
162
|
+
|
|
163
|
+
;
|
|
164
|
+
let middlewareIndex = 0;
|
|
165
|
+
if (counterStore) {
|
|
166
|
+
middlewareIndex = counterStore.counters[routeId] ?? 0;
|
|
167
|
+
counterStore.counters[routeId] = middlewareIndex + 1;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const middlewareName = getMiddlewareName(routeId, middlewareIndex);
|
|
171
|
+
|
|
152
172
|
await startSpan(
|
|
153
173
|
{
|
|
154
|
-
name:
|
|
174
|
+
name: `middleware ${middlewareName || routeId}`,
|
|
155
175
|
attributes: {
|
|
156
176
|
[SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'function.react_router.middleware',
|
|
157
177
|
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.react_router.instrumentation_api',
|
|
178
|
+
'react_router.route.id': routeId,
|
|
179
|
+
[ATTR_HTTP_ROUTE]: routePattern,
|
|
180
|
+
...(middlewareName && { 'react_router.middleware.name': middlewareName }),
|
|
181
|
+
'react_router.middleware.index': middlewareIndex,
|
|
158
182
|
},
|
|
159
183
|
},
|
|
160
184
|
async span => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createServerInstrumentation.js","sources":["../../../src/server/createServerInstrumentation.ts"],"sourcesContent":["import { context } from '@opentelemetry/api';\nimport { getRPCMetadata, RPCType } from '@opentelemetry/core';\nimport { ATTR_HTTP_ROUTE } from '@opentelemetry/semantic-conventions';\nimport {\n debug,\n flushIfServerless,\n getActiveSpan,\n getCurrentScope,\n getRootSpan,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n SEMANTIC_ATTRIBUTE_SENTRY_SOURCE,\n SPAN_STATUS_ERROR,\n startSpan,\n updateSpanName,\n} from '@sentry/core';\nimport { DEBUG_BUILD } from '../common/debug-build';\nimport type { InstrumentableRequestHandler, InstrumentableRoute, ServerInstrumentation } from '../common/types';\nimport { captureInstrumentationError, getPathFromRequest, getPattern, normalizeRoutePath } from '../common/utils';\nimport { markInstrumentationApiUsed } from './serverGlobals';\n\n// Re-export for backward compatibility and external use\nexport { isInstrumentationApiUsed } from './serverGlobals';\n\n/**\n * Options for creating Sentry server instrumentation.\n */\nexport interface CreateSentryServerInstrumentationOptions {\n /**\n * Whether to capture errors from loaders/actions automatically.\n * @default true\n */\n captureErrors?: boolean;\n}\n\n/**\n * Creates a Sentry server instrumentation for React Router's instrumentation API.\n * @experimental\n */\nexport function createSentryServerInstrumentation(\n options: CreateSentryServerInstrumentationOptions = {},\n): ServerInstrumentation {\n const { captureErrors = true } = options;\n\n markInstrumentationApiUsed();\n DEBUG_BUILD && debug.log('React Router server instrumentation API enabled.');\n\n return {\n handler(handler: InstrumentableRequestHandler) {\n handler.instrument({\n async request(handleRequest, info) {\n const pathname = getPathFromRequest(info.request);\n const activeSpan = getActiveSpan();\n const existingRootSpan = activeSpan ? getRootSpan(activeSpan) : undefined;\n\n if (existingRootSpan) {\n updateSpanName(existingRootSpan, `${info.request.method} ${pathname}`);\n existingRootSpan.setAttributes({\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'http.server',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.react_router.instrumentation_api',\n [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'url',\n });\n\n try {\n const result = await handleRequest();\n if (result.status === 'error' && result.error instanceof Error) {\n existingRootSpan.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n captureInstrumentationError(result, captureErrors, 'react_router.request_handler', {\n 'http.method': info.request.method,\n 'http.url': pathname,\n });\n }\n } finally {\n await flushIfServerless();\n }\n } else {\n await startSpan(\n {\n name: `${info.request.method} ${pathname}`,\n forceTransaction: true,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'http.server',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.react_router.instrumentation_api',\n [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'url',\n 'http.request.method': info.request.method,\n 'url.path': pathname,\n 'url.full': info.request.url,\n },\n },\n async span => {\n try {\n const result = await handleRequest();\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.request_handler', {\n 'http.method': info.request.method,\n 'http.url': pathname,\n });\n }\n } finally {\n await flushIfServerless();\n }\n },\n );\n }\n },\n });\n },\n\n route(route: InstrumentableRoute) {\n route.instrument({\n async loader(callLoader, info) {\n const urlPath = getPathFromRequest(info.request);\n const pattern = getPattern(info);\n const routePattern = normalizeRoutePath(pattern) || urlPath;\n updateRootSpanWithRoute(info.request.method, pattern, urlPath);\n\n await startSpan(\n {\n name: routePattern,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'function.react_router.loader',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.react_router.instrumentation_api',\n },\n },\n async span => {\n const result = await callLoader();\n if (result.status === 'error' && result.error instanceof Error) {\n span.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n captureInstrumentationError(result, captureErrors, 'react_router.loader', {\n 'http.method': info.request.method,\n 'http.url': urlPath,\n });\n }\n },\n );\n },\n\n async action(callAction, info) {\n const urlPath = getPathFromRequest(info.request);\n const pattern = getPattern(info);\n const routePattern = normalizeRoutePath(pattern) || urlPath;\n updateRootSpanWithRoute(info.request.method, pattern, urlPath);\n\n await startSpan(\n {\n name: routePattern,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'function.react_router.action',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.react_router.instrumentation_api',\n },\n },\n async span => {\n const result = await callAction();\n if (result.status === 'error' && result.error instanceof Error) {\n span.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n captureInstrumentationError(result, captureErrors, 'react_router.action', {\n 'http.method': info.request.method,\n 'http.url': urlPath,\n });\n }\n },\n );\n },\n\n async middleware(callMiddleware, info) {\n const urlPath = getPathFromRequest(info.request);\n const pattern = getPattern(info);\n const routePattern = normalizeRoutePath(pattern) || urlPath;\n\n // Update root span with parameterized route (same as loader/action)\n updateRootSpanWithRoute(info.request.method, pattern, urlPath);\n\n await startSpan(\n {\n name: routePattern,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'function.react_router.middleware',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.react_router.instrumentation_api',\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.middleware', {\n 'http.method': info.request.method,\n 'http.url': urlPath,\n });\n }\n },\n );\n },\n\n async lazy(callLazy) {\n await startSpan(\n {\n name: 'Lazy Route Load',\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'function.react_router.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.lazy', {});\n }\n },\n );\n },\n });\n },\n };\n}\n\nfunction updateRootSpanWithRoute(method: string, pattern: string | undefined, urlPath: string): void {\n const activeSpan = getActiveSpan();\n if (!activeSpan) return;\n const rootSpan = getRootSpan(activeSpan);\n if (!rootSpan) return;\n\n // Skip update if URL path is invalid (failed to parse)\n if (!urlPath || urlPath === '<unknown>') {\n DEBUG_BUILD && debug.warn('Cannot update span with invalid URL path:', urlPath);\n return;\n }\n\n const hasPattern = !!pattern;\n const routeName = hasPattern ? normalizeRoutePath(pattern) || urlPath : urlPath;\n\n const rpcMetadata = getRPCMetadata(context.active());\n if (rpcMetadata?.type === RPCType.HTTP) {\n rpcMetadata.route = routeName;\n }\n\n const transactionName = `${method} ${routeName}`;\n updateSpanName(rootSpan, transactionName);\n rootSpan.setAttributes({\n [ATTR_HTTP_ROUTE]: routeName,\n [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: hasPattern ? 'route' : 'url',\n });\n\n // Also update the scope's transaction name so errors captured during this request\n // have the correct transaction name (not the initial placeholder like \"GET *\")\n getCurrentScope().setTransactionName(transactionName);\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"createServerInstrumentation.js","sources":["../../../src/server/createServerInstrumentation.ts"],"sourcesContent":["import { context, createContextKey } from '@opentelemetry/api';\nimport { getRPCMetadata, RPCType } from '@opentelemetry/core';\nimport { ATTR_HTTP_ROUTE } from '@opentelemetry/semantic-conventions';\nimport {\n debug,\n flushIfServerless,\n getActiveSpan,\n getCurrentScope,\n getRootSpan,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n SEMANTIC_ATTRIBUTE_SENTRY_SOURCE,\n SPAN_STATUS_ERROR,\n startSpan,\n updateSpanName,\n} from '@sentry/core';\nimport { DEBUG_BUILD } from '../common/debug-build';\nimport type { InstrumentableRequestHandler, InstrumentableRoute, ServerInstrumentation } from '../common/types';\nimport { captureInstrumentationError, getPathFromRequest, getPattern, normalizeRoutePath } from '../common/utils';\nimport { getMiddlewareName } from './serverBuild';\nimport { markInstrumentationApiUsed } from './serverGlobals';\n\nconst MIDDLEWARE_COUNTER_KEY = createContextKey('sentry_react_router_middleware_counter');\n\n// Re-export for backward compatibility and external use\nexport { isInstrumentationApiUsed } from './serverGlobals';\n\n/**\n * Options for creating Sentry server instrumentation.\n */\nexport interface CreateSentryServerInstrumentationOptions {\n /**\n * Whether to capture errors from loaders/actions automatically.\n * @default true\n */\n captureErrors?: boolean;\n}\n\n/**\n * Creates a Sentry server instrumentation for React Router's instrumentation API.\n * @experimental\n */\nexport function createSentryServerInstrumentation(\n options: CreateSentryServerInstrumentationOptions = {},\n): ServerInstrumentation {\n const { captureErrors = true } = options;\n\n markInstrumentationApiUsed();\n DEBUG_BUILD && debug.log('React Router server instrumentation API enabled.');\n\n return {\n handler(handler: InstrumentableRequestHandler) {\n handler.instrument({\n async request(handleRequest, info) {\n const pathname = getPathFromRequest(info.request);\n const activeSpan = getActiveSpan();\n const existingRootSpan = activeSpan ? getRootSpan(activeSpan) : undefined;\n\n const counterStore = { counters: {} as Record<string, number> };\n const ctx = context.active().setValue(MIDDLEWARE_COUNTER_KEY, counterStore);\n\n await context.with(ctx, async () => {\n if (existingRootSpan) {\n updateSpanName(existingRootSpan, `${info.request.method} ${pathname}`);\n existingRootSpan.setAttributes({\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'http.server',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.react_router.instrumentation_api',\n [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'url',\n });\n\n try {\n const result = await handleRequest();\n if (result.status === 'error' && result.error instanceof Error) {\n existingRootSpan.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n captureInstrumentationError(result, captureErrors, 'react_router.request_handler', {\n 'http.method': info.request.method,\n 'http.url': pathname,\n });\n }\n } finally {\n await flushIfServerless();\n }\n } else {\n await startSpan(\n {\n name: `${info.request.method} ${pathname}`,\n forceTransaction: true,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'http.server',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.react_router.instrumentation_api',\n [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'url',\n 'http.request.method': info.request.method,\n 'url.path': pathname,\n 'url.full': info.request.url,\n },\n },\n async span => {\n try {\n const result = await handleRequest();\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.request_handler', {\n 'http.method': info.request.method,\n 'http.url': pathname,\n });\n }\n } finally {\n await flushIfServerless();\n }\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 = getPattern(info);\n const routePattern = normalizeRoutePath(pattern) || urlPath;\n updateRootSpanWithRoute(info.request.method, pattern, urlPath);\n\n await startSpan(\n {\n name: routePattern,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'function.react_router.loader',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.react_router.instrumentation_api',\n },\n },\n async span => {\n const result = await callLoader();\n if (result.status === 'error' && result.error instanceof Error) {\n span.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n captureInstrumentationError(result, captureErrors, 'react_router.loader', {\n 'http.method': info.request.method,\n 'http.url': urlPath,\n });\n }\n },\n );\n },\n\n async action(callAction, info) {\n const urlPath = getPathFromRequest(info.request);\n const pattern = getPattern(info);\n const routePattern = normalizeRoutePath(pattern) || urlPath;\n updateRootSpanWithRoute(info.request.method, pattern, urlPath);\n\n await startSpan(\n {\n name: routePattern,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'function.react_router.action',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.react_router.instrumentation_api',\n },\n },\n async span => {\n const result = await callAction();\n if (result.status === 'error' && result.error instanceof Error) {\n span.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n captureInstrumentationError(result, captureErrors, 'react_router.action', {\n 'http.method': info.request.method,\n 'http.url': urlPath,\n });\n }\n },\n );\n },\n\n async middleware(callMiddleware, info) {\n const urlPath = getPathFromRequest(info.request);\n const pattern = getPattern(info);\n const routePattern = normalizeRoutePath(pattern) || urlPath;\n\n updateRootSpanWithRoute(info.request.method, pattern, urlPath);\n\n const counterStore = context.active().getValue(MIDDLEWARE_COUNTER_KEY) as\n | { counters: Record<string, number> }\n | undefined;\n let middlewareIndex = 0;\n if (counterStore) {\n middlewareIndex = counterStore.counters[routeId] ?? 0;\n counterStore.counters[routeId] = middlewareIndex + 1;\n }\n\n const middlewareName = getMiddlewareName(routeId, middlewareIndex);\n\n await startSpan(\n {\n name: `middleware ${middlewareName || routeId}`,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'function.react_router.middleware',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.react_router.instrumentation_api',\n 'react_router.route.id': routeId,\n [ATTR_HTTP_ROUTE]: routePattern,\n ...(middlewareName && { 'react_router.middleware.name': middlewareName }),\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.middleware', {\n 'http.method': info.request.method,\n 'http.url': urlPath,\n });\n }\n },\n );\n },\n\n async lazy(callLazy) {\n await startSpan(\n {\n name: 'Lazy Route Load',\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'function.react_router.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.lazy', {});\n }\n },\n );\n },\n });\n },\n };\n}\n\nfunction updateRootSpanWithRoute(method: string, pattern: string | undefined, urlPath: string): void {\n const activeSpan = getActiveSpan();\n if (!activeSpan) return;\n const rootSpan = getRootSpan(activeSpan);\n if (!rootSpan) return;\n\n // Skip update if URL path is invalid (failed to parse)\n if (!urlPath || urlPath === '<unknown>') {\n DEBUG_BUILD && debug.warn('Cannot update span with invalid URL path:', urlPath);\n return;\n }\n\n const hasPattern = !!pattern;\n const routeName = hasPattern ? normalizeRoutePath(pattern) || urlPath : urlPath;\n\n const rpcMetadata = getRPCMetadata(context.active());\n if (rpcMetadata?.type === RPCType.HTTP) {\n rpcMetadata.route = routeName;\n }\n\n const transactionName = `${method} ${routeName}`;\n updateSpanName(rootSpan, transactionName);\n rootSpan.setAttributes({\n [ATTR_HTTP_ROUTE]: routeName,\n [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: hasPattern ? 'route' : 'url',\n });\n\n // Also update the scope's transaction name so errors captured during this request\n // have the correct transaction name (not the initial placeholder like \"GET *\")\n getCurrentScope().setTransactionName(transactionName);\n}\n"],"names":[],"mappings":"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"}
|