@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
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","sources":["../../../src/common/utils.ts"],"sourcesContent":["import { captureException, debug } from '@sentry/core';\nimport { DEBUG_BUILD } from './debug-build';\nimport type { InstrumentationResult } from './types';\n\n/**\n * Extracts pathname from request URL.\n * Falls back to '<unknown>' with DEBUG warning if URL cannot be parsed.\n */\nexport function getPathFromRequest(request: { url: string }): string {\n try {\n return new URL(request.url).pathname;\n } catch {\n try {\n // Fallback: use a dummy base URL since we only care about the pathname\n return new URL(request.url, 'http://example.com').pathname;\n } catch (error) {\n DEBUG_BUILD && debug.warn('Failed to parse URL from request:', request.url, error);\n return '<unknown>';\n }\n }\n}\n\n/**\n * Extracts route pattern from instrumentation info.\n * Prefers `pattern` (planned for v8) over `unstable_pattern` (v7.x).\n */\nexport function getPattern(info: { pattern?: string; unstable_pattern?: string }): string | undefined {\n return info.pattern ?? info.unstable_pattern;\n}\n\n/**\n * Normalizes route path by ensuring it starts with a slash.\n * Returns undefined if the input is falsy.\n */\nexport function normalizeRoutePath(pattern?: string): string | undefined {\n if (!pattern) {\n return undefined;\n }\n return pattern.startsWith('/') ? pattern : `/${pattern}`;\n}\n\n/**\n * Captures an error from instrumentation result.\n * Caller must verify result contains an Error before calling.\n */\nexport function captureInstrumentationError(\n result: InstrumentationResult,\n captureErrors: boolean,\n mechanismType: string,\n data: Record<string, string | boolean>,\n): void {\n if (captureErrors) {\n captureException(result.error, {\n mechanism: {\n type: mechanismType,\n handled: false,\n data,\n },\n });\n }\n}\n"],"names":["DEBUG_BUILD","debug","captureException"],"mappings":";;;;;
|
|
1
|
+
{"version":3,"file":"utils.js","sources":["../../../src/common/utils.ts"],"sourcesContent":["import { captureException, debug } from '@sentry/core';\nimport { DEBUG_BUILD } from './debug-build';\nimport type { InstrumentationResult } from './types';\n\n/**\n * Extracts pathname from request URL.\n * Falls back to '<unknown>' with DEBUG warning if URL cannot be parsed.\n */\nexport function getPathFromRequest(request: { url: string }): string {\n try {\n return new URL(request.url).pathname;\n } catch {\n try {\n // Fallback: use a dummy base URL since we only care about the pathname\n return new URL(request.url, 'http://example.com').pathname;\n } catch (error) {\n DEBUG_BUILD && debug.warn('Failed to parse URL from request:', request.url, error);\n return '<unknown>';\n }\n }\n}\n\n/**\n * Extracts route pattern from instrumentation info.\n * Prefers `pattern` (planned for v8) over `unstable_pattern` (v7.x).\n */\nexport function getPattern(info: { pattern?: string; unstable_pattern?: string }): string | undefined {\n return info.pattern ?? info.unstable_pattern;\n}\n\n/**\n * Normalizes route path by ensuring it starts with a slash.\n * Returns undefined if the input is falsy.\n */\nexport function normalizeRoutePath(pattern?: string): string | undefined {\n if (!pattern) {\n return undefined;\n }\n return pattern.startsWith('/') ? pattern : `/${pattern}`;\n}\n\n/**\n * Captures an error from instrumentation result.\n * Caller must verify result contains an Error before calling.\n */\nexport function captureInstrumentationError(\n result: InstrumentationResult,\n captureErrors: boolean,\n mechanismType: string,\n data: Record<string, string | boolean>,\n): void {\n if (captureErrors) {\n captureException(result.error, {\n mechanism: {\n type: mechanismType,\n handled: false,\n data,\n },\n });\n }\n}\n"],"names":["DEBUG_BUILD","debug","captureException"],"mappings":";;;;;AAQO,SAAS,mBAAmB,OAAA,EAAkC;AACnE,EAAA,IAAI;AACF,IAAA,OAAO,IAAI,GAAA,CAAI,OAAA,CAAQ,GAAG,CAAA,CAAE,QAAA;AAAA,EAC9B,CAAA,CAAA,MAAQ;AACN,IAAA,IAAI;AAEF,MAAA,OAAO,IAAI,GAAA,CAAI,OAAA,CAAQ,GAAA,EAAK,oBAAoB,CAAA,CAAE,QAAA;AAAA,IACpD,SAAS,KAAA,EAAO;AACd,MAAAA,sBAAA,IAAeC,UAAA,CAAM,IAAA,CAAK,mCAAA,EAAqC,OAAA,CAAQ,KAAK,KAAK,CAAA;AACjF,MAAA,OAAO,WAAA;AAAA,IACT;AAAA,EACF;AACF;AAMO,SAAS,WAAW,IAAA,EAA2E;AACpG,EAAA,OAAO,IAAA,CAAK,WAAW,IAAA,CAAK,gBAAA;AAC9B;AAMO,SAAS,mBAAmB,OAAA,EAAsC;AACvE,EAAA,IAAI,CAAC,OAAA,EAAS;AACZ,IAAA,OAAO,MAAA;AAAA,EACT;AACA,EAAA,OAAO,QAAQ,UAAA,CAAW,GAAG,CAAA,GAAI,OAAA,GAAU,IAAI,OAAO,CAAA,CAAA;AACxD;AAMO,SAAS,2BAAA,CACd,MAAA,EACA,aAAA,EACA,aAAA,EACA,IAAA,EACM;AACN,EAAA,IAAI,aAAA,EAAe;AACjB,IAAAC,qBAAA,CAAiB,OAAO,KAAA,EAAO;AAAA,MAC7B,SAAA,EAAW;AAAA,QACT,IAAA,EAAM,aAAA;AAAA,QACN,OAAA,EAAS,KAAA;AAAA,QACT;AAAA;AACF,KACD,CAAA;AAAA,EACH;AACF;;;;;;;"}
|
|
@@ -2,33 +2,24 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
|
2
2
|
|
|
3
3
|
const core = require('@sentry/core');
|
|
4
4
|
|
|
5
|
-
/**
|
|
6
|
-
* A complete Sentry-instrumented handleError implementation that handles error reporting
|
|
7
|
-
*
|
|
8
|
-
* @returns A Sentry-instrumented handleError function
|
|
9
|
-
*/
|
|
10
5
|
function createSentryHandleError({ logErrors = false }) {
|
|
11
|
-
const handleError = async function
|
|
12
|
-
// React Router may abort some interrupted requests, don't report those
|
|
6
|
+
const handleError = async function handleError2(error, args) {
|
|
13
7
|
if (!args.request.signal.aborted) {
|
|
14
8
|
core.captureException(error, {
|
|
15
9
|
mechanism: {
|
|
16
|
-
type:
|
|
17
|
-
handled: false
|
|
18
|
-
}
|
|
10
|
+
type: "react-router",
|
|
11
|
+
handled: false
|
|
12
|
+
}
|
|
19
13
|
});
|
|
20
14
|
if (logErrors) {
|
|
21
|
-
// eslint-disable-next-line no-console
|
|
22
15
|
console.error(error);
|
|
23
16
|
}
|
|
24
17
|
try {
|
|
25
18
|
await core.flushIfServerless();
|
|
26
19
|
} catch {
|
|
27
|
-
// Ignore flush errors to ensure error handling completes gracefully
|
|
28
20
|
}
|
|
29
21
|
}
|
|
30
22
|
};
|
|
31
|
-
|
|
32
23
|
return handleError;
|
|
33
24
|
}
|
|
34
25
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createSentryHandleError.js","sources":["../../../src/server/createSentryHandleError.ts"],"sourcesContent":["import { captureException, flushIfServerless } from '@sentry/core';\nimport type { HandleErrorFunction } from 'react-router';\n\nexport type SentryHandleErrorOptions = {\n logErrors?: boolean;\n};\n\n/**\n * A complete Sentry-instrumented handleError implementation that handles error reporting\n *\n * @returns A Sentry-instrumented handleError function\n */\nexport function createSentryHandleError({ logErrors = false }: SentryHandleErrorOptions): HandleErrorFunction {\n const handleError: HandleErrorFunction = async function handleError(error, args): Promise<void> {\n // React Router may abort some interrupted requests, don't report those\n if (!args.request.signal.aborted) {\n captureException(error, {\n mechanism: {\n type: 'react-router',\n handled: false,\n },\n });\n if (logErrors) {\n // eslint-disable-next-line no-console\n console.error(error);\n }\n try {\n await flushIfServerless();\n } catch {\n // Ignore flush errors to ensure error handling completes gracefully\n }\n }\n };\n\n return handleError;\n}\n"],"names":["captureException","flushIfServerless"],"mappings":";;;;
|
|
1
|
+
{"version":3,"file":"createSentryHandleError.js","sources":["../../../src/server/createSentryHandleError.ts"],"sourcesContent":["import { captureException, flushIfServerless } from '@sentry/core';\nimport type { HandleErrorFunction } from 'react-router';\n\nexport type SentryHandleErrorOptions = {\n logErrors?: boolean;\n};\n\n/**\n * A complete Sentry-instrumented handleError implementation that handles error reporting\n *\n * @returns A Sentry-instrumented handleError function\n */\nexport function createSentryHandleError({ logErrors = false }: SentryHandleErrorOptions): HandleErrorFunction {\n const handleError: HandleErrorFunction = async function handleError(error, args): Promise<void> {\n // React Router may abort some interrupted requests, don't report those\n if (!args.request.signal.aborted) {\n captureException(error, {\n mechanism: {\n type: 'react-router',\n handled: false,\n },\n });\n if (logErrors) {\n // eslint-disable-next-line no-console\n console.error(error);\n }\n try {\n await flushIfServerless();\n } catch {\n // Ignore flush errors to ensure error handling completes gracefully\n }\n }\n };\n\n return handleError;\n}\n"],"names":["handleError","captureException","flushIfServerless"],"mappings":";;;;AAYO,SAAS,uBAAA,CAAwB,EAAE,SAAA,GAAY,KAAA,EAAM,EAAkD;AAC5G,EAAA,MAAM,WAAA,GAAmC,eAAeA,YAAAA,CAAY,KAAA,EAAO,IAAA,EAAqB;AAE9F,IAAA,IAAI,CAAC,IAAA,CAAK,OAAA,CAAQ,MAAA,CAAO,OAAA,EAAS;AAChC,MAAAC,qBAAA,CAAiB,KAAA,EAAO;AAAA,QACtB,SAAA,EAAW;AAAA,UACT,IAAA,EAAM,cAAA;AAAA,UACN,OAAA,EAAS;AAAA;AACX,OACD,CAAA;AACD,MAAA,IAAI,SAAA,EAAW;AAEb,QAAA,OAAA,CAAQ,MAAM,KAAK,CAAA;AAAA,MACrB;AACA,MAAA,IAAI;AACF,QAAA,MAAMC,sBAAA,EAAkB;AAAA,MAC1B,CAAA,CAAA,MAAQ;AAAA,MAER;AAAA,IACF;AAAA,EACF,CAAA;AAEA,EAAA,OAAO,WAAA;AACT;;;;"}
|
|
@@ -5,84 +5,49 @@ const stream = require('stream');
|
|
|
5
5
|
const getMetaTagTransformer = require('./getMetaTagTransformer.js');
|
|
6
6
|
const wrapSentryHandleRequest = require('./wrapSentryHandleRequest.js');
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
* A complete Sentry-instrumented handleRequest implementation that handles both
|
|
10
|
-
* route parametrization and trace meta tag injection.
|
|
11
|
-
*
|
|
12
|
-
* @param options Configuration options
|
|
13
|
-
* @returns A Sentry-instrumented handleRequest function
|
|
14
|
-
*/
|
|
15
|
-
function createSentryHandleRequest(
|
|
16
|
-
options,
|
|
17
|
-
) {
|
|
8
|
+
function createSentryHandleRequest(options) {
|
|
18
9
|
const {
|
|
19
|
-
streamTimeout =
|
|
10
|
+
streamTimeout = 1e4,
|
|
20
11
|
renderToPipeableStream,
|
|
21
12
|
ServerRouter,
|
|
22
13
|
createReadableStreamFromReadable,
|
|
23
|
-
botRegex = /bot|crawler|spider|googlebot|chrome-lighthouse|baidu|bing|google|yahoo|lighthouse/i
|
|
14
|
+
botRegex = /bot|crawler|spider|googlebot|chrome-lighthouse|baidu|bing|google|yahoo|lighthouse/i
|
|
24
15
|
} = options;
|
|
25
|
-
|
|
26
|
-
const handleRequest = function handleRequest(
|
|
27
|
-
request,
|
|
28
|
-
responseStatusCode,
|
|
29
|
-
responseHeaders,
|
|
30
|
-
routerContext,
|
|
31
|
-
_loadContext,
|
|
32
|
-
) {
|
|
16
|
+
const handleRequest = function handleRequest2(request, responseStatusCode, responseHeaders, routerContext, _loadContext) {
|
|
33
17
|
return new Promise((resolve, reject) => {
|
|
34
18
|
let shellRendered = false;
|
|
35
|
-
const userAgent = request.headers.get(
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
const
|
|
39
|
-
const
|
|
40
|
-
|
|
41
|
-
const readyOption = isBot || isSpaMode ? 'onAllReady' : 'onShellReady';
|
|
42
|
-
|
|
43
|
-
const { pipe, abort } = renderToPipeableStream(React.default.createElement(ServerRouter, { context: routerContext, url: request.url,} ), {
|
|
19
|
+
const userAgent = request.headers.get("user-agent");
|
|
20
|
+
const isBot = typeof userAgent === "string" && botRegex.test(userAgent);
|
|
21
|
+
const isSpaMode = !!routerContext.isSpaMode;
|
|
22
|
+
const readyOption = isBot || isSpaMode ? "onAllReady" : "onShellReady";
|
|
23
|
+
const { pipe, abort } = renderToPipeableStream(/* @__PURE__ */ React.default.createElement(ServerRouter, { context: routerContext, url: request.url }), {
|
|
44
24
|
[readyOption]() {
|
|
45
25
|
shellRendered = true;
|
|
46
26
|
const body = new stream.PassThrough();
|
|
47
|
-
|
|
48
27
|
const stream$1 = createReadableStreamFromReadable(body);
|
|
49
|
-
|
|
50
|
-
responseHeaders.set('Content-Type', 'text/html');
|
|
51
|
-
|
|
28
|
+
responseHeaders.set("Content-Type", "text/html");
|
|
52
29
|
resolve(
|
|
53
30
|
new Response(stream$1, {
|
|
54
31
|
headers: responseHeaders,
|
|
55
|
-
status: responseStatusCode
|
|
56
|
-
})
|
|
32
|
+
status: responseStatusCode
|
|
33
|
+
})
|
|
57
34
|
);
|
|
58
|
-
|
|
59
|
-
// this injects trace data to the HTML head
|
|
60
35
|
pipe(getMetaTagTransformer.getMetaTagTransformer(body));
|
|
61
36
|
},
|
|
62
37
|
onShellError(error) {
|
|
63
38
|
reject(error);
|
|
64
39
|
},
|
|
65
40
|
onError(error) {
|
|
66
|
-
// eslint-disable-next-line no-param-reassign
|
|
67
41
|
responseStatusCode = 500;
|
|
68
|
-
// Log streaming rendering errors from inside the shell. Don't log
|
|
69
|
-
// errors encountered during initial shell rendering since they'll
|
|
70
|
-
// reject and get logged in handleDocumentRequest.
|
|
71
42
|
if (shellRendered) {
|
|
72
|
-
// eslint-disable-next-line no-console
|
|
73
43
|
console.error(error);
|
|
74
44
|
}
|
|
75
|
-
}
|
|
45
|
+
}
|
|
76
46
|
});
|
|
77
|
-
|
|
78
|
-
// Abort the rendering stream after the `streamTimeout`
|
|
79
47
|
setTimeout(abort, streamTimeout);
|
|
80
48
|
});
|
|
81
49
|
};
|
|
82
|
-
|
|
83
|
-
// Wrap the handle request function for request parametrization
|
|
84
|
-
return wrapSentryHandleRequest.wrapSentryHandleRequest(handleRequest )
|
|
85
|
-
;
|
|
50
|
+
return wrapSentryHandleRequest.wrapSentryHandleRequest(handleRequest);
|
|
86
51
|
}
|
|
87
52
|
|
|
88
53
|
exports.createSentryHandleRequest = createSentryHandleRequest;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createSentryHandleRequest.js","sources":["../../../src/server/createSentryHandleRequest.tsx"],"sourcesContent":["import type { createReadableStreamFromReadable } from '@react-router/node';\nimport type { ReactNode } from 'react';\nimport React from 'react';\nimport type { AppLoadContext, EntryContext, RouterContextProvider, ServerRouter } from 'react-router';\nimport { PassThrough } from 'stream';\nimport { getMetaTagTransformer } from './getMetaTagTransformer';\nimport { wrapSentryHandleRequest } from './wrapSentryHandleRequest';\n\ntype RenderToPipeableStreamOptions = {\n [key: string]: unknown;\n onShellReady?: () => void;\n onAllReady?: () => void;\n onShellError?: (error: unknown) => void;\n onError?: (error: unknown) => void;\n};\n\ntype RenderToPipeableStreamResult = {\n pipe: (destination: NodeJS.WritableStream) => void;\n abort: () => void;\n};\n\ntype RenderToPipeableStreamFunction = (\n node: ReactNode,\n options: RenderToPipeableStreamOptions,\n) => RenderToPipeableStreamResult;\n\nexport interface SentryHandleRequestOptions {\n /**\n * Timeout in milliseconds after which the rendering stream will be aborted\n * @default 10000\n */\n streamTimeout?: number;\n\n /**\n * React's renderToPipeableStream function from 'react-dom/server'\n */\n renderToPipeableStream: RenderToPipeableStreamFunction;\n\n /**\n * The <ServerRouter /> component from '@react-router/server'\n */\n ServerRouter: typeof ServerRouter;\n\n /**\n * createReadableStreamFromReadable from '@react-router/node'\n */\n createReadableStreamFromReadable: typeof createReadableStreamFromReadable;\n\n /**\n * Regular expression to identify bot user agents\n * @default /bot|crawler|spider|googlebot|chrome-lighthouse|baidu|bing|google|yahoo|lighthouse/i\n */\n botRegex?: RegExp;\n}\n\ntype HandleRequestWithoutMiddleware = (\n request: Request,\n responseStatusCode: number,\n responseHeaders: Headers,\n routerContext: EntryContext,\n loadContext: AppLoadContext,\n) => Promise<unknown>;\n\ntype HandleRequestWithMiddleware = (\n request: Request,\n responseStatusCode: number,\n responseHeaders: Headers,\n routerContext: EntryContext,\n loadContext: RouterContextProvider,\n) => Promise<unknown>;\n\n/**\n * A complete Sentry-instrumented handleRequest implementation that handles both\n * route parametrization and trace meta tag injection.\n *\n * @param options Configuration options\n * @returns A Sentry-instrumented handleRequest function\n */\nexport function createSentryHandleRequest(\n options: SentryHandleRequestOptions,\n): HandleRequestWithoutMiddleware & HandleRequestWithMiddleware {\n const {\n streamTimeout = 10000,\n renderToPipeableStream,\n ServerRouter,\n createReadableStreamFromReadable,\n botRegex = /bot|crawler|spider|googlebot|chrome-lighthouse|baidu|bing|google|yahoo|lighthouse/i,\n } = options;\n\n const handleRequest = function handleRequest(\n request: Request,\n responseStatusCode: number,\n responseHeaders: Headers,\n routerContext: EntryContext,\n _loadContext: AppLoadContext | RouterContextProvider,\n ): Promise<Response> {\n return new Promise((resolve, reject) => {\n let shellRendered = false;\n const userAgent = request.headers.get('user-agent');\n\n // Determine if we should use onAllReady or onShellReady\n const isBot = typeof userAgent === 'string' && botRegex.test(userAgent);\n const isSpaMode = !!(routerContext as { isSpaMode?: boolean }).isSpaMode;\n\n const readyOption = isBot || isSpaMode ? 'onAllReady' : 'onShellReady';\n\n const { pipe, abort } = renderToPipeableStream(<ServerRouter context={routerContext} url={request.url} />, {\n [readyOption]() {\n shellRendered = true;\n const body = new PassThrough();\n\n const stream = createReadableStreamFromReadable(body);\n\n responseHeaders.set('Content-Type', 'text/html');\n\n resolve(\n new Response(stream, {\n headers: responseHeaders,\n status: responseStatusCode,\n }),\n );\n\n // this injects trace data to the HTML head\n pipe(getMetaTagTransformer(body));\n },\n onShellError(error: unknown) {\n reject(error);\n },\n onError(error: unknown) {\n // eslint-disable-next-line no-param-reassign\n responseStatusCode = 500;\n // Log streaming rendering errors from inside the shell. Don't log\n // errors encountered during initial shell rendering since they'll\n // reject and get logged in handleDocumentRequest.\n if (shellRendered) {\n // eslint-disable-next-line no-console\n console.error(error);\n }\n },\n });\n\n // Abort the rendering stream after the `streamTimeout`\n setTimeout(abort, streamTimeout);\n });\n };\n\n // Wrap the handle request function for request parametrization\n return wrapSentryHandleRequest(handleRequest as HandleRequestWithoutMiddleware) as HandleRequestWithoutMiddleware &\n HandleRequestWithMiddleware;\n}\n"],"names":["React","PassThrough","stream","getMetaTagTransformer","wrapSentryHandleRequest"],"mappings":";;;;;;;
|
|
1
|
+
{"version":3,"file":"createSentryHandleRequest.js","sources":["../../../src/server/createSentryHandleRequest.tsx"],"sourcesContent":["import type { createReadableStreamFromReadable } from '@react-router/node';\nimport type { ReactNode } from 'react';\nimport React from 'react';\nimport type { AppLoadContext, EntryContext, RouterContextProvider, ServerRouter } from 'react-router';\nimport { PassThrough } from 'stream';\nimport { getMetaTagTransformer } from './getMetaTagTransformer';\nimport { wrapSentryHandleRequest } from './wrapSentryHandleRequest';\n\ntype RenderToPipeableStreamOptions = {\n [key: string]: unknown;\n onShellReady?: () => void;\n onAllReady?: () => void;\n onShellError?: (error: unknown) => void;\n onError?: (error: unknown) => void;\n};\n\ntype RenderToPipeableStreamResult = {\n pipe: (destination: NodeJS.WritableStream) => void;\n abort: () => void;\n};\n\ntype RenderToPipeableStreamFunction = (\n node: ReactNode,\n options: RenderToPipeableStreamOptions,\n) => RenderToPipeableStreamResult;\n\nexport interface SentryHandleRequestOptions {\n /**\n * Timeout in milliseconds after which the rendering stream will be aborted\n * @default 10000\n */\n streamTimeout?: number;\n\n /**\n * React's renderToPipeableStream function from 'react-dom/server'\n */\n renderToPipeableStream: RenderToPipeableStreamFunction;\n\n /**\n * The <ServerRouter /> component from '@react-router/server'\n */\n ServerRouter: typeof ServerRouter;\n\n /**\n * createReadableStreamFromReadable from '@react-router/node'\n */\n createReadableStreamFromReadable: typeof createReadableStreamFromReadable;\n\n /**\n * Regular expression to identify bot user agents\n * @default /bot|crawler|spider|googlebot|chrome-lighthouse|baidu|bing|google|yahoo|lighthouse/i\n */\n botRegex?: RegExp;\n}\n\ntype HandleRequestWithoutMiddleware = (\n request: Request,\n responseStatusCode: number,\n responseHeaders: Headers,\n routerContext: EntryContext,\n loadContext: AppLoadContext,\n) => Promise<unknown>;\n\ntype HandleRequestWithMiddleware = (\n request: Request,\n responseStatusCode: number,\n responseHeaders: Headers,\n routerContext: EntryContext,\n loadContext: RouterContextProvider,\n) => Promise<unknown>;\n\n/**\n * A complete Sentry-instrumented handleRequest implementation that handles both\n * route parametrization and trace meta tag injection.\n *\n * @param options Configuration options\n * @returns A Sentry-instrumented handleRequest function\n */\nexport function createSentryHandleRequest(\n options: SentryHandleRequestOptions,\n): HandleRequestWithoutMiddleware & HandleRequestWithMiddleware {\n const {\n streamTimeout = 10000,\n renderToPipeableStream,\n ServerRouter,\n createReadableStreamFromReadable,\n botRegex = /bot|crawler|spider|googlebot|chrome-lighthouse|baidu|bing|google|yahoo|lighthouse/i,\n } = options;\n\n const handleRequest = function handleRequest(\n request: Request,\n responseStatusCode: number,\n responseHeaders: Headers,\n routerContext: EntryContext,\n _loadContext: AppLoadContext | RouterContextProvider,\n ): Promise<Response> {\n return new Promise((resolve, reject) => {\n let shellRendered = false;\n const userAgent = request.headers.get('user-agent');\n\n // Determine if we should use onAllReady or onShellReady\n const isBot = typeof userAgent === 'string' && botRegex.test(userAgent);\n const isSpaMode = !!(routerContext as { isSpaMode?: boolean }).isSpaMode;\n\n const readyOption = isBot || isSpaMode ? 'onAllReady' : 'onShellReady';\n\n const { pipe, abort } = renderToPipeableStream(<ServerRouter context={routerContext} url={request.url} />, {\n [readyOption]() {\n shellRendered = true;\n const body = new PassThrough();\n\n const stream = createReadableStreamFromReadable(body);\n\n responseHeaders.set('Content-Type', 'text/html');\n\n resolve(\n new Response(stream, {\n headers: responseHeaders,\n status: responseStatusCode,\n }),\n );\n\n // this injects trace data to the HTML head\n pipe(getMetaTagTransformer(body));\n },\n onShellError(error: unknown) {\n reject(error);\n },\n onError(error: unknown) {\n // eslint-disable-next-line no-param-reassign\n responseStatusCode = 500;\n // Log streaming rendering errors from inside the shell. Don't log\n // errors encountered during initial shell rendering since they'll\n // reject and get logged in handleDocumentRequest.\n if (shellRendered) {\n // eslint-disable-next-line no-console\n console.error(error);\n }\n },\n });\n\n // Abort the rendering stream after the `streamTimeout`\n setTimeout(abort, streamTimeout);\n });\n };\n\n // Wrap the handle request function for request parametrization\n return wrapSentryHandleRequest(handleRequest as HandleRequestWithoutMiddleware) as HandleRequestWithoutMiddleware &\n HandleRequestWithMiddleware;\n}\n"],"names":["handleRequest","React","PassThrough","stream","getMetaTagTransformer","wrapSentryHandleRequest"],"mappings":";;;;;;;AA8EO,SAAS,0BACd,OAAA,EAC8D;AAC9D,EAAA,MAAM;AAAA,IACJ,aAAA,GAAgB,GAAA;AAAA,IAChB,sBAAA;AAAA,IACA,YAAA;AAAA,IACA,gCAAA;AAAA,IACA,QAAA,GAAW;AAAA,GACb,GAAI,OAAA;AAEJ,EAAA,MAAM,gBAAgB,SAASA,cAAAA,CAC7B,SACA,kBAAA,EACA,eAAA,EACA,eACA,YAAA,EACmB;AACnB,IAAA,OAAO,IAAI,OAAA,CAAQ,CAAC,OAAA,EAAS,MAAA,KAAW;AACtC,MAAA,IAAI,aAAA,GAAgB,KAAA;AACpB,MAAA,MAAM,SAAA,GAAY,OAAA,CAAQ,OAAA,CAAQ,GAAA,CAAI,YAAY,CAAA;AAGlD,MAAA,MAAM,QAAQ,OAAO,SAAA,KAAc,QAAA,IAAY,QAAA,CAAS,KAAK,SAAS,CAAA;AACtE,MAAA,MAAM,SAAA,GAAY,CAAC,CAAE,aAAA,CAA0C,SAAA;AAE/D,MAAA,MAAM,WAAA,GAAc,KAAA,IAAS,SAAA,GAAY,YAAA,GAAe,cAAA;AAExD,MAAA,MAAM,EAAE,IAAA,EAAM,KAAA,EAAM,GAAI,sBAAA,iBAAuBC,aAAA,CAAA,aAAA,CAAC,YAAA,EAAA,EAAa,OAAA,EAAS,aAAA,EAAe,GAAA,EAAK,OAAA,CAAQ,GAAA,EAAK,CAAA,EAAI;AAAA,QACzG,CAAC,WAAW,CAAA,GAAI;AACd,UAAA,aAAA,GAAgB,IAAA;AAChB,UAAA,MAAM,IAAA,GAAO,IAAIC,kBAAA,EAAY;AAE7B,UAAA,MAAMC,QAAA,GAAS,iCAAiC,IAAI,CAAA;AAEpD,UAAA,eAAA,CAAgB,GAAA,CAAI,gBAAgB,WAAW,CAAA;AAE/C,UAAA,OAAA;AAAA,YACE,IAAI,SAASA,QAAA,EAAQ;AAAA,cACnB,OAAA,EAAS,eAAA;AAAA,cACT,MAAA,EAAQ;AAAA,aACT;AAAA,WACH;AAGA,UAAA,IAAA,CAAKC,2CAAA,CAAsB,IAAI,CAAC,CAAA;AAAA,QAClC,CAAA;AAAA,QACA,aAAa,KAAA,EAAgB;AAC3B,UAAA,MAAA,CAAO,KAAK,CAAA;AAAA,QACd,CAAA;AAAA,QACA,QAAQ,KAAA,EAAgB;AAEtB,UAAA,kBAAA,GAAqB,GAAA;AAIrB,UAAA,IAAI,aAAA,EAAe;AAEjB,YAAA,OAAA,CAAQ,MAAM,KAAK,CAAA;AAAA,UACrB;AAAA,QACF;AAAA,OACD,CAAA;AAGD,MAAA,UAAA,CAAW,OAAO,aAAa,CAAA;AAAA,IACjC,CAAC,CAAA;AAAA,EACH,CAAA;AAGA,EAAA,OAAOC,gDAAwB,aAA+C,CAAA;AAEhF;;;;"}
|
|
@@ -9,51 +9,35 @@ const utils = require('../common/utils.js');
|
|
|
9
9
|
const serverBuild = require('./serverBuild.js');
|
|
10
10
|
const serverGlobals = require('./serverGlobals.js');
|
|
11
11
|
|
|
12
|
-
const MIDDLEWARE_COUNTER_KEY = api.createContextKey(
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Options for creating Sentry server instrumentation.
|
|
16
|
-
*/
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Creates a Sentry server instrumentation for React Router's instrumentation API.
|
|
20
|
-
* @experimental
|
|
21
|
-
*/
|
|
22
|
-
function createSentryServerInstrumentation(
|
|
23
|
-
options = {},
|
|
24
|
-
) {
|
|
12
|
+
const MIDDLEWARE_COUNTER_KEY = api.createContextKey("sentry_react_router_middleware_counter");
|
|
13
|
+
function createSentryServerInstrumentation(options = {}) {
|
|
25
14
|
const { captureErrors = true } = options;
|
|
26
|
-
|
|
27
15
|
serverGlobals.markInstrumentationApiUsed();
|
|
28
|
-
debugBuild.DEBUG_BUILD && core.debug.log(
|
|
29
|
-
|
|
16
|
+
debugBuild.DEBUG_BUILD && core.debug.log("React Router server instrumentation API enabled.");
|
|
30
17
|
return {
|
|
31
18
|
handler(handler) {
|
|
32
19
|
handler.instrument({
|
|
33
20
|
async request(handleRequest, info) {
|
|
34
21
|
const pathname = utils.getPathFromRequest(info.request);
|
|
35
22
|
const activeSpan = core.getActiveSpan();
|
|
36
|
-
const existingRootSpan = activeSpan ? core.getRootSpan(activeSpan) :
|
|
37
|
-
|
|
38
|
-
const counterStore = { counters: {} };
|
|
23
|
+
const existingRootSpan = activeSpan ? core.getRootSpan(activeSpan) : void 0;
|
|
24
|
+
const counterStore = { counters: {} };
|
|
39
25
|
const ctx = api.context.active().setValue(MIDDLEWARE_COUNTER_KEY, counterStore);
|
|
40
|
-
|
|
41
26
|
await api.context.with(ctx, async () => {
|
|
42
27
|
if (existingRootSpan) {
|
|
43
28
|
core.updateSpanName(existingRootSpan, `${info.request.method} ${pathname}`);
|
|
44
29
|
existingRootSpan.setAttributes({
|
|
45
|
-
[core.SEMANTIC_ATTRIBUTE_SENTRY_OP]:
|
|
46
|
-
[core.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]:
|
|
47
|
-
[core.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]:
|
|
30
|
+
[core.SEMANTIC_ATTRIBUTE_SENTRY_OP]: "http.server",
|
|
31
|
+
[core.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: "auto.http.react_router.instrumentation_api",
|
|
32
|
+
[core.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: "url"
|
|
48
33
|
});
|
|
49
|
-
|
|
50
34
|
try {
|
|
51
35
|
const result = await handleRequest();
|
|
52
|
-
if (result.status ===
|
|
53
|
-
existingRootSpan.setStatus({ code: core.SPAN_STATUS_ERROR, message:
|
|
54
|
-
utils.captureInstrumentationError(result, captureErrors,
|
|
55
|
-
|
|
56
|
-
|
|
36
|
+
if (result.status === "error" && result.error instanceof Error) {
|
|
37
|
+
existingRootSpan.setStatus({ code: core.SPAN_STATUS_ERROR, message: "internal_error" });
|
|
38
|
+
utils.captureInstrumentationError(result, captureErrors, "react_router.request_handler", {
|
|
39
|
+
"http.method": info.request.method,
|
|
40
|
+
"http.url": pathname
|
|
57
41
|
});
|
|
58
42
|
}
|
|
59
43
|
} finally {
|
|
@@ -65,188 +49,166 @@ function createSentryServerInstrumentation(
|
|
|
65
49
|
name: `${info.request.method} ${pathname}`,
|
|
66
50
|
forceTransaction: true,
|
|
67
51
|
attributes: {
|
|
68
|
-
[core.SEMANTIC_ATTRIBUTE_SENTRY_OP]:
|
|
69
|
-
[core.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]:
|
|
70
|
-
[core.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]:
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
}
|
|
52
|
+
[core.SEMANTIC_ATTRIBUTE_SENTRY_OP]: "http.server",
|
|
53
|
+
[core.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: "auto.http.react_router.instrumentation_api",
|
|
54
|
+
[core.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: "url",
|
|
55
|
+
"http.request.method": info.request.method,
|
|
56
|
+
"url.path": pathname,
|
|
57
|
+
"url.full": info.request.url
|
|
58
|
+
}
|
|
75
59
|
},
|
|
76
|
-
async span => {
|
|
60
|
+
async (span) => {
|
|
77
61
|
try {
|
|
78
62
|
const result = await handleRequest();
|
|
79
|
-
if (result.status ===
|
|
80
|
-
span.setStatus({ code: core.SPAN_STATUS_ERROR, message:
|
|
81
|
-
utils.captureInstrumentationError(result, captureErrors,
|
|
82
|
-
|
|
83
|
-
|
|
63
|
+
if (result.status === "error" && result.error instanceof Error) {
|
|
64
|
+
span.setStatus({ code: core.SPAN_STATUS_ERROR, message: "internal_error" });
|
|
65
|
+
utils.captureInstrumentationError(result, captureErrors, "react_router.request_handler", {
|
|
66
|
+
"http.method": info.request.method,
|
|
67
|
+
"http.url": pathname
|
|
84
68
|
});
|
|
85
69
|
}
|
|
86
70
|
} finally {
|
|
87
71
|
await core.flushIfServerless();
|
|
88
72
|
}
|
|
89
|
-
}
|
|
73
|
+
}
|
|
90
74
|
);
|
|
91
75
|
}
|
|
92
76
|
});
|
|
93
|
-
}
|
|
77
|
+
}
|
|
94
78
|
});
|
|
95
79
|
},
|
|
96
|
-
|
|
97
80
|
route(route) {
|
|
98
81
|
const routeId = route.id;
|
|
99
|
-
|
|
100
82
|
route.instrument({
|
|
101
83
|
async loader(callLoader, info) {
|
|
102
84
|
const urlPath = utils.getPathFromRequest(info.request);
|
|
103
85
|
const pattern = utils.getPattern(info);
|
|
104
86
|
const routePattern = utils.normalizeRoutePath(pattern) || urlPath;
|
|
105
87
|
updateRootSpanWithRoute(info.request.method, pattern, urlPath);
|
|
106
|
-
|
|
107
88
|
await core.startSpan(
|
|
108
89
|
{
|
|
109
90
|
name: routePattern,
|
|
110
91
|
attributes: {
|
|
111
|
-
[core.SEMANTIC_ATTRIBUTE_SENTRY_OP]:
|
|
112
|
-
[core.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]:
|
|
113
|
-
}
|
|
92
|
+
[core.SEMANTIC_ATTRIBUTE_SENTRY_OP]: "function.react_router.loader",
|
|
93
|
+
[core.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: "auto.function.react_router.instrumentation_api"
|
|
94
|
+
}
|
|
114
95
|
},
|
|
115
|
-
async span => {
|
|
96
|
+
async (span) => {
|
|
116
97
|
const result = await callLoader();
|
|
117
|
-
if (result.status ===
|
|
118
|
-
span.setStatus({ code: core.SPAN_STATUS_ERROR, message:
|
|
119
|
-
utils.captureInstrumentationError(result, captureErrors,
|
|
120
|
-
|
|
121
|
-
|
|
98
|
+
if (result.status === "error" && result.error instanceof Error) {
|
|
99
|
+
span.setStatus({ code: core.SPAN_STATUS_ERROR, message: "internal_error" });
|
|
100
|
+
utils.captureInstrumentationError(result, captureErrors, "react_router.loader", {
|
|
101
|
+
"http.method": info.request.method,
|
|
102
|
+
"http.url": urlPath
|
|
122
103
|
});
|
|
123
104
|
}
|
|
124
|
-
}
|
|
105
|
+
}
|
|
125
106
|
);
|
|
126
107
|
},
|
|
127
|
-
|
|
128
108
|
async action(callAction, info) {
|
|
129
109
|
const urlPath = utils.getPathFromRequest(info.request);
|
|
130
110
|
const pattern = utils.getPattern(info);
|
|
131
111
|
const routePattern = utils.normalizeRoutePath(pattern) || urlPath;
|
|
132
112
|
updateRootSpanWithRoute(info.request.method, pattern, urlPath);
|
|
133
|
-
|
|
134
113
|
await core.startSpan(
|
|
135
114
|
{
|
|
136
115
|
name: routePattern,
|
|
137
116
|
attributes: {
|
|
138
|
-
[core.SEMANTIC_ATTRIBUTE_SENTRY_OP]:
|
|
139
|
-
[core.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]:
|
|
140
|
-
}
|
|
117
|
+
[core.SEMANTIC_ATTRIBUTE_SENTRY_OP]: "function.react_router.action",
|
|
118
|
+
[core.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: "auto.function.react_router.instrumentation_api"
|
|
119
|
+
}
|
|
141
120
|
},
|
|
142
|
-
async span => {
|
|
121
|
+
async (span) => {
|
|
143
122
|
const result = await callAction();
|
|
144
|
-
if (result.status ===
|
|
145
|
-
span.setStatus({ code: core.SPAN_STATUS_ERROR, message:
|
|
146
|
-
utils.captureInstrumentationError(result, captureErrors,
|
|
147
|
-
|
|
148
|
-
|
|
123
|
+
if (result.status === "error" && result.error instanceof Error) {
|
|
124
|
+
span.setStatus({ code: core.SPAN_STATUS_ERROR, message: "internal_error" });
|
|
125
|
+
utils.captureInstrumentationError(result, captureErrors, "react_router.action", {
|
|
126
|
+
"http.method": info.request.method,
|
|
127
|
+
"http.url": urlPath
|
|
149
128
|
});
|
|
150
129
|
}
|
|
151
|
-
}
|
|
130
|
+
}
|
|
152
131
|
);
|
|
153
132
|
},
|
|
154
|
-
|
|
155
133
|
async middleware(callMiddleware, info) {
|
|
156
134
|
const urlPath = utils.getPathFromRequest(info.request);
|
|
157
135
|
const pattern = utils.getPattern(info);
|
|
158
136
|
const routePattern = utils.normalizeRoutePath(pattern) || urlPath;
|
|
159
|
-
|
|
160
137
|
updateRootSpanWithRoute(info.request.method, pattern, urlPath);
|
|
161
|
-
|
|
162
|
-
const counterStore = api.context.active().getValue(MIDDLEWARE_COUNTER_KEY)
|
|
163
|
-
|
|
164
|
-
;
|
|
138
|
+
const counterStore = api.context.active().getValue(MIDDLEWARE_COUNTER_KEY);
|
|
165
139
|
let middlewareIndex = 0;
|
|
166
140
|
if (counterStore) {
|
|
167
141
|
middlewareIndex = counterStore.counters[routeId] ?? 0;
|
|
168
142
|
counterStore.counters[routeId] = middlewareIndex + 1;
|
|
169
143
|
}
|
|
170
|
-
|
|
171
144
|
const middlewareName = serverBuild.getMiddlewareName(routeId, middlewareIndex);
|
|
172
|
-
|
|
173
145
|
await core.startSpan(
|
|
174
146
|
{
|
|
175
147
|
name: `middleware ${middlewareName || routeId}`,
|
|
176
148
|
attributes: {
|
|
177
|
-
[core.SEMANTIC_ATTRIBUTE_SENTRY_OP]:
|
|
178
|
-
[core.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]:
|
|
179
|
-
|
|
149
|
+
[core.SEMANTIC_ATTRIBUTE_SENTRY_OP]: "function.react_router.middleware",
|
|
150
|
+
[core.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: "auto.function.react_router.instrumentation_api",
|
|
151
|
+
"react_router.route.id": routeId,
|
|
180
152
|
[semanticConventions.ATTR_HTTP_ROUTE]: routePattern,
|
|
181
|
-
...
|
|
182
|
-
|
|
183
|
-
}
|
|
153
|
+
...middlewareName && { "react_router.middleware.name": middlewareName },
|
|
154
|
+
"react_router.middleware.index": middlewareIndex
|
|
155
|
+
}
|
|
184
156
|
},
|
|
185
|
-
async span => {
|
|
157
|
+
async (span) => {
|
|
186
158
|
const result = await callMiddleware();
|
|
187
|
-
if (result.status ===
|
|
188
|
-
span.setStatus({ code: core.SPAN_STATUS_ERROR, message:
|
|
189
|
-
utils.captureInstrumentationError(result, captureErrors,
|
|
190
|
-
|
|
191
|
-
|
|
159
|
+
if (result.status === "error" && result.error instanceof Error) {
|
|
160
|
+
span.setStatus({ code: core.SPAN_STATUS_ERROR, message: "internal_error" });
|
|
161
|
+
utils.captureInstrumentationError(result, captureErrors, "react_router.middleware", {
|
|
162
|
+
"http.method": info.request.method,
|
|
163
|
+
"http.url": urlPath
|
|
192
164
|
});
|
|
193
165
|
}
|
|
194
|
-
}
|
|
166
|
+
}
|
|
195
167
|
);
|
|
196
168
|
},
|
|
197
|
-
|
|
198
169
|
async lazy(callLazy) {
|
|
199
170
|
await core.startSpan(
|
|
200
171
|
{
|
|
201
|
-
name:
|
|
172
|
+
name: "Lazy Route Load",
|
|
202
173
|
attributes: {
|
|
203
|
-
[core.SEMANTIC_ATTRIBUTE_SENTRY_OP]:
|
|
204
|
-
[core.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]:
|
|
205
|
-
}
|
|
174
|
+
[core.SEMANTIC_ATTRIBUTE_SENTRY_OP]: "function.react_router.lazy",
|
|
175
|
+
[core.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: "auto.function.react_router.instrumentation_api"
|
|
176
|
+
}
|
|
206
177
|
},
|
|
207
|
-
async span => {
|
|
178
|
+
async (span) => {
|
|
208
179
|
const result = await callLazy();
|
|
209
|
-
if (result.status ===
|
|
210
|
-
span.setStatus({ code: core.SPAN_STATUS_ERROR, message:
|
|
211
|
-
utils.captureInstrumentationError(result, captureErrors,
|
|
180
|
+
if (result.status === "error" && result.error instanceof Error) {
|
|
181
|
+
span.setStatus({ code: core.SPAN_STATUS_ERROR, message: "internal_error" });
|
|
182
|
+
utils.captureInstrumentationError(result, captureErrors, "react_router.lazy", {});
|
|
212
183
|
}
|
|
213
|
-
}
|
|
184
|
+
}
|
|
214
185
|
);
|
|
215
|
-
}
|
|
186
|
+
}
|
|
216
187
|
});
|
|
217
|
-
}
|
|
188
|
+
}
|
|
218
189
|
};
|
|
219
190
|
}
|
|
220
|
-
|
|
221
191
|
function updateRootSpanWithRoute(method, pattern, urlPath) {
|
|
222
192
|
const activeSpan = core.getActiveSpan();
|
|
223
193
|
if (!activeSpan) return;
|
|
224
194
|
const rootSpan = core.getRootSpan(activeSpan);
|
|
225
195
|
if (!rootSpan) return;
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
if (!urlPath || urlPath === '<unknown>') {
|
|
229
|
-
debugBuild.DEBUG_BUILD && core.debug.warn('Cannot update span with invalid URL path:', urlPath);
|
|
196
|
+
if (!urlPath || urlPath === "<unknown>") {
|
|
197
|
+
debugBuild.DEBUG_BUILD && core.debug.warn("Cannot update span with invalid URL path:", urlPath);
|
|
230
198
|
return;
|
|
231
199
|
}
|
|
232
|
-
|
|
233
200
|
const hasPattern = !!pattern;
|
|
234
201
|
const routeName = hasPattern ? utils.normalizeRoutePath(pattern) || urlPath : urlPath;
|
|
235
|
-
|
|
236
202
|
const rpcMetadata = core$1.getRPCMetadata(api.context.active());
|
|
237
203
|
if (rpcMetadata?.type === core$1.RPCType.HTTP) {
|
|
238
204
|
rpcMetadata.route = routeName;
|
|
239
205
|
}
|
|
240
|
-
|
|
241
206
|
const transactionName = `${method} ${routeName}`;
|
|
242
207
|
core.updateSpanName(rootSpan, transactionName);
|
|
243
208
|
rootSpan.setAttributes({
|
|
244
209
|
[semanticConventions.ATTR_HTTP_ROUTE]: routeName,
|
|
245
|
-
[core.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: hasPattern ?
|
|
210
|
+
[core.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: hasPattern ? "route" : "url"
|
|
246
211
|
});
|
|
247
|
-
|
|
248
|
-
// Also update the scope's transaction name so errors captured during this request
|
|
249
|
-
// have the correct transaction name (not the initial placeholder like "GET *")
|
|
250
212
|
core.getCurrentScope().setTransactionName(transactionName);
|
|
251
213
|
}
|
|
252
214
|
|