@sentry/react-router 11.0.0-alpha.1 → 11.0.0-alpha.2

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.
Files changed (80) hide show
  1. package/README.md +2 -2
  2. package/build/cjs/client/createClientInstrumentation.js +30 -23
  3. package/build/cjs/client/createClientInstrumentation.js.map +1 -1
  4. package/build/cjs/client/hydratedRouter.js +11 -19
  5. package/build/cjs/client/hydratedRouter.js.map +1 -1
  6. package/build/cjs/client/tracingIntegration.js.map +1 -1
  7. package/build/cjs/client/utils.js +32 -12
  8. package/build/cjs/client/utils.js.map +1 -1
  9. package/build/cjs/cloudflare/index.js +3 -2
  10. package/build/cjs/cloudflare/index.js.map +1 -1
  11. package/build/cjs/common/utils.js.map +1 -1
  12. package/build/cjs/index.server.js +0 -6
  13. package/build/cjs/index.server.js.map +1 -1
  14. package/build/cjs/server/createServerInstrumentation.js +22 -15
  15. package/build/cjs/server/createServerInstrumentation.js.map +1 -1
  16. package/build/cjs/server/getMetaTagTransformer.js +3 -2
  17. package/build/cjs/server/getMetaTagTransformer.js.map +1 -1
  18. package/build/cjs/server/integration/lowQualityTransactionsFilterIntegration.js +3 -2
  19. package/build/cjs/server/integration/lowQualityTransactionsFilterIntegration.js.map +1 -1
  20. package/build/cjs/server/wrapSentryHandleRequest.js +2 -2
  21. package/build/cjs/server/wrapSentryHandleRequest.js.map +1 -1
  22. package/build/cjs/vite/buildEnd/handleOnBuildEnd.js +17 -29
  23. package/build/cjs/vite/buildEnd/handleOnBuildEnd.js.map +1 -1
  24. package/build/cjs/vite/index.js +12 -0
  25. package/build/cjs/vite/index.js.map +1 -0
  26. package/build/cjs/vite/makeCustomSentryVitePlugins.js +21 -32
  27. package/build/cjs/vite/makeCustomSentryVitePlugins.js.map +1 -1
  28. package/build/esm/client/createClientInstrumentation.js +22 -15
  29. package/build/esm/client/createClientInstrumentation.js.map +1 -1
  30. package/build/esm/client/hydratedRouter.js +14 -22
  31. package/build/esm/client/hydratedRouter.js.map +1 -1
  32. package/build/esm/client/tracingIntegration.js.map +1 -1
  33. package/build/esm/client/utils.js +34 -14
  34. package/build/esm/client/utils.js.map +1 -1
  35. package/build/esm/cloudflare/index.js +3 -2
  36. package/build/esm/cloudflare/index.js.map +1 -1
  37. package/build/esm/common/utils.js.map +1 -1
  38. package/build/esm/index.server.js +0 -3
  39. package/build/esm/index.server.js.map +1 -1
  40. package/build/esm/package.json +1 -1
  41. package/build/esm/server/createServerInstrumentation.js +25 -18
  42. package/build/esm/server/createServerInstrumentation.js.map +1 -1
  43. package/build/esm/server/getMetaTagTransformer.js +3 -2
  44. package/build/esm/server/getMetaTagTransformer.js.map +1 -1
  45. package/build/esm/server/integration/lowQualityTransactionsFilterIntegration.js +3 -2
  46. package/build/esm/server/integration/lowQualityTransactionsFilterIntegration.js.map +1 -1
  47. package/build/esm/server/wrapSentryHandleRequest.js +4 -4
  48. package/build/esm/server/wrapSentryHandleRequest.js.map +1 -1
  49. package/build/esm/vite/buildEnd/handleOnBuildEnd.js +17 -29
  50. package/build/esm/vite/buildEnd/handleOnBuildEnd.js.map +1 -1
  51. package/build/esm/vite/index.js +4 -0
  52. package/build/esm/vite/index.js.map +1 -0
  53. package/build/esm/vite/makeCustomSentryVitePlugins.js +21 -32
  54. package/build/esm/vite/makeCustomSentryVitePlugins.js.map +1 -1
  55. package/build/types/client/createClientInstrumentation.d.ts +1 -1
  56. package/build/types/client/createClientInstrumentation.d.ts.map +1 -1
  57. package/build/types/client/hydratedRouter.d.ts.map +1 -1
  58. package/build/types/client/tracingIntegration.d.ts +1 -1
  59. package/build/types/client/tracingIntegration.d.ts.map +1 -1
  60. package/build/types/client/utils.d.ts +7 -1
  61. package/build/types/client/utils.d.ts.map +1 -1
  62. package/build/types/cloudflare/index.d.ts.map +1 -1
  63. package/build/types/common/utils.d.ts +3 -2
  64. package/build/types/common/utils.d.ts.map +1 -1
  65. package/build/types/index.server.d.ts +0 -1
  66. package/build/types/index.server.d.ts.map +1 -1
  67. package/build/types/index.types.d.ts +3 -1
  68. package/build/types/index.types.d.ts.map +1 -1
  69. package/build/types/server/createServerInstrumentation.d.ts +1 -1
  70. package/build/types/server/createServerInstrumentation.d.ts.map +1 -1
  71. package/build/types/server/getMetaTagTransformer.d.ts.map +1 -1
  72. package/build/types/server/integration/lowQualityTransactionsFilterIntegration.d.ts.map +1 -1
  73. package/build/types/server/wrapSentryHandleRequest.d.ts.map +1 -1
  74. package/build/types/vite/buildEnd/handleOnBuildEnd.d.ts.map +1 -1
  75. package/build/types/vite/makeCustomSentryVitePlugins.d.ts.map +1 -1
  76. package/build/types/vite/types.d.ts +15 -13
  77. package/build/types/vite/types.d.ts.map +1 -1
  78. package/package.json +16 -10
  79. package/build/types/common/types.d.ts +0 -86
  80. package/build/types/common/types.d.ts.map +0 -1
@@ -1,66 +1,55 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
2
 
3
3
  const vite = require('@sentry/bundler-plugins/vite');
4
+ const core = require('@sentry/core');
4
5
 
5
6
  async function makeCustomSentryVitePlugins(options) {
7
+ core.warnOnRemovedBuildOptions(options, ["unstable_sentryVitePluginOptions"]);
6
8
  const {
7
9
  debug,
8
- unstable_sentryVitePluginOptions,
9
10
  bundleSizeOptimizations,
10
11
  applicationKey,
11
12
  authToken,
13
+ errorHandler,
14
+ headers,
15
+ moduleMetadata,
12
16
  org,
13
17
  project,
18
+ sentryUrl,
19
+ silent,
14
20
  telemetry,
15
21
  reactComponentAnnotation,
16
22
  release
17
23
  } = options;
18
- const unstableSourcemapsDisable = unstable_sentryVitePluginOptions?.sourcemaps?.disable;
19
- if (unstableSourcemapsDisable !== void 0 && unstableSourcemapsDisable !== true) {
20
- console.warn(
21
- `[Sentry] \`unstable_sentryVitePluginOptions.sourcemaps.disable: ${JSON.stringify(
22
- unstableSourcemapsDisable
23
- )}\` does not apply to the Vite plugin. Debug ID injection and source map upload are handled by the \`sentryOnBuildEnd\` hook for React Router, so letting the Vite plugin do it as well would inject a second debug ID per chunk. The option still applies to \`sentryOnBuildEnd\`.`
24
- );
25
- }
26
24
  const sentryVitePlugins = vite.sentryVitePlugin({
27
25
  applicationKey,
28
26
  authToken: authToken ?? process.env.SENTRY_AUTH_TOKEN,
29
27
  bundleSizeOptimizations,
30
28
  debug: debug ?? false,
29
+ errorHandler,
30
+ headers,
31
+ moduleMetadata,
31
32
  org: org ?? process.env.SENTRY_ORG,
32
33
  project: project ?? process.env.SENTRY_PROJECT,
34
+ reactComponentAnnotation,
35
+ release,
36
+ silent,
33
37
  telemetry: telemetry ?? true,
34
- // Spread here so it can override the plain options above, but not the objects
35
- // merged below - object spread replaces whole keys rather than deep-merging.
36
- ...unstable_sentryVitePluginOptions,
38
+ // Release creation runs in the plugin's `writeBundle` even with `sourcemaps.disable` set below,
39
+ // so the plugin needs its own URL rather than relying on the `sentryOnBuildEnd` CLI instance.
40
+ url: sentryUrl,
37
41
  _metaOptions: {
38
- ...unstable_sentryVitePluginOptions?._metaOptions,
39
42
  telemetry: {
40
- ...unstable_sentryVitePluginOptions?._metaOptions?.telemetry,
41
43
  metaFramework: "react-router"
42
44
  }
43
45
  },
44
- reactComponentAnnotation: {
45
- // Only assign when set, as an explicit `undefined` would erase the unstable value
46
- ...reactComponentAnnotation?.enabled !== void 0 && { enabled: reactComponentAnnotation.enabled },
47
- ...reactComponentAnnotation?.ignoredComponents !== void 0 && {
48
- ignoredComponents: reactComponentAnnotation.ignoredComponents
49
- },
50
- ...unstable_sentryVitePluginOptions?.reactComponentAnnotation
51
- },
52
- release: {
53
- ...unstable_sentryVitePluginOptions?.release,
54
- ...release
55
- },
56
46
  sourcemaps: {
57
- ...unstable_sentryVitePluginOptions?.sourcemaps,
58
- // Injection and upload are handled in the buildEnd hook, so the Vite plugin must
59
- // never do it too. This is deliberately not overridable - see the warning above.
47
+ // Debug ID injection and upload are handled by the `sentryOnBuildEnd` hook, so the Vite plugin
48
+ // must never do it as well - that would inject a second debug ID per chunk and break source
49
+ // map resolution.
60
50
  disable: true,
61
- // The plugin deletes these in a `finally` block that runs regardless of `disable`,
62
- // which would remove the maps before `sentryOnBuildEnd` gets to upload them.
63
- // Deletion is handled there instead, from the same option.
51
+ // The plugin deletes these in a `finally` block that runs regardless of `disable`, which would
52
+ // remove the maps before `sentryOnBuildEnd` gets to upload them. Deletion happens there instead.
64
53
  filesToDeleteAfterUpload: void 0
65
54
  }
66
55
  });
@@ -1 +1 @@
1
- {"version":3,"file":"makeCustomSentryVitePlugins.js","sources":["../../../src/vite/makeCustomSentryVitePlugins.ts"],"sourcesContent":["import { sentryVitePlugin } from '@sentry/bundler-plugins/vite';\nimport { type Plugin } from 'vite';\nimport type { SentryReactRouterBuildOptions } from './types';\n\n/**\n * Create a custom subset of sentry's vite plugins\n */\nexport async function makeCustomSentryVitePlugins(options: SentryReactRouterBuildOptions): Promise<Plugin[]> {\n const {\n debug,\n unstable_sentryVitePluginOptions,\n bundleSizeOptimizations,\n applicationKey,\n authToken,\n org,\n project,\n telemetry,\n reactComponentAnnotation,\n release,\n } = options;\n\n const unstableSourcemapsDisable = unstable_sentryVitePluginOptions?.sourcemaps?.disable;\n\n // Anything other than `true` would have the Vite plugin inject debug IDs on top of the\n // ones `sentryOnBuildEnd` injects, which breaks source map resolution. The value still\n // applies to the buildEnd hook - only the Vite plugin ignores it.\n if (unstableSourcemapsDisable !== undefined && unstableSourcemapsDisable !== true) {\n // eslint-disable-next-line no-console\n console.warn(\n `[Sentry] \\`unstable_sentryVitePluginOptions.sourcemaps.disable: ${JSON.stringify(\n unstableSourcemapsDisable,\n )}\\` does not apply to the Vite plugin. Debug ID injection and source map upload are handled by the \\`sentryOnBuildEnd\\` hook for React Router, so letting the Vite plugin do it as well would inject a second debug ID per chunk. The option still applies to \\`sentryOnBuildEnd\\`.`,\n );\n }\n\n const sentryVitePlugins = sentryVitePlugin({\n applicationKey,\n authToken: authToken ?? process.env.SENTRY_AUTH_TOKEN,\n bundleSizeOptimizations,\n debug: debug ?? false,\n org: org ?? process.env.SENTRY_ORG,\n project: project ?? process.env.SENTRY_PROJECT,\n telemetry: telemetry ?? true,\n // Spread here so it can override the plain options above, but not the objects\n // merged below - object spread replaces whole keys rather than deep-merging.\n ...unstable_sentryVitePluginOptions,\n _metaOptions: {\n ...unstable_sentryVitePluginOptions?._metaOptions,\n telemetry: {\n ...unstable_sentryVitePluginOptions?._metaOptions?.telemetry,\n metaFramework: 'react-router',\n },\n },\n reactComponentAnnotation: {\n // Only assign when set, as an explicit `undefined` would erase the unstable value\n ...(reactComponentAnnotation?.enabled !== undefined && { enabled: reactComponentAnnotation.enabled }),\n ...(reactComponentAnnotation?.ignoredComponents !== undefined && {\n ignoredComponents: reactComponentAnnotation.ignoredComponents,\n }),\n ...unstable_sentryVitePluginOptions?.reactComponentAnnotation,\n },\n release: {\n ...unstable_sentryVitePluginOptions?.release,\n ...release,\n },\n sourcemaps: {\n ...unstable_sentryVitePluginOptions?.sourcemaps,\n // Injection and upload are handled in the buildEnd hook, so the Vite plugin must\n // never do it too. This is deliberately not overridable - see the warning above.\n disable: true,\n // The plugin deletes these in a `finally` block that runs regardless of `disable`,\n // which would remove the maps before `sentryOnBuildEnd` gets to upload them.\n // Deletion is handled there instead, from the same option.\n filesToDeleteAfterUpload: undefined,\n },\n }) as Plugin[];\n\n return sentryVitePlugins;\n}\n"],"names":["sentryVitePlugin"],"mappings":";;;;AAOA,eAAsB,4BAA4B,OAAA,EAA2D;AAC3G,EAAA,MAAM;AAAA,IACJ,KAAA;AAAA,IACA,gCAAA;AAAA,IACA,uBAAA;AAAA,IACA,cAAA;AAAA,IACA,SAAA;AAAA,IACA,GAAA;AAAA,IACA,OAAA;AAAA,IACA,SAAA;AAAA,IACA,wBAAA;AAAA,IACA;AAAA,GACF,GAAI,OAAA;AAEJ,EAAA,MAAM,yBAAA,GAA4B,kCAAkC,UAAA,EAAY,OAAA;AAKhF,EAAA,IAAI,yBAAA,KAA8B,MAAA,IAAa,yBAAA,KAA8B,IAAA,EAAM;AAEjF,IAAA,OAAA,CAAQ,IAAA;AAAA,MACN,mEAAmE,IAAA,CAAK,SAAA;AAAA,QACtE;AAAA,OACD,CAAA,kRAAA;AAAA,KACH;AAAA,EACF;AAEA,EAAA,MAAM,oBAAoBA,qBAAA,CAAiB;AAAA,IACzC,cAAA;AAAA,IACA,SAAA,EAAW,SAAA,IAAa,OAAA,CAAQ,GAAA,CAAI,iBAAA;AAAA,IACpC,uBAAA;AAAA,IACA,OAAO,KAAA,IAAS,KAAA;AAAA,IAChB,GAAA,EAAK,GAAA,IAAO,OAAA,CAAQ,GAAA,CAAI,UAAA;AAAA,IACxB,OAAA,EAAS,OAAA,IAAW,OAAA,CAAQ,GAAA,CAAI,cAAA;AAAA,IAChC,WAAW,SAAA,IAAa,IAAA;AAAA;AAAA;AAAA,IAGxB,GAAG,gCAAA;AAAA,IACH,YAAA,EAAc;AAAA,MACZ,GAAG,gCAAA,EAAkC,YAAA;AAAA,MACrC,SAAA,EAAW;AAAA,QACT,GAAG,kCAAkC,YAAA,EAAc,SAAA;AAAA,QACnD,aAAA,EAAe;AAAA;AACjB,KACF;AAAA,IACA,wBAAA,EAA0B;AAAA;AAAA,MAExB,GAAI,wBAAA,EAA0B,OAAA,KAAY,UAAa,EAAE,OAAA,EAAS,yBAAyB,OAAA,EAAQ;AAAA,MACnG,GAAI,wBAAA,EAA0B,iBAAA,KAAsB,MAAA,IAAa;AAAA,QAC/D,mBAAmB,wBAAA,CAAyB;AAAA,OAC9C;AAAA,MACA,GAAG,gCAAA,EAAkC;AAAA,KACvC;AAAA,IACA,OAAA,EAAS;AAAA,MACP,GAAG,gCAAA,EAAkC,OAAA;AAAA,MACrC,GAAG;AAAA,KACL;AAAA,IACA,UAAA,EAAY;AAAA,MACV,GAAG,gCAAA,EAAkC,UAAA;AAAA;AAAA;AAAA,MAGrC,OAAA,EAAS,IAAA;AAAA;AAAA;AAAA;AAAA,MAIT,wBAAA,EAA0B;AAAA;AAC5B,GACD,CAAA;AAED,EAAA,OAAO,iBAAA;AACT;;;;"}
1
+ {"version":3,"file":"makeCustomSentryVitePlugins.js","sources":["../../../src/vite/makeCustomSentryVitePlugins.ts"],"sourcesContent":["import { sentryVitePlugin } from '@sentry/bundler-plugins/vite';\nimport { warnOnRemovedBuildOptions } from '@sentry/core';\nimport { type Plugin } from 'vite';\nimport type { SentryReactRouterBuildOptions } from './types';\n\n/**\n * Create a custom subset of sentry's vite plugins\n */\nexport async function makeCustomSentryVitePlugins(options: SentryReactRouterBuildOptions): Promise<Plugin[]> {\n warnOnRemovedBuildOptions(options, ['unstable_sentryVitePluginOptions']);\n\n const {\n debug,\n bundleSizeOptimizations,\n applicationKey,\n authToken,\n errorHandler,\n headers,\n moduleMetadata,\n org,\n project,\n sentryUrl,\n silent,\n telemetry,\n reactComponentAnnotation,\n release,\n } = options;\n\n const sentryVitePlugins = sentryVitePlugin({\n applicationKey,\n authToken: authToken ?? process.env.SENTRY_AUTH_TOKEN,\n bundleSizeOptimizations,\n debug: debug ?? false,\n errorHandler,\n headers,\n moduleMetadata,\n org: org ?? process.env.SENTRY_ORG,\n project: project ?? process.env.SENTRY_PROJECT,\n reactComponentAnnotation,\n release,\n silent,\n telemetry: telemetry ?? true,\n // Release creation runs in the plugin's `writeBundle` even with `sourcemaps.disable` set below,\n // so the plugin needs its own URL rather than relying on the `sentryOnBuildEnd` CLI instance.\n url: sentryUrl,\n _metaOptions: {\n telemetry: {\n metaFramework: 'react-router',\n },\n },\n sourcemaps: {\n // Debug ID injection and upload are handled by the `sentryOnBuildEnd` hook, so the Vite plugin\n // must never do it as well - that would inject a second debug ID per chunk and break source\n // map resolution.\n disable: true,\n // The plugin deletes these in a `finally` block that runs regardless of `disable`, which would\n // remove the maps before `sentryOnBuildEnd` gets to upload them. Deletion happens there instead.\n filesToDeleteAfterUpload: undefined,\n },\n }) as Plugin[];\n\n return sentryVitePlugins;\n}\n"],"names":["warnOnRemovedBuildOptions","sentryVitePlugin"],"mappings":";;;;;AAQA,eAAsB,4BAA4B,OAAA,EAA2D;AAC3G,EAAAA,8BAAA,CAA0B,OAAA,EAAS,CAAC,kCAAkC,CAAC,CAAA;AAEvE,EAAA,MAAM;AAAA,IACJ,KAAA;AAAA,IACA,uBAAA;AAAA,IACA,cAAA;AAAA,IACA,SAAA;AAAA,IACA,YAAA;AAAA,IACA,OAAA;AAAA,IACA,cAAA;AAAA,IACA,GAAA;AAAA,IACA,OAAA;AAAA,IACA,SAAA;AAAA,IACA,MAAA;AAAA,IACA,SAAA;AAAA,IACA,wBAAA;AAAA,IACA;AAAA,GACF,GAAI,OAAA;AAEJ,EAAA,MAAM,oBAAoBC,qBAAA,CAAiB;AAAA,IACzC,cAAA;AAAA,IACA,SAAA,EAAW,SAAA,IAAa,OAAA,CAAQ,GAAA,CAAI,iBAAA;AAAA,IACpC,uBAAA;AAAA,IACA,OAAO,KAAA,IAAS,KAAA;AAAA,IAChB,YAAA;AAAA,IACA,OAAA;AAAA,IACA,cAAA;AAAA,IACA,GAAA,EAAK,GAAA,IAAO,OAAA,CAAQ,GAAA,CAAI,UAAA;AAAA,IACxB,OAAA,EAAS,OAAA,IAAW,OAAA,CAAQ,GAAA,CAAI,cAAA;AAAA,IAChC,wBAAA;AAAA,IACA,OAAA;AAAA,IACA,MAAA;AAAA,IACA,WAAW,SAAA,IAAa,IAAA;AAAA;AAAA;AAAA,IAGxB,GAAA,EAAK,SAAA;AAAA,IACL,YAAA,EAAc;AAAA,MACZ,SAAA,EAAW;AAAA,QACT,aAAA,EAAe;AAAA;AACjB,KACF;AAAA,IACA,UAAA,EAAY;AAAA;AAAA;AAAA;AAAA,MAIV,OAAA,EAAS,IAAA;AAAA;AAAA;AAAA,MAGT,wBAAA,EAA0B;AAAA;AAC5B,GACD,CAAA;AAED,EAAA,OAAO,iBAAA;AACT;;;;"}
@@ -1,10 +1,11 @@
1
1
  import { startBrowserTracingNavigationSpan, getAbsoluteUrl } from '@sentry/browser';
2
- import { debug, startSpan, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, SPAN_STATUS_ERROR, GLOBAL_OBJ, getClient, SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, filterCollectedUrl, getActiveSpan, getRootSpan, spanToJSON, updateSpanName } from '@sentry/core';
2
+ import { debug, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, SPAN_STATUS_ERROR, GLOBAL_OBJ, getClient, NAVIGATION_SPAN_NAME_FALLBACK, SEMANTIC_ATTRIBUTE_SENTRY_OP, hasSpanStreamingEnabled, filterCollectedUrl, getActiveSpan, getRootSpan, spanToJSON, updateSpanName } from '@sentry/core';
3
+ import { startSpan } from '@sentry/core/browser';
3
4
  import { DEBUG_BUILD } from '../common/debug-build.js';
4
5
  import { captureInstrumentationError, getPathFromRequest, normalizeRoutePath, getPattern } from '../common/utils.js';
5
6
  import { updateNavigationSpanUrlFromLocation, finalizeNavigationSpanFromHydratedRouter, resolveNavigateArg, resolveNavigateAbsoluteUrl } from './utils.js';
6
- import { CODE_FUNCTION_NAME, SENTRY_OP, URL_FULL, URL_TEMPLATE } from '@sentry/conventions/attributes';
7
- import { GENERAL_FUNCTION_SPAN_OP, WEB_SERVER_MIDDLEWARE_SPAN_OP } from '@sentry/conventions/op';
7
+ import { CODE_FUNCTION_NAME, SENTRY_OP, SENTRY_SEGMENT_NAME_SOURCE, URL_FULL, URL_TEMPLATE } from '@sentry/conventions/attributes';
8
+ import { FUNCTION, MIDDLEWARE } from '@sentry/conventions/op';
8
9
 
9
10
  const WINDOW = GLOBAL_OBJ;
10
11
  let currentNumericNavigationSpan;
@@ -39,9 +40,11 @@ function createSentryClientInstrumentation(options = {}) {
39
40
  startBrowserTracingNavigationSpan(
40
41
  client,
41
42
  {
42
- name: pathname,
43
+ // With span streaming, span names have to be low cardinality, so we can't fall back to
44
+ // the URL. The route hooks parameterize the span once they resolve.
45
+ name: hasSpanStreamingEnabled(client) ? NAVIGATION_SPAN_NAME_FALLBACK : pathname,
43
46
  attributes: {
44
- [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: "url",
47
+ [SENTRY_SEGMENT_NAME_SOURCE]: "url",
45
48
  [SEMANTIC_ATTRIBUTE_SENTRY_OP]: "navigation",
46
49
  [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: "auto.navigation.react_router.instrumentation_api",
47
50
  "navigation.type": "browser.popstate"
@@ -73,9 +76,11 @@ function createSentryClientInstrumentation(options = {}) {
73
76
  navigationSpan2 = startBrowserTracingNavigationSpan(
74
77
  client2,
75
78
  {
76
- name: currentPathname,
79
+ // With span streaming, span names have to be low cardinality, so we can't fall back
80
+ // to the URL. The route is resolved once the navigation settles.
81
+ name: hasSpanStreamingEnabled(client2) ? NAVIGATION_SPAN_NAME_FALLBACK : currentPathname,
77
82
  attributes: {
78
- [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: "url",
83
+ [SENTRY_SEGMENT_NAME_SOURCE]: "url",
79
84
  [SEMANTIC_ATTRIBUTE_SENTRY_OP]: "navigation",
80
85
  [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: "auto.navigation.react_router.instrumentation_api",
81
86
  "navigation.type": navigationType
@@ -110,9 +115,11 @@ function createSentryClientInstrumentation(options = {}) {
110
115
  navigationSpan = startBrowserTracingNavigationSpan(
111
116
  client,
112
117
  {
113
- name: toPath,
118
+ // With span streaming, span names have to be low cardinality, so we can't fall back to
119
+ // the URL. The route hooks parameterize the span once they resolve.
120
+ name: hasSpanStreamingEnabled(client) ? NAVIGATION_SPAN_NAME_FALLBACK : toPath,
114
121
  attributes: {
115
- [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: "url",
122
+ [SENTRY_SEGMENT_NAME_SOURCE]: "url",
116
123
  [SEMANTIC_ATTRIBUTE_SENTRY_OP]: "navigation",
117
124
  [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: "auto.navigation.react_router.instrumentation_api",
118
125
  "navigation.type": "router.navigate"
@@ -137,7 +144,7 @@ function createSentryClientInstrumentation(options = {}) {
137
144
  {
138
145
  name: `Fetcher ${info.fetcherKey}`,
139
146
  attributes: {
140
- [SENTRY_OP]: GENERAL_FUNCTION_SPAN_OP,
147
+ [SENTRY_OP]: FUNCTION,
141
148
  [CODE_FUNCTION_NAME]: "fetcher",
142
149
  [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: "auto.function.react_router.instrumentation_api"
143
150
  }
@@ -167,7 +174,7 @@ function createSentryClientInstrumentation(options = {}) {
167
174
  {
168
175
  name: routePattern,
169
176
  attributes: {
170
- [SENTRY_OP]: GENERAL_FUNCTION_SPAN_OP,
177
+ [SENTRY_OP]: FUNCTION,
171
178
  [CODE_FUNCTION_NAME]: "clientLoader",
172
179
  [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: "auto.function.react_router.instrumentation_api"
173
180
  }
@@ -192,7 +199,7 @@ function createSentryClientInstrumentation(options = {}) {
192
199
  {
193
200
  name: routePattern,
194
201
  attributes: {
195
- [SENTRY_OP]: GENERAL_FUNCTION_SPAN_OP,
202
+ [SENTRY_OP]: FUNCTION,
196
203
  [CODE_FUNCTION_NAME]: "clientAction",
197
204
  [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: "auto.function.react_router.instrumentation_api"
198
205
  }
@@ -222,7 +229,7 @@ function createSentryClientInstrumentation(options = {}) {
222
229
  {
223
230
  name: `middleware ${routeId}`,
224
231
  attributes: {
225
- [SENTRY_OP]: WEB_SERVER_MIDDLEWARE_SPAN_OP,
232
+ [SENTRY_OP]: MIDDLEWARE,
226
233
  [CODE_FUNCTION_NAME]: "clientMiddleware",
227
234
  [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: "auto.function.react_router.instrumentation_api",
228
235
  "react_router.route.id": routeId,
@@ -246,7 +253,7 @@ function createSentryClientInstrumentation(options = {}) {
246
253
  {
247
254
  name: "Lazy Route Load",
248
255
  attributes: {
249
- [SENTRY_OP]: GENERAL_FUNCTION_SPAN_OP,
256
+ [SENTRY_OP]: FUNCTION,
250
257
  [CODE_FUNCTION_NAME]: "lazy",
251
258
  [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: "auto.function.react_router.instrumentation_api"
252
259
  }
@@ -279,7 +286,7 @@ function updateRootSpanRoute(routeName, hasPattern) {
279
286
  return;
280
287
  }
281
288
  updateSpanName(rootSpan, routeName);
282
- rootSpan.setAttributes({ [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: "route", [URL_TEMPLATE]: routeName });
289
+ rootSpan.setAttributes({ [SENTRY_SEGMENT_NAME_SOURCE]: "route", [URL_TEMPLATE]: routeName });
283
290
  }
284
291
  function isClientInstrumentationApiUsed() {
285
292
  return !!GLOBAL_WITH_FLAGS[SENTRY_CLIENT_INSTRUMENTATION_FLAG];
@@ -1 +1 @@
1
- {"version":3,"file":"createClientInstrumentation.js","sources":["../../../src/client/createClientInstrumentation.ts"],"sourcesContent":["// oxlint-disable max-lines\nimport { getAbsoluteUrl, startBrowserTracingNavigationSpan } from '@sentry/browser';\nimport type { Span } from '@sentry/core';\nimport {\n debug,\n getActiveSpan,\n getClient,\n getRootSpan,\n GLOBAL_OBJ,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n SEMANTIC_ATTRIBUTE_SENTRY_SOURCE,\n spanToJSON,\n SPAN_STATUS_ERROR,\n startSpan,\n updateSpanName,\n filterCollectedUrl,\n} from '@sentry/core';\nimport { DEBUG_BUILD } from '../common/debug-build';\nimport type { ClientInstrumentation, InstrumentableRoute, InstrumentableRouter } from '../common/types';\nimport { captureInstrumentationError, getPathFromRequest, getPattern, normalizeRoutePath } from '../common/utils';\nimport {\n resolveNavigateAbsoluteUrl,\n resolveNavigateArg,\n finalizeNavigationSpanFromHydratedRouter,\n updateNavigationSpanUrlFromLocation,\n} from './utils';\nimport { CODE_FUNCTION_NAME, SENTRY_OP, URL_FULL, URL_TEMPLATE } from '@sentry/conventions/attributes';\nimport { GENERAL_FUNCTION_SPAN_OP, WEB_SERVER_MIDDLEWARE_SPAN_OP } from '@sentry/conventions/op';\n\nconst WINDOW = GLOBAL_OBJ as typeof GLOBAL_OBJ & Window;\n\n// Tracks active numeric navigation span to prevent duplicate spans when popstate fires\nlet currentNumericNavigationSpan: Span | undefined;\n\n// Per-request middleware counters, keyed by Request\nconst middlewareCountersMap = new WeakMap<object, Record<string, number>>();\n\nconst SENTRY_CLIENT_INSTRUMENTATION_FLAG = '__sentryReactRouterClientInstrumentationUsed';\n// Intentionally never reset - once set, instrumentation API handles all navigations for the session.\nconst SENTRY_NAVIGATE_HOOK_INVOKED_FLAG = '__sentryReactRouterNavigateHookInvoked';\nconst SENTRY_POPSTATE_LISTENER_ADDED_FLAG = '__sentryReactRouterPopstateListenerAdded';\n\ntype GlobalObjWithFlags = typeof GLOBAL_OBJ & {\n [SENTRY_CLIENT_INSTRUMENTATION_FLAG]?: boolean;\n [SENTRY_NAVIGATE_HOOK_INVOKED_FLAG]?: boolean;\n [SENTRY_POPSTATE_LISTENER_ADDED_FLAG]?: boolean;\n};\n\nconst GLOBAL_WITH_FLAGS = GLOBAL_OBJ as GlobalObjWithFlags;\n\n/**\n * Options for creating Sentry client instrumentation.\n */\nexport interface CreateSentryClientInstrumentationOptions {\n /**\n * Whether to capture errors from loaders/actions automatically.\n * Set to `false` to avoid duplicates if using custom error handlers.\n * @default true\n */\n captureErrors?: boolean;\n}\n\n/**\n * Creates a Sentry client instrumentation for React Router's instrumentation API.\n */\nexport function createSentryClientInstrumentation(\n options: CreateSentryClientInstrumentationOptions = {},\n): ClientInstrumentation {\n const { captureErrors = true } = options;\n\n DEBUG_BUILD && debug.log('React Router client instrumentation API created.');\n\n return {\n router(router: InstrumentableRouter) {\n // Set the flag when React Router actually invokes our instrumentation.\n // This ensures the flag is only set in Library Mode (where hooks run),\n // not in Framework Mode (where hooks are never called).\n // See: https://github.com/remix-run/react-router/discussions/13749\n GLOBAL_WITH_FLAGS[SENTRY_CLIENT_INSTRUMENTATION_FLAG] = true;\n DEBUG_BUILD && debug.log('React Router client instrumentation API router hook registered.');\n\n // Add popstate listener for browser back/forward navigation (persists for session, one listener only)\n if (!GLOBAL_WITH_FLAGS[SENTRY_POPSTATE_LISTENER_ADDED_FLAG] && WINDOW.addEventListener) {\n GLOBAL_WITH_FLAGS[SENTRY_POPSTATE_LISTENER_ADDED_FLAG] = true;\n\n WINDOW.addEventListener('popstate', () => {\n const client = getClient();\n if (!client) {\n currentNumericNavigationSpan = undefined;\n return;\n }\n\n const pathname = WINDOW.location?.pathname || '/';\n\n // If there's an active numeric navigation span, update it instead of creating a duplicate\n if (currentNumericNavigationSpan) {\n if (currentNumericNavigationSpan.isRecording()) {\n updateNavigationSpanUrlFromLocation(currentNumericNavigationSpan);\n }\n currentNumericNavigationSpan = undefined;\n return;\n }\n\n // Only create a new span for actual browser back/forward button clicks\n startBrowserTracingNavigationSpan(\n client,\n {\n name: pathname,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'url',\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'navigation',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.navigation.react_router.instrumentation_api',\n 'navigation.type': 'browser.popstate',\n },\n },\n { url: getAbsoluteUrl(pathname) },\n );\n });\n\n DEBUG_BUILD && debug.log('React Router popstate listener registered for browser back/forward navigation.');\n }\n\n router.instrument({\n async navigate(callNavigate, info) {\n // navigate(0) triggers a page reload - skip span creation, but still capture errors\n // (navigation can be rejected before reload, e.g., by a navigation guard)\n if (info.to === 0) {\n const result = await callNavigate();\n if (result.status === 'error' && result.error instanceof Error) {\n captureInstrumentationError(result, captureErrors, 'react_router.navigate', {\n [URL_FULL]: filterCollectedUrl(info.currentUrl),\n });\n }\n return;\n }\n\n GLOBAL_WITH_FLAGS[SENTRY_NAVIGATE_HOOK_INVOKED_FLAG] = true;\n\n // Handle numeric navigations (navigate(-1), navigate(1), etc.)\n if (typeof info.to === 'number') {\n const client = getClient();\n let navigationSpan;\n\n if (client) {\n const navigationType = info.to < 0 ? 'router.back' : 'router.forward';\n const currentPathname = WINDOW.location?.pathname || info.currentUrl;\n\n navigationSpan = startBrowserTracingNavigationSpan(\n client,\n {\n name: currentPathname,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'url',\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'navigation',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.navigation.react_router.instrumentation_api',\n 'navigation.type': navigationType,\n },\n },\n { url: getAbsoluteUrl(currentPathname) },\n );\n\n // Store ref so popstate listener can update it instead of creating a duplicate\n currentNumericNavigationSpan = navigationSpan;\n }\n\n try {\n const result = await callNavigate();\n\n if (navigationSpan && WINDOW.location) {\n finalizeNavigationSpanFromHydratedRouter(navigationSpan);\n }\n\n if (result.status === 'error' && result.error instanceof Error) {\n if (navigationSpan) {\n navigationSpan.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n }\n captureInstrumentationError(result, captureErrors, 'react_router.navigate', {\n [URL_FULL]: WINDOW.location?.pathname || filterCollectedUrl(info.currentUrl),\n });\n }\n } finally {\n currentNumericNavigationSpan = undefined;\n }\n return;\n }\n\n // Handle string/object navigations (e.g., navigate('/about') or navigate({ pathname: '/about' }))\n const client = getClient();\n const toPath = resolveNavigateArg(info.to);\n let navigationSpan;\n\n if (client) {\n navigationSpan = startBrowserTracingNavigationSpan(\n client,\n {\n name: toPath,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'url',\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'navigation',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.navigation.react_router.instrumentation_api',\n 'navigation.type': 'router.navigate',\n },\n },\n { url: resolveNavigateAbsoluteUrl(info.to, info.currentUrl) },\n );\n }\n\n const result = await callNavigate();\n if (result.status === 'error' && result.error instanceof Error) {\n if (navigationSpan) {\n navigationSpan.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n }\n captureInstrumentationError(result, captureErrors, 'react_router.navigate', {\n [URL_FULL]: filterCollectedUrl(toPath),\n });\n }\n return;\n },\n\n async fetch(callFetch, info) {\n await startSpan(\n {\n name: `Fetcher ${info.fetcherKey}`,\n attributes: {\n [SENTRY_OP]: GENERAL_FUNCTION_SPAN_OP,\n [CODE_FUNCTION_NAME]: 'fetcher',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.react_router.instrumentation_api',\n },\n },\n async span => {\n const result = await callFetch();\n if (result.status === 'error' && result.error instanceof Error) {\n span.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n captureInstrumentationError(result, captureErrors, 'react_router.fetcher', {\n [URL_FULL]: filterCollectedUrl(info.href),\n });\n }\n },\n );\n },\n });\n },\n\n route(route: InstrumentableRoute) {\n const routeId = route.id;\n\n route.instrument({\n async loader(callLoader, info) {\n const urlPath = getPathFromRequest(info.request);\n const pattern = normalizeRoutePath(getPattern(info));\n const routePattern = pattern || urlPath;\n // Parameterize the active navigation root span. (Route hooks don't fire on initial\n // pageload, so this only affects navigations.)\n updateRootSpanRoute(routePattern, !!pattern);\n\n await startSpan(\n {\n name: routePattern,\n attributes: {\n [SENTRY_OP]: GENERAL_FUNCTION_SPAN_OP,\n [CODE_FUNCTION_NAME]: 'clientLoader',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.react_router.instrumentation_api',\n },\n },\n async span => {\n const result = await callLoader();\n if (result.status === 'error' && result.error instanceof Error) {\n span.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n captureInstrumentationError(result, captureErrors, 'react_router.client_loader', {\n [URL_FULL]: urlPath,\n });\n }\n },\n );\n },\n\n async action(callAction, info) {\n const urlPath = getPathFromRequest(info.request);\n const pattern = normalizeRoutePath(getPattern(info));\n const routePattern = pattern || urlPath;\n updateRootSpanRoute(routePattern, !!pattern);\n\n await startSpan(\n {\n name: routePattern,\n attributes: {\n [SENTRY_OP]: GENERAL_FUNCTION_SPAN_OP,\n [CODE_FUNCTION_NAME]: 'clientAction',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.react_router.instrumentation_api',\n },\n },\n async span => {\n const result = await callAction();\n if (result.status === 'error' && result.error instanceof Error) {\n span.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n captureInstrumentationError(result, captureErrors, 'react_router.client_action', {\n [URL_FULL]: urlPath,\n });\n }\n },\n );\n },\n\n async middleware(callMiddleware, info) {\n const urlPath = getPathFromRequest(info.request);\n const routePattern = normalizeRoutePath(getPattern(info)) || urlPath;\n\n let counters = middlewareCountersMap.get(info.request);\n if (!counters) {\n counters = {};\n middlewareCountersMap.set(info.request, counters);\n }\n\n const middlewareIndex = counters[routeId] ?? 0;\n counters[routeId] = middlewareIndex + 1;\n\n await startSpan(\n {\n name: `middleware ${routeId}`,\n attributes: {\n [SENTRY_OP]: WEB_SERVER_MIDDLEWARE_SPAN_OP,\n [CODE_FUNCTION_NAME]: 'clientMiddleware',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.react_router.instrumentation_api',\n 'react_router.route.id': routeId,\n 'http.route': routePattern,\n 'react_router.middleware.index': middlewareIndex,\n },\n },\n async span => {\n const result = await callMiddleware();\n if (result.status === 'error' && result.error instanceof Error) {\n span.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n captureInstrumentationError(result, captureErrors, 'react_router.client_middleware', {\n [URL_FULL]: urlPath,\n });\n }\n },\n );\n },\n\n async lazy(callLazy) {\n await startSpan(\n {\n name: 'Lazy Route Load',\n attributes: {\n [SENTRY_OP]: GENERAL_FUNCTION_SPAN_OP,\n [CODE_FUNCTION_NAME]: 'lazy',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.react_router.instrumentation_api',\n },\n },\n async span => {\n const result = await callLazy();\n if (result.status === 'error' && result.error instanceof Error) {\n span.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n captureInstrumentationError(result, captureErrors, 'react_router.client_lazy', {});\n }\n },\n );\n },\n });\n },\n };\n}\n\n/**\n * Updates the active navigation/pageload root span name with the parameterized route, so the\n * transaction reflects the parameterized route pattern (e.g. `/users/:id`).\n */\nfunction updateRootSpanRoute(routeName: string, hasPattern: boolean): void {\n if (!hasPattern) {\n return;\n }\n\n const activeSpan = getActiveSpan();\n const rootSpan = activeSpan && getRootSpan(activeSpan);\n if (!rootSpan) {\n return;\n }\n\n const { attributes } = spanToJSON(rootSpan);\n const op = attributes[SENTRY_OP];\n if (op !== 'navigation' && op !== 'pageload') {\n return;\n }\n\n updateSpanName(rootSpan, routeName);\n rootSpan.setAttributes({ [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'route', [URL_TEMPLATE]: routeName });\n}\n\n/**\n * Check if React Router's instrumentation API is being used on the client.\n */\nexport function isClientInstrumentationApiUsed(): boolean {\n return !!GLOBAL_WITH_FLAGS[SENTRY_CLIENT_INSTRUMENTATION_FLAG];\n}\n\n/**\n * Check if React Router's instrumentation API's navigate hook was invoked.\n */\nexport function isNavigateHookInvoked(): boolean {\n return !!GLOBAL_WITH_FLAGS[SENTRY_NAVIGATE_HOOK_INVOKED_FLAG];\n}\n"],"names":["result","client","navigationSpan"],"mappings":"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"}
1
+ {"version":3,"file":"createClientInstrumentation.js","sources":["../../../src/client/createClientInstrumentation.ts"],"sourcesContent":["// oxlint-disable max-lines\nimport { getAbsoluteUrl, startBrowserTracingNavigationSpan } from '@sentry/browser';\nimport type { Span } from '@sentry/core';\nimport {\n debug,\n getActiveSpan,\n getClient,\n getRootSpan,\n GLOBAL_OBJ,\n hasSpanStreamingEnabled,\n NAVIGATION_SPAN_NAME_FALLBACK,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n spanToJSON,\n SPAN_STATUS_ERROR,\n updateSpanName,\n filterCollectedUrl,\n} from '@sentry/core';\nimport { startSpan } from '@sentry/core/browser';\nimport type { ClientInstrumentation } from 'react-router';\nimport { DEBUG_BUILD } from '../common/debug-build';\nimport { captureInstrumentationError, getPathFromRequest, getPattern, normalizeRoutePath } from '../common/utils';\nimport {\n resolveNavigateAbsoluteUrl,\n resolveNavigateArg,\n finalizeNavigationSpanFromHydratedRouter,\n updateNavigationSpanUrlFromLocation,\n} from './utils';\nimport {\n SENTRY_SEGMENT_NAME_SOURCE,\n CODE_FUNCTION_NAME,\n SENTRY_OP,\n URL_FULL,\n URL_TEMPLATE,\n} from '@sentry/conventions/attributes';\nimport { FUNCTION, MIDDLEWARE } from '@sentry/conventions/op';\n\nconst WINDOW = GLOBAL_OBJ as typeof GLOBAL_OBJ & Window;\n\n// Tracks active numeric navigation span to prevent duplicate spans when popstate fires\nlet currentNumericNavigationSpan: Span | undefined;\n\n// Per-request middleware counters, keyed by Request\nconst middlewareCountersMap = new WeakMap<object, Record<string, number>>();\n\nconst SENTRY_CLIENT_INSTRUMENTATION_FLAG = '__sentryReactRouterClientInstrumentationUsed';\n// Intentionally never reset - once set, instrumentation API handles all navigations for the session.\nconst SENTRY_NAVIGATE_HOOK_INVOKED_FLAG = '__sentryReactRouterNavigateHookInvoked';\nconst SENTRY_POPSTATE_LISTENER_ADDED_FLAG = '__sentryReactRouterPopstateListenerAdded';\n\ntype GlobalObjWithFlags = typeof GLOBAL_OBJ & {\n [SENTRY_CLIENT_INSTRUMENTATION_FLAG]?: boolean;\n [SENTRY_NAVIGATE_HOOK_INVOKED_FLAG]?: boolean;\n [SENTRY_POPSTATE_LISTENER_ADDED_FLAG]?: boolean;\n};\n\nconst GLOBAL_WITH_FLAGS = GLOBAL_OBJ as GlobalObjWithFlags;\n\n/**\n * Options for creating Sentry client instrumentation.\n */\nexport interface CreateSentryClientInstrumentationOptions {\n /**\n * Whether to capture errors from loaders/actions automatically.\n * Set to `false` to avoid duplicates if using custom error handlers.\n * @default true\n */\n captureErrors?: boolean;\n}\n\n/**\n * Creates a Sentry client instrumentation for React Router's instrumentation API.\n */\nexport function createSentryClientInstrumentation(\n options: CreateSentryClientInstrumentationOptions = {},\n): ClientInstrumentation {\n const { captureErrors = true } = options;\n\n DEBUG_BUILD && debug.log('React Router client instrumentation API created.');\n\n return {\n router(router) {\n // Set the flag when React Router actually invokes our instrumentation.\n // This ensures the flag is only set in Library Mode (where hooks run),\n // not in Framework Mode (where hooks are never called).\n // See: https://github.com/remix-run/react-router/discussions/13749\n GLOBAL_WITH_FLAGS[SENTRY_CLIENT_INSTRUMENTATION_FLAG] = true;\n DEBUG_BUILD && debug.log('React Router client instrumentation API router hook registered.');\n\n // Add popstate listener for browser back/forward navigation (persists for session, one listener only)\n if (!GLOBAL_WITH_FLAGS[SENTRY_POPSTATE_LISTENER_ADDED_FLAG] && WINDOW.addEventListener) {\n GLOBAL_WITH_FLAGS[SENTRY_POPSTATE_LISTENER_ADDED_FLAG] = true;\n\n WINDOW.addEventListener('popstate', () => {\n const client = getClient();\n if (!client) {\n currentNumericNavigationSpan = undefined;\n return;\n }\n\n const pathname = WINDOW.location?.pathname || '/';\n\n // If there's an active numeric navigation span, update it instead of creating a duplicate\n if (currentNumericNavigationSpan) {\n if (currentNumericNavigationSpan.isRecording()) {\n updateNavigationSpanUrlFromLocation(currentNumericNavigationSpan);\n }\n currentNumericNavigationSpan = undefined;\n return;\n }\n\n // Only create a new span for actual browser back/forward button clicks\n startBrowserTracingNavigationSpan(\n client,\n {\n // With span streaming, span names have to be low cardinality, so we can't fall back to\n // the URL. The route hooks parameterize the span once they resolve.\n name: hasSpanStreamingEnabled(client) ? NAVIGATION_SPAN_NAME_FALLBACK : pathname,\n attributes: {\n [SENTRY_SEGMENT_NAME_SOURCE]: 'url',\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'navigation',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.navigation.react_router.instrumentation_api',\n 'navigation.type': 'browser.popstate',\n },\n },\n { url: getAbsoluteUrl(pathname) },\n );\n });\n\n DEBUG_BUILD && debug.log('React Router popstate listener registered for browser back/forward navigation.');\n }\n\n router.instrument({\n async navigate(callNavigate, info) {\n // navigate(0) triggers a page reload - skip span creation, but still capture errors\n // (navigation can be rejected before reload, e.g., by a navigation guard)\n if (info.to === 0) {\n const result = await callNavigate();\n if (result.status === 'error' && result.error instanceof Error) {\n captureInstrumentationError(result, captureErrors, 'react_router.navigate', {\n [URL_FULL]: filterCollectedUrl(info.currentUrl),\n });\n }\n return;\n }\n\n GLOBAL_WITH_FLAGS[SENTRY_NAVIGATE_HOOK_INVOKED_FLAG] = true;\n\n // Handle numeric navigations (navigate(-1), navigate(1), etc.)\n if (typeof info.to === 'number') {\n const client = getClient();\n let navigationSpan;\n\n if (client) {\n const navigationType = info.to < 0 ? 'router.back' : 'router.forward';\n const currentPathname = WINDOW.location?.pathname || info.currentUrl;\n\n navigationSpan = startBrowserTracingNavigationSpan(\n client,\n {\n // With span streaming, span names have to be low cardinality, so we can't fall back\n // to the URL. The route is resolved once the navigation settles.\n name: hasSpanStreamingEnabled(client) ? NAVIGATION_SPAN_NAME_FALLBACK : currentPathname,\n attributes: {\n [SENTRY_SEGMENT_NAME_SOURCE]: 'url',\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'navigation',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.navigation.react_router.instrumentation_api',\n 'navigation.type': navigationType,\n },\n },\n { url: getAbsoluteUrl(currentPathname) },\n );\n\n // Store ref so popstate listener can update it instead of creating a duplicate\n currentNumericNavigationSpan = navigationSpan;\n }\n\n try {\n const result = await callNavigate();\n\n if (navigationSpan && WINDOW.location) {\n finalizeNavigationSpanFromHydratedRouter(navigationSpan);\n }\n\n if (result.status === 'error' && result.error instanceof Error) {\n if (navigationSpan) {\n navigationSpan.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n }\n captureInstrumentationError(result, captureErrors, 'react_router.navigate', {\n [URL_FULL]: WINDOW.location?.pathname || filterCollectedUrl(info.currentUrl),\n });\n }\n } finally {\n currentNumericNavigationSpan = undefined;\n }\n return;\n }\n\n // Handle string/object navigations (e.g., navigate('/about') or navigate({ pathname: '/about' }))\n const client = getClient();\n const toPath = resolveNavigateArg(info.to);\n let navigationSpan;\n\n if (client) {\n navigationSpan = startBrowserTracingNavigationSpan(\n client,\n {\n // With span streaming, span names have to be low cardinality, so we can't fall back to\n // the URL. The route hooks parameterize the span once they resolve.\n name: hasSpanStreamingEnabled(client) ? NAVIGATION_SPAN_NAME_FALLBACK : toPath,\n attributes: {\n [SENTRY_SEGMENT_NAME_SOURCE]: 'url',\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'navigation',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.navigation.react_router.instrumentation_api',\n 'navigation.type': 'router.navigate',\n },\n },\n { url: resolveNavigateAbsoluteUrl(info.to, info.currentUrl) },\n );\n }\n\n const result = await callNavigate();\n if (result.status === 'error' && result.error instanceof Error) {\n if (navigationSpan) {\n navigationSpan.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n }\n captureInstrumentationError(result, captureErrors, 'react_router.navigate', {\n [URL_FULL]: filterCollectedUrl(toPath),\n });\n }\n return;\n },\n\n async fetch(callFetch, info) {\n await startSpan(\n {\n name: `Fetcher ${info.fetcherKey}`,\n attributes: {\n [SENTRY_OP]: FUNCTION,\n [CODE_FUNCTION_NAME]: 'fetcher',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.react_router.instrumentation_api',\n },\n },\n async span => {\n const result = await callFetch();\n if (result.status === 'error' && result.error instanceof Error) {\n span.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n captureInstrumentationError(result, captureErrors, 'react_router.fetcher', {\n [URL_FULL]: filterCollectedUrl(info.href),\n });\n }\n },\n );\n },\n });\n },\n\n route(route) {\n const routeId = route.id;\n\n route.instrument({\n async loader(callLoader, info) {\n const urlPath = getPathFromRequest(info.request);\n const pattern = normalizeRoutePath(getPattern(info));\n const routePattern = pattern || urlPath;\n // Parameterize the active navigation root span. (Route hooks don't fire on initial\n // pageload, so this only affects navigations.)\n updateRootSpanRoute(routePattern, !!pattern);\n\n await startSpan(\n {\n name: routePattern,\n attributes: {\n [SENTRY_OP]: FUNCTION,\n [CODE_FUNCTION_NAME]: 'clientLoader',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.react_router.instrumentation_api',\n },\n },\n async span => {\n const result = await callLoader();\n if (result.status === 'error' && result.error instanceof Error) {\n span.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n captureInstrumentationError(result, captureErrors, 'react_router.client_loader', {\n [URL_FULL]: urlPath,\n });\n }\n },\n );\n },\n\n async action(callAction, info) {\n const urlPath = getPathFromRequest(info.request);\n const pattern = normalizeRoutePath(getPattern(info));\n const routePattern = pattern || urlPath;\n updateRootSpanRoute(routePattern, !!pattern);\n\n await startSpan(\n {\n name: routePattern,\n attributes: {\n [SENTRY_OP]: FUNCTION,\n [CODE_FUNCTION_NAME]: 'clientAction',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.react_router.instrumentation_api',\n },\n },\n async span => {\n const result = await callAction();\n if (result.status === 'error' && result.error instanceof Error) {\n span.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n captureInstrumentationError(result, captureErrors, 'react_router.client_action', {\n [URL_FULL]: urlPath,\n });\n }\n },\n );\n },\n\n async middleware(callMiddleware, info) {\n const urlPath = getPathFromRequest(info.request);\n const routePattern = normalizeRoutePath(getPattern(info)) || urlPath;\n\n let counters = middlewareCountersMap.get(info.request);\n if (!counters) {\n counters = {};\n middlewareCountersMap.set(info.request, counters);\n }\n\n const middlewareIndex = counters[routeId] ?? 0;\n counters[routeId] = middlewareIndex + 1;\n\n await startSpan(\n {\n name: `middleware ${routeId}`,\n attributes: {\n [SENTRY_OP]: MIDDLEWARE,\n [CODE_FUNCTION_NAME]: 'clientMiddleware',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.react_router.instrumentation_api',\n 'react_router.route.id': routeId,\n 'http.route': routePattern,\n 'react_router.middleware.index': middlewareIndex,\n },\n },\n async span => {\n const result = await callMiddleware();\n if (result.status === 'error' && result.error instanceof Error) {\n span.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n captureInstrumentationError(result, captureErrors, 'react_router.client_middleware', {\n [URL_FULL]: urlPath,\n });\n }\n },\n );\n },\n\n async lazy(callLazy) {\n await startSpan(\n {\n name: 'Lazy Route Load',\n attributes: {\n [SENTRY_OP]: FUNCTION,\n [CODE_FUNCTION_NAME]: 'lazy',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.react_router.instrumentation_api',\n },\n },\n async span => {\n const result = await callLazy();\n if (result.status === 'error' && result.error instanceof Error) {\n span.setStatus({ code: SPAN_STATUS_ERROR, message: 'internal_error' });\n captureInstrumentationError(result, captureErrors, 'react_router.client_lazy', {});\n }\n },\n );\n },\n });\n },\n };\n}\n\n/**\n * Updates the active navigation/pageload root span name with the parameterized route, so the\n * transaction reflects the parameterized route pattern (e.g. `/users/:id`).\n */\nfunction updateRootSpanRoute(routeName: string, hasPattern: boolean): void {\n if (!hasPattern) {\n return;\n }\n\n const activeSpan = getActiveSpan();\n const rootSpan = activeSpan && getRootSpan(activeSpan);\n if (!rootSpan) {\n return;\n }\n\n const { attributes } = spanToJSON(rootSpan);\n const op = attributes[SENTRY_OP];\n if (op !== 'navigation' && op !== 'pageload') {\n return;\n }\n\n updateSpanName(rootSpan, routeName);\n rootSpan.setAttributes({ [SENTRY_SEGMENT_NAME_SOURCE]: 'route', [URL_TEMPLATE]: routeName });\n}\n\n/**\n * Check if React Router's instrumentation API is being used on the client.\n */\nexport function isClientInstrumentationApiUsed(): boolean {\n return !!GLOBAL_WITH_FLAGS[SENTRY_CLIENT_INSTRUMENTATION_FLAG];\n}\n\n/**\n * Check if React Router's instrumentation API's navigate hook was invoked.\n */\nexport function isNavigateHookInvoked(): boolean {\n return !!GLOBAL_WITH_FLAGS[SENTRY_NAVIGATE_HOOK_INVOKED_FLAG];\n}\n"],"names":["result","client","navigationSpan"],"mappings":"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"}
@@ -1,9 +1,9 @@
1
1
  import { getAbsoluteUrl, startBrowserTracingNavigationSpan } from '@sentry/browser';
2
- import { GLOBAL_OBJ, spanToJSON, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, isThenable, debug, getActiveSpan, getRootSpan, getClient, SEMANTIC_ATTRIBUTE_SENTRY_OP } from '@sentry/core';
2
+ import { GLOBAL_OBJ, spanToJSON, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, isThenable, debug, getActiveSpan, getRootSpan, getClient, NAVIGATION_SPAN_NAME_FALLBACK, SEMANTIC_ATTRIBUTE_SENTRY_OP, hasSpanStreamingEnabled } from '@sentry/core';
3
3
  import { DEBUG_BUILD } from '../common/debug-build.js';
4
4
  import { isClientInstrumentationApiUsed } from './createClientInstrumentation.js';
5
- import { getParameterizedRoute, normalizePathname, finalizeNavigationSpanFromRouterState, resolveNavigateAbsoluteUrl, resolveNavigateArg } from './utils.js';
6
- import { URL_TEMPLATE, SENTRY_OP, URL_PATH } from '@sentry/conventions/attributes';
5
+ import { normalizePathname, updateSpanWithParameterizedRoute, finalizeNavigationSpanFromRouterState, resolveNavigateAbsoluteUrl, resolveNavigateArg } from './utils.js';
6
+ import { URL_PATH, SENTRY_OP, SENTRY_SEGMENT_NAME_SOURCE } from '@sentry/conventions/attributes';
7
7
 
8
8
  const GLOBAL_OBJ_WITH_DATA_ROUTER = GLOBAL_OBJ;
9
9
  const WINDOW = GLOBAL_OBJ;
@@ -14,16 +14,11 @@ function instrumentHydratedRouter() {
14
14
  if (router) {
15
15
  const pageloadSpan = getActiveRootSpan();
16
16
  if (pageloadSpan) {
17
- const pageloadName = spanToJSON(pageloadSpan).name;
18
- const parameterizePageloadRoute = getParameterizedRoute(router.state);
19
- if (pageloadName && // this event is for the currently active pageload
20
- normalizePathname(router.state.location.pathname) === normalizePathname(pageloadName)) {
21
- pageloadSpan.updateName(parameterizePageloadRoute);
22
- pageloadSpan.setAttributes({
23
- [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: "route",
24
- [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: "auto.pageload.react_router",
25
- [URL_TEMPLATE]: parameterizePageloadRoute
26
- });
17
+ const pageloadPath = spanToJSON(pageloadSpan).attributes[URL_PATH];
18
+ if (typeof pageloadPath === "string" && // this event is for the currently active pageload
19
+ normalizePathname(router.state.location.pathname) === normalizePathname(pageloadPath)) {
20
+ pageloadSpan.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, "auto.pageload.react_router");
21
+ updateSpanWithParameterizedRoute(pageloadSpan, router.state);
27
22
  }
28
23
  }
29
24
  if (typeof router.navigate === "function") {
@@ -70,21 +65,16 @@ function instrumentHydratedRouter() {
70
65
  }
71
66
  const rootSpanJson = spanToJSON(rootSpan);
72
67
  const rootSpanAttributes = rootSpanJson.attributes;
73
- if (rootSpanAttributes[SENTRY_OP] === "navigation" && isClientInstrumentationApiUsed() && rootSpanAttributes[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE] === "route") {
68
+ if (rootSpanAttributes[SENTRY_OP] === "navigation" && isClientInstrumentationApiUsed() && rootSpanAttributes[SENTRY_SEGMENT_NAME_SOURCE] === "route") {
74
69
  return;
75
70
  }
76
71
  const rootSpanName = rootSpanJson.name;
77
- const parameterizedRoute = getParameterizedRoute(newState);
78
72
  const spanPathname = rootSpanAttributes[URL_PATH];
79
73
  const destinationPathname = normalizePathname(newState.location.pathname);
80
74
  if (rootSpanName && newState.navigation.state === "idle" && // navigation has completed
81
75
  // this event is for the currently active root span
82
76
  (destinationPathname === normalizePathname(rootSpanName) || spanPathname && destinationPathname === normalizePathname(spanPathname))) {
83
- rootSpan.updateName(parameterizedRoute);
84
- rootSpan.setAttributes({
85
- [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: "route",
86
- [URL_TEMPLATE]: parameterizedRoute
87
- });
77
+ updateSpanWithParameterizedRoute(rootSpan, newState);
88
78
  }
89
79
  });
90
80
  return true;
@@ -112,9 +102,11 @@ function maybeCreateNavigationTransaction(name, url, source) {
112
102
  return startBrowserTracingNavigationSpan(
113
103
  client,
114
104
  {
115
- name,
105
+ // With span streaming, span names have to be low cardinality, so we can't fall back to the URL.
106
+ // The route is resolved once the router settles, which updates the span name then.
107
+ name: !hasSpanStreamingEnabled(client) ? name : NAVIGATION_SPAN_NAME_FALLBACK,
116
108
  attributes: {
117
- [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: source,
109
+ [SENTRY_SEGMENT_NAME_SOURCE]: source,
118
110
  [SEMANTIC_ATTRIBUTE_SENTRY_OP]: "navigation",
119
111
  [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: "auto.navigation.react_router",
120
112
  ...{}
@@ -1 +1 @@
1
- {"version":3,"file":"hydratedRouter.js","sources":["../../../src/client/hydratedRouter.ts"],"sourcesContent":["import { getAbsoluteUrl, startBrowserTracingNavigationSpan } from '@sentry/browser';\nimport type { Span } from '@sentry/core';\nimport {\n debug,\n getActiveSpan,\n getClient,\n getRootSpan,\n GLOBAL_OBJ,\n isThenable,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n SEMANTIC_ATTRIBUTE_SENTRY_SOURCE,\n spanToJSON,\n} from '@sentry/core';\nimport type { DataRouter } from 'react-router';\nimport { DEBUG_BUILD } from '../common/debug-build';\nimport { isClientInstrumentationApiUsed } from './createClientInstrumentation';\nimport {\n finalizeNavigationSpanFromRouterState,\n getParameterizedRoute,\n normalizePathname,\n resolveNavigateAbsoluteUrl,\n resolveNavigateArg,\n} from './utils';\nimport { SENTRY_OP, URL_PATH, URL_TEMPLATE } from '@sentry/conventions/attributes';\n\nconst GLOBAL_OBJ_WITH_DATA_ROUTER = GLOBAL_OBJ as typeof GLOBAL_OBJ & {\n __reactRouterDataRouter?: DataRouter;\n};\n\nconst WINDOW = GLOBAL_OBJ as typeof GLOBAL_OBJ & Window;\n\nconst MAX_RETRIES = 40; // 2 seconds at 50ms interval\n\n/**\n * Instruments the React Router Data Router for pageloads and navigation.\n *\n * This function waits for the router to be available after hydration, then:\n * 1. Updates the pageload transaction with parameterized route info\n * 2. Patches router.navigate() to create navigation transactions\n * 3. Subscribes to router state changes to update navigation transactions with parameterized routes\n */\nexport function instrumentHydratedRouter(): void {\n function trySubscribe(): boolean {\n const router = GLOBAL_OBJ_WITH_DATA_ROUTER.__reactRouterDataRouter;\n\n if (router) {\n // The first time we hit the router, we try to update the pageload transaction\n const pageloadSpan = getActiveRootSpan();\n\n if (pageloadSpan) {\n const pageloadName = spanToJSON(pageloadSpan).name;\n const parameterizePageloadRoute = getParameterizedRoute(router.state);\n if (\n pageloadName &&\n // this event is for the currently active pageload\n normalizePathname(router.state.location.pathname) === normalizePathname(pageloadName)\n ) {\n pageloadSpan.updateName(parameterizePageloadRoute);\n pageloadSpan.setAttributes({\n [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'route',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.pageload.react_router',\n [URL_TEMPLATE]: parameterizePageloadRoute,\n });\n }\n }\n\n // Patching navigate for creating accurate navigation transactions\n if (typeof router.navigate === 'function') {\n const originalNav = router.navigate.bind(router);\n router.navigate = function sentryPatchedNavigate(...args) {\n // Skip if instrumentation API is enabled (it handles navigation spans itself)\n if (!isClientInstrumentationApiUsed()) {\n const target = args[0];\n\n if (typeof target === 'number') {\n // navigate(0) triggers a reload, not a route change — skip span creation\n if (target !== 0) {\n const currentPathname = WINDOW.location?.pathname || '/';\n const navigationSpan = maybeCreateNavigationTransaction(\n currentPathname,\n getAbsoluteUrl(currentPathname),\n 'url',\n );\n\n const result = originalNav(...args);\n\n // Numeric navigations (`navigate(-1)`/`navigate(1)`) don't carry a destination\n // path, so we can only resolve the real URL/route once the router has settled.\n if (navigationSpan) {\n // Finalize from the (updated) router state after navigation completes, in both\n // the resolve and reject paths, so a rejected navigation still ends up with the\n // correct URL attributes instead of the placeholder start pathname.\n if (isThenable(result)) {\n result.then(\n () => finalizeNavigationSpanFromRouterState(navigationSpan, router.state),\n () => finalizeNavigationSpanFromRouterState(navigationSpan, router.state),\n );\n } else {\n finalizeNavigationSpanFromRouterState(navigationSpan, router.state);\n }\n }\n\n return result;\n }\n } else {\n maybeCreateNavigationTransaction(\n resolveNavigateArg(target) || '<unknown route>',\n resolveNavigateAbsoluteUrl(target),\n 'url',\n );\n }\n }\n return originalNav(...args);\n };\n }\n\n // Subscribe to router state changes to update navigation transactions (and any pageload\n // whose route info only became available after `trySubscribe`, e.g. lazy routes) with the\n // parameterized route.\n router.subscribe(newState => {\n const rootSpan = getActiveRootSpan();\n\n if (!rootSpan) {\n return;\n }\n\n const rootSpanJson = spanToJSON(rootSpan);\n const rootSpanAttributes = rootSpanJson.attributes;\n\n // When the instrumentation API is active, navigation roots are parameterized\n // by the native route hooks\n if (\n rootSpanAttributes[SENTRY_OP] === 'navigation' &&\n isClientInstrumentationApiUsed() &&\n rootSpanAttributes[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE] === 'route'\n ) {\n return;\n }\n\n const rootSpanName = rootSpanJson.name;\n const parameterizedRoute = getParameterizedRoute(newState);\n const spanPathname = rootSpanAttributes[URL_PATH] as string | undefined;\n const destinationPathname = normalizePathname(newState.location.pathname);\n\n if (\n rootSpanName &&\n newState.navigation.state === 'idle' && // navigation has completed\n // this event is for the currently active root span\n (destinationPathname === normalizePathname(rootSpanName) ||\n (spanPathname && destinationPathname === normalizePathname(spanPathname)))\n ) {\n rootSpan.updateName(parameterizedRoute);\n rootSpan.setAttributes({\n [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'route',\n [URL_TEMPLATE]: parameterizedRoute,\n });\n }\n });\n return true;\n }\n return false;\n }\n\n // Wait until the router is available (since the SDK loads before hydration)\n if (!trySubscribe()) {\n let retryCount = 0;\n // Retry until the router is available or max retries reached\n const interval = setInterval(() => {\n if (trySubscribe() || retryCount >= MAX_RETRIES) {\n if (retryCount >= MAX_RETRIES) {\n DEBUG_BUILD && debug.warn('Unable to instrument React Router: router not found after hydration.');\n }\n clearInterval(interval);\n }\n retryCount++;\n }, 50);\n }\n}\n\nfunction maybeCreateNavigationTransaction(name: string, url: string, source: 'url' | 'route'): Span | undefined {\n const client = getClient();\n\n if (!client) {\n return undefined;\n }\n\n return startBrowserTracingNavigationSpan(\n client,\n {\n name,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: source,\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'navigation',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.navigation.react_router',\n ...(source === 'route' ? { [URL_TEMPLATE]: name } : {}),\n },\n },\n { url },\n );\n}\n\nfunction getActiveRootSpan(): Span | undefined {\n const activeSpan = getActiveSpan();\n if (!activeSpan) {\n return undefined;\n }\n\n const rootSpan = getRootSpan(activeSpan);\n\n const op = spanToJSON(rootSpan).attributes[SENTRY_OP];\n\n // Only use this root span if it is a pageload or navigation span\n return op === 'navigation' || op === 'pageload' ? rootSpan : undefined;\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"hydratedRouter.js","sources":["../../../src/client/hydratedRouter.ts"],"sourcesContent":["import { getAbsoluteUrl, startBrowserTracingNavigationSpan } from '@sentry/browser';\nimport type { Span } from '@sentry/core';\nimport {\n debug,\n getActiveSpan,\n getClient,\n getRootSpan,\n GLOBAL_OBJ,\n hasSpanStreamingEnabled,\n isThenable,\n NAVIGATION_SPAN_NAME_FALLBACK,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n spanToJSON,\n} from '@sentry/core';\nimport type { DataRouter } from 'react-router';\nimport { DEBUG_BUILD } from '../common/debug-build';\nimport { isClientInstrumentationApiUsed } from './createClientInstrumentation';\nimport {\n finalizeNavigationSpanFromRouterState,\n normalizePathname,\n resolveNavigateAbsoluteUrl,\n resolveNavigateArg,\n updateSpanWithParameterizedRoute,\n} from './utils';\nimport { SENTRY_SEGMENT_NAME_SOURCE, SENTRY_OP, URL_PATH, URL_TEMPLATE } from '@sentry/conventions/attributes';\n\nconst GLOBAL_OBJ_WITH_DATA_ROUTER = GLOBAL_OBJ as typeof GLOBAL_OBJ & {\n __reactRouterDataRouter?: DataRouter;\n};\n\nconst WINDOW = GLOBAL_OBJ as typeof GLOBAL_OBJ & Window;\n\nconst MAX_RETRIES = 40; // 2 seconds at 50ms interval\n\n/**\n * Instruments the React Router Data Router for pageloads and navigation.\n *\n * This function waits for the router to be available after hydration, then:\n * 1. Updates the pageload transaction with parameterized route info\n * 2. Patches router.navigate() to create navigation transactions\n * 3. Subscribes to router state changes to update navigation transactions with parameterized routes\n */\nexport function instrumentHydratedRouter(): void {\n function trySubscribe(): boolean {\n const router = GLOBAL_OBJ_WITH_DATA_ROUTER.__reactRouterDataRouter;\n\n if (router) {\n // The first time we hit the router, we try to update the pageload transaction\n const pageloadSpan = getActiveRootSpan();\n\n if (pageloadSpan) {\n // Matched against `url.path` rather than the span name: with span streaming, the pageload\n // span is named `Pageload` until a route is resolved, so the name may not hold the pathname.\n const pageloadPath = spanToJSON(pageloadSpan).attributes[URL_PATH];\n if (\n typeof pageloadPath === 'string' &&\n // this event is for the currently active pageload\n normalizePathname(router.state.location.pathname) === normalizePathname(pageloadPath)\n ) {\n pageloadSpan.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, 'auto.pageload.react_router');\n updateSpanWithParameterizedRoute(pageloadSpan, router.state);\n }\n }\n\n // Patching navigate for creating accurate navigation transactions\n if (typeof router.navigate === 'function') {\n const originalNav = router.navigate.bind(router);\n router.navigate = function sentryPatchedNavigate(...args) {\n // Skip if instrumentation API is enabled (it handles navigation spans itself)\n if (!isClientInstrumentationApiUsed()) {\n const target = args[0];\n\n if (typeof target === 'number') {\n // navigate(0) triggers a reload, not a route change — skip span creation\n if (target !== 0) {\n const currentPathname = WINDOW.location?.pathname || '/';\n const navigationSpan = maybeCreateNavigationTransaction(\n currentPathname,\n getAbsoluteUrl(currentPathname),\n 'url',\n );\n\n const result = originalNav(...args);\n\n // Numeric navigations (`navigate(-1)`/`navigate(1)`) don't carry a destination\n // path, so we can only resolve the real URL/route once the router has settled.\n if (navigationSpan) {\n // Finalize from the (updated) router state after navigation completes, in both\n // the resolve and reject paths, so a rejected navigation still ends up with the\n // correct URL attributes instead of the placeholder start pathname.\n if (isThenable(result)) {\n result.then(\n () => finalizeNavigationSpanFromRouterState(navigationSpan, router.state),\n () => finalizeNavigationSpanFromRouterState(navigationSpan, router.state),\n );\n } else {\n finalizeNavigationSpanFromRouterState(navigationSpan, router.state);\n }\n }\n\n return result;\n }\n } else {\n maybeCreateNavigationTransaction(\n resolveNavigateArg(target) || '<unknown route>',\n resolveNavigateAbsoluteUrl(target),\n 'url',\n );\n }\n }\n return originalNav(...args);\n };\n }\n\n // Subscribe to router state changes to update navigation transactions (and any pageload\n // whose route info only became available after `trySubscribe`, e.g. lazy routes) with the\n // parameterized route.\n router.subscribe(newState => {\n const rootSpan = getActiveRootSpan();\n\n if (!rootSpan) {\n return;\n }\n\n const rootSpanJson = spanToJSON(rootSpan);\n const rootSpanAttributes = rootSpanJson.attributes;\n\n // When the instrumentation API is active, navigation roots are parameterized\n // by the native route hooks\n if (\n rootSpanAttributes[SENTRY_OP] === 'navigation' &&\n isClientInstrumentationApiUsed() &&\n rootSpanAttributes[SENTRY_SEGMENT_NAME_SOURCE] === 'route'\n ) {\n return;\n }\n\n const rootSpanName = rootSpanJson.name;\n const spanPathname = rootSpanAttributes[URL_PATH] as string | undefined;\n const destinationPathname = normalizePathname(newState.location.pathname);\n\n if (\n rootSpanName &&\n newState.navigation.state === 'idle' && // navigation has completed\n // this event is for the currently active root span\n (destinationPathname === normalizePathname(rootSpanName) ||\n (spanPathname && destinationPathname === normalizePathname(spanPathname)))\n ) {\n updateSpanWithParameterizedRoute(rootSpan, newState);\n }\n });\n return true;\n }\n return false;\n }\n\n // Wait until the router is available (since the SDK loads before hydration)\n if (!trySubscribe()) {\n let retryCount = 0;\n // Retry until the router is available or max retries reached\n const interval = setInterval(() => {\n if (trySubscribe() || retryCount >= MAX_RETRIES) {\n if (retryCount >= MAX_RETRIES) {\n DEBUG_BUILD && debug.warn('Unable to instrument React Router: router not found after hydration.');\n }\n clearInterval(interval);\n }\n retryCount++;\n }, 50);\n }\n}\n\nfunction maybeCreateNavigationTransaction(name: string, url: string, source: 'url' | 'route'): Span | undefined {\n const client = getClient();\n\n if (!client) {\n return undefined;\n }\n\n return startBrowserTracingNavigationSpan(\n client,\n {\n // With span streaming, span names have to be low cardinality, so we can't fall back to the URL.\n // The route is resolved once the router settles, which updates the span name then.\n name: source === 'route' || !hasSpanStreamingEnabled(client) ? name : NAVIGATION_SPAN_NAME_FALLBACK,\n attributes: {\n [SENTRY_SEGMENT_NAME_SOURCE]: source,\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'navigation',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.navigation.react_router',\n ...(source === 'route' ? { [URL_TEMPLATE]: name } : {}),\n },\n },\n { url },\n );\n}\n\nfunction getActiveRootSpan(): Span | undefined {\n const activeSpan = getActiveSpan();\n if (!activeSpan) {\n return undefined;\n }\n\n const rootSpan = getRootSpan(activeSpan);\n\n const op = spanToJSON(rootSpan).attributes[SENTRY_OP];\n\n // Only use this root span if it is a pageload or navigation span\n return op === 'navigation' || op === 'pageload' ? rootSpan : undefined;\n}\n"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"tracingIntegration.js","sources":["../../../src/client/tracingIntegration.ts"],"sourcesContent":["import { browserTracingIntegration as originalBrowserTracingIntegration } from '@sentry/browser';\nimport type { Integration } from '@sentry/core';\nimport type { ClientInstrumentation } from '../common/types';\nimport {\n createSentryClientInstrumentation,\n type CreateSentryClientInstrumentationOptions,\n} from './createClientInstrumentation';\nimport { instrumentHydratedRouter } from './hydratedRouter';\n\n/**\n * Options for the React Router tracing integration.\n */\nexport interface ReactRouterTracingIntegrationOptions {\n /**\n * Options for React Router's instrumentation API.\n */\n instrumentationOptions?: CreateSentryClientInstrumentationOptions;\n\n /** @deprecated `clientInstrumentation` is always built, so this flag is a no-op. Will be removed in a future major. */\n useInstrumentationAPI?: boolean;\n}\n\n/**\n * React Router tracing integration with support for the instrumentation API.\n */\nexport interface ReactRouterTracingIntegration extends Integration {\n /**\n * Client instrumentation to pass to `HydratedRouter`'s `instrumentations` prop.\n *\n * @deprecated Use the standalone `createSentryClientInstrumentation()` export instead and pass its\n * result to `HydratedRouter`'s `instrumentations` prop. This mirrors the server-side\n * `createSentryServerInstrumentation()` API. Will be removed in a future major.\n */\n readonly clientInstrumentation: ClientInstrumentation;\n}\n\n/**\n * Browser tracing integration for React Router (Framework) applications.\n * This integration will create navigation spans and enhance transaction names with parameterized routes.\n */\nexport function reactRouterTracingIntegration(\n options: ReactRouterTracingIntegrationOptions = {},\n): ReactRouterTracingIntegration {\n const browserTracingIntegrationInstance = originalBrowserTracingIntegration({\n // Navigation transactions are started within the hydrated router instrumentation\n instrumentNavigation: false,\n });\n\n // Built eagerly so it can be passed to HydratedRouter's `instrumentations` prop. This has no\n // side effects - the API is only marked \"used\" once React Router invokes the `router()` hook.\n const clientInstrumentationInstance = createSentryClientInstrumentation(options.instrumentationOptions);\n\n return {\n ...browserTracingIntegrationInstance,\n name: 'ReactRouterTracingIntegration',\n afterAllSetup(client) {\n browserTracingIntegrationInstance.afterAllSetup(client);\n instrumentHydratedRouter();\n },\n // oxlint-disable-next-line typescript/no-deprecated -- exposes the deprecated getter for back-compat until it is removed\n get clientInstrumentation(): ClientInstrumentation {\n return clientInstrumentationInstance;\n },\n };\n}\n"],"names":["originalBrowserTracingIntegration"],"mappings":";;;;AAwCO,SAAS,6BAAA,CACd,OAAA,GAAgD,EAAC,EAClB;AAC/B,EAAA,MAAM,oCAAoCA,yBAAA,CAAkC;AAAA;AAAA,IAE1E,oBAAA,EAAsB;AAAA,GACvB,CAAA;AAID,EAAA,MAAM,6BAAA,GAAgC,iCAAA,CAAkC,OAAA,CAAQ,sBAAsB,CAAA;AAEtG,EAAA,OAAO;AAAA,IACL,GAAG,iCAAA;AAAA,IACH,IAAA,EAAM,+BAAA;AAAA,IACN,cAAc,MAAA,EAAQ;AACpB,MAAA,iCAAA,CAAkC,cAAc,MAAM,CAAA;AACtD,MAAA,wBAAA,EAAyB;AAAA,IAC3B,CAAA;AAAA;AAAA,IAEA,IAAI,qBAAA,GAA+C;AACjD,MAAA,OAAO,6BAAA;AAAA,IACT;AAAA,GACF;AACF;;;;"}
1
+ {"version":3,"file":"tracingIntegration.js","sources":["../../../src/client/tracingIntegration.ts"],"sourcesContent":["import { browserTracingIntegration as originalBrowserTracingIntegration } from '@sentry/browser';\nimport type { Integration } from '@sentry/core';\nimport type { ClientInstrumentation } from 'react-router';\nimport {\n createSentryClientInstrumentation,\n type CreateSentryClientInstrumentationOptions,\n} from './createClientInstrumentation';\nimport { instrumentHydratedRouter } from './hydratedRouter';\n\n/**\n * Options for the React Router tracing integration.\n */\nexport interface ReactRouterTracingIntegrationOptions {\n /**\n * Options for React Router's instrumentation API.\n */\n instrumentationOptions?: CreateSentryClientInstrumentationOptions;\n\n /** @deprecated `clientInstrumentation` is always built, so this flag is a no-op. Will be removed in a future major. */\n useInstrumentationAPI?: boolean;\n}\n\n/**\n * React Router tracing integration with support for the instrumentation API.\n */\nexport interface ReactRouterTracingIntegration extends Integration {\n /**\n * Client instrumentation to pass to `HydratedRouter`'s `instrumentations` prop.\n *\n * @deprecated Use the standalone `createSentryClientInstrumentation()` export instead and pass its\n * result to `HydratedRouter`'s `instrumentations` prop. This mirrors the server-side\n * `createSentryServerInstrumentation()` API. Will be removed in a future major.\n */\n readonly clientInstrumentation: ClientInstrumentation;\n}\n\n/**\n * Browser tracing integration for React Router (Framework) applications.\n * This integration will create navigation spans and enhance transaction names with parameterized routes.\n */\nexport function reactRouterTracingIntegration(\n options: ReactRouterTracingIntegrationOptions = {},\n): ReactRouterTracingIntegration {\n const browserTracingIntegrationInstance = originalBrowserTracingIntegration({\n // Navigation transactions are started within the hydrated router instrumentation\n instrumentNavigation: false,\n });\n\n // Built eagerly so it can be passed to HydratedRouter's `instrumentations` prop. This has no\n // side effects - the API is only marked \"used\" once React Router invokes the `router()` hook.\n const clientInstrumentationInstance = createSentryClientInstrumentation(options.instrumentationOptions);\n\n return {\n ...browserTracingIntegrationInstance,\n name: 'ReactRouterTracingIntegration',\n afterAllSetup(client) {\n browserTracingIntegrationInstance.afterAllSetup(client);\n instrumentHydratedRouter();\n },\n // oxlint-disable-next-line typescript/no-deprecated -- exposes the deprecated getter for back-compat until it is removed\n get clientInstrumentation(): ClientInstrumentation {\n return clientInstrumentationInstance;\n },\n };\n}\n"],"names":["originalBrowserTracingIntegration"],"mappings":";;;;AAwCO,SAAS,6BAAA,CACd,OAAA,GAAgD,EAAC,EAClB;AAC/B,EAAA,MAAM,oCAAoCA,yBAAA,CAAkC;AAAA;AAAA,IAE1E,oBAAA,EAAsB;AAAA,GACvB,CAAA;AAID,EAAA,MAAM,6BAAA,GAAgC,iCAAA,CAAkC,OAAA,CAAQ,sBAAsB,CAAA;AAEtG,EAAA,OAAO;AAAA,IACL,GAAG,iCAAA;AAAA,IACH,IAAA,EAAM,+BAAA;AAAA,IACN,cAAc,MAAA,EAAQ;AACpB,MAAA,iCAAA,CAAkC,cAAc,MAAM,CAAA;AACtD,MAAA,wBAAA,EAAyB;AAAA,IAC3B,CAAA;AAAA;AAAA,IAEA,IAAI,qBAAA,GAA+C;AACjD,MAAA,OAAO,6BAAA;AAAA,IACT;AAAA,GACF;AACF;;;;"}
@@ -1,6 +1,6 @@
1
1
  import { getAbsoluteUrl } from '@sentry/browser';
2
- import { GLOBAL_OBJ, filterCollectedUrl, SEMANTIC_ATTRIBUTE_SENTRY_SOURCE } from '@sentry/core';
3
- import { URL_FULL, URL_PATH, URL_TEMPLATE } from '@sentry/conventions/attributes';
2
+ import { GLOBAL_OBJ, getClient, NAVIGATION_SPAN_NAME_FALLBACK, hasSpanStreamingEnabled, filterCollectedUrl } from '@sentry/core';
3
+ import { URL_FULL, URL_PATH, SENTRY_SEGMENT_NAME_SOURCE, URL_TEMPLATE } from '@sentry/conventions/attributes';
4
4
 
5
5
  const WINDOW = GLOBAL_OBJ;
6
6
  const GLOBAL_OBJ_WITH_DATA_ROUTER = GLOBAL_OBJ;
@@ -51,9 +51,10 @@ function updateNavigationSpanUrlFromLocation(span) {
51
51
  }
52
52
  const { pathname, search = "", hash = "" } = WINDOW.location;
53
53
  const destinationUrl = getAbsoluteUrl(`${pathname}${search}${hash}`);
54
- span.updateName(pathname);
54
+ const client = getClient();
55
+ span.updateName(client && hasSpanStreamingEnabled(client) ? NAVIGATION_SPAN_NAME_FALLBACK : pathname);
55
56
  span.setAttributes({
56
- [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: "url",
57
+ [SENTRY_SEGMENT_NAME_SOURCE]: "url",
57
58
  [URL_PATH]: pathname,
58
59
  [URL_FULL]: filterCollectedUrl(destinationUrl)
59
60
  });
@@ -65,9 +66,33 @@ function normalizePathname(pathname) {
65
66
  }
66
67
  return normalized;
67
68
  }
68
- function getParameterizedRoute(routerState) {
69
- const lastMatch = routerState.matches[routerState.matches.length - 1];
70
- return normalizePathname(lastMatch?.route.path || routerState.location.pathname);
69
+ function getRouteTemplate(routerState) {
70
+ const { matches } = routerState;
71
+ if (!matches.length) {
72
+ return void 0;
73
+ }
74
+ let template = "";
75
+ for (const match of matches) {
76
+ const routePath = match.route.path;
77
+ if (!routePath) {
78
+ continue;
79
+ }
80
+ template = routePath.startsWith("/") ? routePath : `${template.replace(/\/$/, "")}/${routePath}`;
81
+ }
82
+ return normalizePathname(template);
83
+ }
84
+ function updateSpanWithParameterizedRoute(span, routerState) {
85
+ const routeTemplate = getRouteTemplate(routerState);
86
+ const client = getClient();
87
+ if (!routeTemplate && client && hasSpanStreamingEnabled(client)) {
88
+ return;
89
+ }
90
+ const parameterizedRoute = routeTemplate || normalizePathname(routerState.location.pathname);
91
+ span.updateName(parameterizedRoute);
92
+ span.setAttributes({
93
+ [SENTRY_SEGMENT_NAME_SOURCE]: "route",
94
+ [URL_TEMPLATE]: parameterizedRoute
95
+ });
71
96
  }
72
97
  function finalizeNavigationSpanFromRouterState(span, routerState) {
73
98
  updateNavigationSpanUrlFromLocation(span);
@@ -76,12 +101,7 @@ function finalizeNavigationSpanFromRouterState(span, routerState) {
76
101
  }
77
102
  const { pathname } = WINDOW.location;
78
103
  if (routerState.navigation?.state === "idle" && normalizePathname(routerState.location.pathname) === normalizePathname(pathname)) {
79
- const parameterizedRoute = getParameterizedRoute(routerState);
80
- span.updateName(parameterizedRoute);
81
- span.setAttributes({
82
- [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: "route",
83
- [URL_TEMPLATE]: parameterizedRoute
84
- });
104
+ updateSpanWithParameterizedRoute(span, routerState);
85
105
  }
86
106
  }
87
107
  function finalizeNavigationSpanFromHydratedRouter(span) {
@@ -93,5 +113,5 @@ function finalizeNavigationSpanFromHydratedRouter(span) {
93
113
  }
94
114
  }
95
115
 
96
- export { finalizeNavigationSpanFromHydratedRouter, finalizeNavigationSpanFromRouterState, getParameterizedRoute, normalizePathname, resolveNavigateAbsoluteUrl, resolveNavigateArg, resolveNavigateUrl, updateNavigationSpanUrlFromLocation };
116
+ export { finalizeNavigationSpanFromHydratedRouter, finalizeNavigationSpanFromRouterState, normalizePathname, resolveNavigateAbsoluteUrl, resolveNavigateArg, resolveNavigateUrl, updateNavigationSpanUrlFromLocation, updateSpanWithParameterizedRoute };
97
117
  //# sourceMappingURL=utils.js.map