@sentry/react 11.0.0-alpha.0 → 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 (34) hide show
  1. package/build/cjs/profiler.js +12 -15
  2. package/build/cjs/profiler.js.map +1 -1
  3. package/build/cjs/reactrouter-compat-utils/instrumentation.js +43 -33
  4. package/build/cjs/reactrouter-compat-utils/instrumentation.js.map +1 -1
  5. package/build/cjs/reactrouter-compat-utils/utils.js +2 -1
  6. package/build/cjs/reactrouter-compat-utils/utils.js.map +1 -1
  7. package/build/cjs/reactrouter.js +8 -6
  8. package/build/cjs/reactrouter.js.map +1 -1
  9. package/build/cjs/reactrouterv3.js +6 -4
  10. package/build/cjs/reactrouterv3.js.map +1 -1
  11. package/build/cjs/tanstackrouter.js +20 -9
  12. package/build/cjs/tanstackrouter.js.map +1 -1
  13. package/build/esm/package.json +1 -1
  14. package/build/esm/profiler.js +14 -17
  15. package/build/esm/profiler.js.map +1 -1
  16. package/build/esm/reactrouter-compat-utils/instrumentation.js +45 -35
  17. package/build/esm/reactrouter-compat-utils/instrumentation.js.map +1 -1
  18. package/build/esm/reactrouter-compat-utils/utils.js +2 -1
  19. package/build/esm/reactrouter-compat-utils/utils.js.map +1 -1
  20. package/build/esm/reactrouter.js +10 -8
  21. package/build/esm/reactrouter.js.map +1 -1
  22. package/build/esm/reactrouterv3.js +8 -6
  23. package/build/esm/reactrouterv3.js.map +1 -1
  24. package/build/esm/tanstackrouter.js +23 -12
  25. package/build/esm/tanstackrouter.js.map +1 -1
  26. package/build/types/profiler.d.ts.map +1 -1
  27. package/build/types/reactrouter-compat-utils/instrumentation.d.ts.map +1 -1
  28. package/build/types/reactrouter-compat-utils/utils.d.ts.map +1 -1
  29. package/build/types/reactrouter.d.ts.map +1 -1
  30. package/build/types/reactrouterv3.d.ts.map +1 -1
  31. package/build/types/tanstackrouter.d.ts.map +1 -1
  32. package/build/types/vendor/tanstackrouter-types.d.ts +1 -0
  33. package/build/types/vendor/tanstackrouter-types.d.ts.map +1 -1
  34. package/package.json +5 -4
@@ -19,10 +19,9 @@ class Profiler extends React.Component {
19
19
  name: `<${name}>`,
20
20
  onlyIfParent: true,
21
21
  attributes: {
22
- // TODO(conventions): Replace `'ui.mount'` with the `ui.mount` span op constant once it is released in `@sentry/conventions`.
23
- [attributes.SENTRY_OP]: "ui.mount",
22
+ [attributes.SENTRY_OP]: op.UI_MOUNT,
24
23
  [core.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: "auto.ui.react.profiler",
25
- "ui.component_name": name
24
+ [attributes.UI_COMPONENT_NAME]: name
26
25
  }
27
26
  });
28
27
  }
@@ -43,10 +42,9 @@ class Profiler extends React.Component {
43
42
  onlyIfParent: true,
44
43
  startTime: now,
45
44
  attributes: {
46
- // TODO(conventions): Replace `'ui.update'` with the `ui.update` span op constant once it is released in `@sentry/conventions`.
47
- [attributes.SENTRY_OP]: "ui.update",
45
+ [attributes.SENTRY_OP]: op.UI_UPDATE,
48
46
  [core.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: "auto.ui.react.profiler",
49
- "ui.component_name": this.props.name,
47
+ [attributes.UI_COMPONENT_NAME]: this.props.name,
50
48
  "ui.react.changed_props": changedProps
51
49
  }
52
50
  });
@@ -67,16 +65,16 @@ class Profiler extends React.Component {
67
65
  const endTimestamp = core.timestampInSeconds();
68
66
  const { name, includeRender = true } = this.props;
69
67
  if (this._mountSpan && includeRender) {
70
- const startTime = core.spanToJSON(this._mountSpan).timestamp;
68
+ const startTime = core.spanToJSON(this._mountSpan).end_timestamp;
71
69
  core.withActiveSpan(this._mountSpan, () => {
72
70
  const renderSpan = browser.startInactiveSpan({
73
71
  onlyIfParent: true,
74
72
  name: `<${name}>`,
75
73
  startTime,
76
74
  attributes: {
77
- [attributes.SENTRY_OP]: op.BROWSER_UI_RENDER_SPAN_OP,
75
+ [attributes.SENTRY_OP]: op.UI_RENDER,
78
76
  [core.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: "auto.ui.react.profiler",
79
- "ui.component_name": name
77
+ [attributes.UI_COMPONENT_NAME]: name
80
78
  }
81
79
  });
82
80
  if (renderSpan) {
@@ -115,10 +113,9 @@ function useProfiler(name, options = {
115
113
  name: `<${name}>`,
116
114
  onlyIfParent: true,
117
115
  attributes: {
118
- // TODO(conventions): Replace `'ui.mount'` with the `ui.mount` span op constant once it is released in `@sentry/conventions`.
119
- [attributes.SENTRY_OP]: "ui.mount",
116
+ [attributes.SENTRY_OP]: op.UI_MOUNT,
120
117
  [core.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: "auto.ui.react.profiler",
121
- "ui.component_name": name
118
+ [attributes.UI_COMPONENT_NAME]: name
122
119
  }
123
120
  });
124
121
  });
@@ -128,16 +125,16 @@ function useProfiler(name, options = {
128
125
  }
129
126
  return () => {
130
127
  if (mountSpan && options.hasRenderSpan) {
131
- const startTime = core.spanToJSON(mountSpan).timestamp;
128
+ const startTime = core.spanToJSON(mountSpan).end_timestamp;
132
129
  const endTimestamp = core.timestampInSeconds();
133
130
  const renderSpan = browser.startInactiveSpan({
134
131
  name: `<${name}>`,
135
132
  onlyIfParent: true,
136
133
  startTime,
137
134
  attributes: {
138
- [attributes.SENTRY_OP]: op.BROWSER_UI_RENDER_SPAN_OP,
135
+ [attributes.SENTRY_OP]: op.UI_RENDER,
139
136
  [core.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: "auto.ui.react.profiler",
140
- "ui.component_name": name
137
+ [attributes.UI_COMPONENT_NAME]: name
141
138
  }
142
139
  });
143
140
  if (renderSpan) {
@@ -1 +1 @@
1
- {"version":3,"file":"profiler.js","sources":["../../src/profiler.tsx"],"sourcesContent":["import { startInactiveSpan } from '@sentry/browser';\nimport type { Span } from '@sentry/core';\nimport { SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, spanToJSON, timestampInSeconds, withActiveSpan } from '@sentry/core';\nimport { SENTRY_OP } from '@sentry/conventions/attributes';\nimport { BROWSER_UI_RENDER_SPAN_OP } from '@sentry/conventions/op';\nimport * as React from 'react';\nimport { hoistNonReactStatics } from './hoist-non-react-statics';\n\nexport const UNKNOWN_COMPONENT = 'unknown';\n\nexport type ProfilerProps = {\n // The name of the component being profiled.\n name: string;\n // If the Profiler is disabled. False by default. This is useful if you want to disable profilers\n // in certain environments.\n disabled?: boolean;\n // If time component is on page should be displayed as spans. True by default.\n includeRender?: boolean;\n // If component updates should be displayed as spans. True by default.\n includeUpdates?: boolean;\n // Component that is being profiled.\n children?: React.ReactNode;\n // props given to component being profiled.\n updateProps: { [key: string]: unknown };\n};\n\n/**\n * The Profiler component leverages Sentry's Tracing integration to generate\n * spans based on component lifecycles.\n */\nclass Profiler extends React.Component<ProfilerProps> {\n /**\n * The span of the mount activity\n * Made protected for the React Native SDK to access\n */\n protected _mountSpan: Span | undefined;\n /**\n * The span that represents the duration of time between shouldComponentUpdate and componentDidUpdate\n */\n protected _updateSpan: Span | undefined;\n\n public constructor(props: ProfilerProps) {\n super(props);\n const { name, disabled = false } = this.props;\n\n if (disabled) {\n return;\n }\n\n this._mountSpan = startInactiveSpan({\n name: `<${name}>`,\n onlyIfParent: true,\n attributes: {\n // TODO(conventions): Replace `'ui.mount'` with the `ui.mount` span op constant once it is released in `@sentry/conventions`.\n [SENTRY_OP]: 'ui.mount',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.ui.react.profiler',\n 'ui.component_name': name,\n },\n });\n }\n\n // If a component mounted, we can finish the mount activity.\n public componentDidMount(): void {\n if (this._mountSpan) {\n this._mountSpan.end();\n }\n }\n\n public shouldComponentUpdate({ updateProps, includeUpdates = true }: ProfilerProps): boolean {\n // Only generate an update span if includeUpdates is true, if there is a valid mountSpan,\n // and if the updateProps have changed. It is ok to not do a deep equality check here as it is expensive.\n // We are just trying to give baseline clues for further investigation.\n if (includeUpdates && this._mountSpan && updateProps !== this.props.updateProps) {\n // See what props have changed between the previous props, and the current props. This is\n // set as data on the span. We just store the prop keys as the values could be potentially very large.\n const changedProps = Object.keys(updateProps).filter(k => updateProps[k] !== this.props.updateProps[k]);\n if (changedProps.length > 0) {\n const now = timestampInSeconds();\n this._updateSpan = withActiveSpan(this._mountSpan, () => {\n return startInactiveSpan({\n name: `<${this.props.name}>`,\n onlyIfParent: true,\n startTime: now,\n attributes: {\n // TODO(conventions): Replace `'ui.update'` with the `ui.update` span op constant once it is released in `@sentry/conventions`.\n [SENTRY_OP]: 'ui.update',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.ui.react.profiler',\n 'ui.component_name': this.props.name,\n 'ui.react.changed_props': changedProps,\n },\n });\n });\n }\n }\n\n return true;\n }\n\n public componentDidUpdate(): void {\n if (this._updateSpan) {\n this._updateSpan.end();\n this._updateSpan = undefined;\n }\n }\n\n // If a component is unmounted, we can say it is no longer on the screen.\n // This means we can finish the span representing the component render.\n public componentWillUnmount(): void {\n const endTimestamp = timestampInSeconds();\n const { name, includeRender = true } = this.props;\n\n if (this._mountSpan && includeRender) {\n const startTime = spanToJSON(this._mountSpan).timestamp;\n withActiveSpan(this._mountSpan, () => {\n const renderSpan = startInactiveSpan({\n onlyIfParent: true,\n name: `<${name}>`,\n startTime,\n attributes: {\n [SENTRY_OP]: BROWSER_UI_RENDER_SPAN_OP,\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.ui.react.profiler',\n 'ui.component_name': name,\n },\n });\n if (renderSpan) {\n // Have to cast to Span because the type of _mountSpan is Span | undefined\n // and not getting narrowed properly\n renderSpan.end(endTimestamp);\n }\n });\n }\n }\n\n public render(): React.ReactNode {\n return this.props.children;\n }\n}\n\n// React.Component default props are defined as static property on the class\nObject.assign(Profiler, {\n defaultProps: {\n disabled: false,\n includeRender: true,\n includeUpdates: true,\n },\n});\n\n/**\n * withProfiler is a higher order component that wraps a\n * component in a {@link Profiler} component. It is recommended that\n * the higher order component be used over the regular {@link Profiler} component.\n *\n * @param WrappedComponent component that is wrapped by Profiler\n * @param options the {@link ProfilerProps} you can pass into the Profiler\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction withProfiler<P extends Record<string, any>>(\n WrappedComponent: React.ComponentType<P>,\n // We do not want to have `updateProps` given in options, it is instead filled through the HOC.\n options?: Pick<Partial<ProfilerProps>, Exclude<keyof ProfilerProps, 'updateProps' | 'children'>>,\n): React.FC<P> {\n const componentDisplayName =\n options?.name || WrappedComponent.displayName || WrappedComponent.name || UNKNOWN_COMPONENT;\n\n const Wrapped: React.FC<P> = (props: P) => (\n <Profiler {...options} name={componentDisplayName} updateProps={props}>\n <WrappedComponent {...props} />\n </Profiler>\n );\n\n Wrapped.displayName = `profiler(${componentDisplayName})`;\n\n // Copy over static methods from Wrapped component to Profiler HOC\n // See: https://reactjs.org/docs/higher-order-components.html#static-methods-must-be-copied-over\n hoistNonReactStatics(Wrapped, WrappedComponent);\n return Wrapped;\n}\n\n/**\n *\n * `useProfiler` is a React hook that profiles a React component.\n *\n * @param name displayName of component being profiled\n */\nfunction useProfiler(\n name: string,\n options: { disabled?: boolean; hasRenderSpan?: boolean } = {\n disabled: false,\n hasRenderSpan: true,\n },\n): void {\n const [mountSpan] = React.useState(() => {\n if (options?.disabled) {\n return undefined;\n }\n\n return startInactiveSpan({\n name: `<${name}>`,\n onlyIfParent: true,\n attributes: {\n // TODO(conventions): Replace `'ui.mount'` with the `ui.mount` span op constant once it is released in `@sentry/conventions`.\n [SENTRY_OP]: 'ui.mount',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.ui.react.profiler',\n 'ui.component_name': name,\n },\n });\n });\n\n React.useEffect(() => {\n if (mountSpan) {\n mountSpan.end();\n }\n\n return (): void => {\n if (mountSpan && options.hasRenderSpan) {\n const startTime = spanToJSON(mountSpan).timestamp;\n const endTimestamp = timestampInSeconds();\n\n const renderSpan = startInactiveSpan({\n name: `<${name}>`,\n onlyIfParent: true,\n startTime,\n attributes: {\n [SENTRY_OP]: BROWSER_UI_RENDER_SPAN_OP,\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.ui.react.profiler',\n 'ui.component_name': name,\n },\n });\n if (renderSpan) {\n // Have to cast to Span because the type of _mountSpan is Span | undefined\n // and not getting narrowed properly\n renderSpan.end(endTimestamp);\n }\n }\n };\n // We only want this to run once.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n}\n\nexport { Profiler, useProfiler, withProfiler };\n"],"names":["startInactiveSpan","SENTRY_OP","SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN","timestampInSeconds","withActiveSpan","spanToJSON","BROWSER_UI_RENDER_SPAN_OP","hoistNonReactStatics"],"mappings":"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"}
1
+ {"version":3,"file":"profiler.js","sources":["../../src/profiler.tsx"],"sourcesContent":["import { startInactiveSpan } from '@sentry/browser';\nimport type { Span } from '@sentry/core';\nimport { SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, spanToJSON, timestampInSeconds, withActiveSpan } from '@sentry/core';\nimport { SENTRY_OP, UI_COMPONENT_NAME } from '@sentry/conventions/attributes';\nimport { UI_MOUNT, UI_RENDER, UI_UPDATE } from '@sentry/conventions/op';\nimport * as React from 'react';\nimport { hoistNonReactStatics } from './hoist-non-react-statics';\n\nexport const UNKNOWN_COMPONENT = 'unknown';\n\nexport type ProfilerProps = {\n // The name of the component being profiled.\n name: string;\n // If the Profiler is disabled. False by default. This is useful if you want to disable profilers\n // in certain environments.\n disabled?: boolean;\n // If time component is on page should be displayed as spans. True by default.\n includeRender?: boolean;\n // If component updates should be displayed as spans. True by default.\n includeUpdates?: boolean;\n // Component that is being profiled.\n children?: React.ReactNode;\n // props given to component being profiled.\n updateProps: { [key: string]: unknown };\n};\n\n/**\n * The Profiler component leverages Sentry's Tracing integration to generate\n * spans based on component lifecycles.\n */\nclass Profiler extends React.Component<ProfilerProps> {\n /**\n * The span of the mount activity\n * Made protected for the React Native SDK to access\n */\n protected _mountSpan: Span | undefined;\n /**\n * The span that represents the duration of time between shouldComponentUpdate and componentDidUpdate\n */\n protected _updateSpan: Span | undefined;\n\n public constructor(props: ProfilerProps) {\n super(props);\n const { name, disabled = false } = this.props;\n\n if (disabled) {\n return;\n }\n\n this._mountSpan = startInactiveSpan({\n name: `<${name}>`,\n onlyIfParent: true,\n attributes: {\n [SENTRY_OP]: UI_MOUNT,\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.ui.react.profiler',\n [UI_COMPONENT_NAME]: name,\n },\n });\n }\n\n // If a component mounted, we can finish the mount activity.\n public componentDidMount(): void {\n if (this._mountSpan) {\n this._mountSpan.end();\n }\n }\n\n public shouldComponentUpdate({ updateProps, includeUpdates = true }: ProfilerProps): boolean {\n // Only generate an update span if includeUpdates is true, if there is a valid mountSpan,\n // and if the updateProps have changed. It is ok to not do a deep equality check here as it is expensive.\n // We are just trying to give baseline clues for further investigation.\n if (includeUpdates && this._mountSpan && updateProps !== this.props.updateProps) {\n // See what props have changed between the previous props, and the current props. This is\n // set as data on the span. We just store the prop keys as the values could be potentially very large.\n const changedProps = Object.keys(updateProps).filter(k => updateProps[k] !== this.props.updateProps[k]);\n if (changedProps.length > 0) {\n const now = timestampInSeconds();\n this._updateSpan = withActiveSpan(this._mountSpan, () => {\n return startInactiveSpan({\n name: `<${this.props.name}>`,\n onlyIfParent: true,\n startTime: now,\n attributes: {\n [SENTRY_OP]: UI_UPDATE,\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.ui.react.profiler',\n [UI_COMPONENT_NAME]: this.props.name,\n 'ui.react.changed_props': changedProps,\n },\n });\n });\n }\n }\n\n return true;\n }\n\n public componentDidUpdate(): void {\n if (this._updateSpan) {\n this._updateSpan.end();\n this._updateSpan = undefined;\n }\n }\n\n // If a component is unmounted, we can say it is no longer on the screen.\n // This means we can finish the span representing the component render.\n public componentWillUnmount(): void {\n const endTimestamp = timestampInSeconds();\n const { name, includeRender = true } = this.props;\n\n if (this._mountSpan && includeRender) {\n const startTime = spanToJSON(this._mountSpan).end_timestamp;\n withActiveSpan(this._mountSpan, () => {\n const renderSpan = startInactiveSpan({\n onlyIfParent: true,\n name: `<${name}>`,\n startTime,\n attributes: {\n [SENTRY_OP]: UI_RENDER,\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.ui.react.profiler',\n [UI_COMPONENT_NAME]: name,\n },\n });\n if (renderSpan) {\n // Have to cast to Span because the type of _mountSpan is Span | undefined\n // and not getting narrowed properly\n renderSpan.end(endTimestamp);\n }\n });\n }\n }\n\n public render(): React.ReactNode {\n return this.props.children;\n }\n}\n\n// React.Component default props are defined as static property on the class\nObject.assign(Profiler, {\n defaultProps: {\n disabled: false,\n includeRender: true,\n includeUpdates: true,\n },\n});\n\n/**\n * withProfiler is a higher order component that wraps a\n * component in a {@link Profiler} component. It is recommended that\n * the higher order component be used over the regular {@link Profiler} component.\n *\n * @param WrappedComponent component that is wrapped by Profiler\n * @param options the {@link ProfilerProps} you can pass into the Profiler\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction withProfiler<P extends Record<string, any>>(\n WrappedComponent: React.ComponentType<P>,\n // We do not want to have `updateProps` given in options, it is instead filled through the HOC.\n options?: Pick<Partial<ProfilerProps>, Exclude<keyof ProfilerProps, 'updateProps' | 'children'>>,\n): React.FC<P> {\n const componentDisplayName =\n options?.name || WrappedComponent.displayName || WrappedComponent.name || UNKNOWN_COMPONENT;\n\n const Wrapped: React.FC<P> = (props: P) => (\n <Profiler {...options} name={componentDisplayName} updateProps={props}>\n <WrappedComponent {...props} />\n </Profiler>\n );\n\n Wrapped.displayName = `profiler(${componentDisplayName})`;\n\n // Copy over static methods from Wrapped component to Profiler HOC\n // See: https://reactjs.org/docs/higher-order-components.html#static-methods-must-be-copied-over\n hoistNonReactStatics(Wrapped, WrappedComponent);\n return Wrapped;\n}\n\n/**\n *\n * `useProfiler` is a React hook that profiles a React component.\n *\n * @param name displayName of component being profiled\n */\nfunction useProfiler(\n name: string,\n options: { disabled?: boolean; hasRenderSpan?: boolean } = {\n disabled: false,\n hasRenderSpan: true,\n },\n): void {\n const [mountSpan] = React.useState(() => {\n if (options?.disabled) {\n return undefined;\n }\n\n return startInactiveSpan({\n name: `<${name}>`,\n onlyIfParent: true,\n attributes: {\n [SENTRY_OP]: UI_MOUNT,\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.ui.react.profiler',\n [UI_COMPONENT_NAME]: name,\n },\n });\n });\n\n React.useEffect(() => {\n if (mountSpan) {\n mountSpan.end();\n }\n\n return (): void => {\n if (mountSpan && options.hasRenderSpan) {\n const startTime = spanToJSON(mountSpan).end_timestamp;\n const endTimestamp = timestampInSeconds();\n\n const renderSpan = startInactiveSpan({\n name: `<${name}>`,\n onlyIfParent: true,\n startTime,\n attributes: {\n [SENTRY_OP]: UI_RENDER,\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.ui.react.profiler',\n [UI_COMPONENT_NAME]: name,\n },\n });\n if (renderSpan) {\n // Have to cast to Span because the type of _mountSpan is Span | undefined\n // and not getting narrowed properly\n renderSpan.end(endTimestamp);\n }\n }\n };\n // We only want this to run once.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n}\n\nexport { Profiler, useProfiler, withProfiler };\n"],"names":["startInactiveSpan","SENTRY_OP","UI_MOUNT","SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN","UI_COMPONENT_NAME","timestampInSeconds","withActiveSpan","UI_UPDATE","spanToJSON","UI_RENDER","hoistNonReactStatics"],"mappings":"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"}
@@ -114,12 +114,12 @@ function processResolvedRoutes(resolvedRoutes, parentRoute, currentLocation = nu
114
114
  }
115
115
  const targetSpan = capturedSpan ?? utils.getActiveRootSpan();
116
116
  if (targetSpan) {
117
- const spanJson = core.spanToJSON(targetSpan);
118
- if (spanJson.timestamp) {
117
+ const { end_timestamp, attributes: attributes$1 } = core.spanToJSON(targetSpan);
118
+ if (end_timestamp) {
119
119
  debugBuild.DEBUG_BUILD && core.debug.warn("[React Router] Lazy handler resolved after span ended - skipping update");
120
120
  return;
121
121
  }
122
- const spanOp = spanJson.op;
122
+ const spanOp = attributes$1[attributes.SENTRY_OP];
123
123
  let location = currentLocation;
124
124
  if (!location && !capturedSpan) {
125
125
  if (typeof browser.WINDOW !== "undefined") {
@@ -144,12 +144,11 @@ function processResolvedRoutes(resolvedRoutes, parentRoute, currentLocation = nu
144
144
  }
145
145
  }
146
146
  function updateNavigationSpan(activeRootSpan, location, allRoutes2, forceUpdate = false, matchRoutes) {
147
- const spanJson = core.spanToJSON(activeRootSpan);
148
- const currentName = spanJson.description;
147
+ const { name: currentName, end_timestamp, attributes: attributes$1 } = core.spanToJSON(activeRootSpan);
149
148
  const hasBeenNamed = activeRootSpan?.__sentry_navigation_name_set__;
150
149
  const currentNameHasWildcard = currentName && utils.transactionNameHasWildcard(currentName);
151
150
  const shouldUpdate = !hasBeenNamed || forceUpdate || currentNameHasWildcard;
152
- if (shouldUpdate && !spanJson.timestamp) {
151
+ if (shouldUpdate && !end_timestamp) {
153
152
  const currentBranches = matchRoutes(allRoutes2, location);
154
153
  const [name, source] = utils.resolveRouteNameAndSource(
155
154
  location,
@@ -160,14 +159,16 @@ function updateNavigationSpan(activeRootSpan, location, allRoutes2, forceUpdate
160
159
  _lazyRouteManifest,
161
160
  _enableAsyncRouteHandlers
162
161
  );
163
- const currentSource = spanJson.data?.[core.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE];
162
+ const currentSource = attributes$1[attributes.SENTRY_SEGMENT_NAME_SOURCE];
164
163
  const isImprovement = name && (!currentName || // No current name - always set
165
164
  !hasBeenNamed && (currentSource !== "route" || source === "route") || // Not finalized - allow unless downgrading route→url
166
165
  currentSource !== "route" && source === "route" || // URL → route upgrade
167
166
  currentSource === "route" && source === "route" && currentNameHasWildcard);
168
167
  if (isImprovement) {
169
- activeRootSpan.updateName(name);
170
- activeRootSpan.setAttribute(core.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, source);
168
+ const client = core.getClient();
169
+ const isUnparameterizedStreamedNavigation = source !== "route" && !!client && core.hasSpanStreamingEnabled(client);
170
+ activeRootSpan.updateName(isUnparameterizedStreamedNavigation ? core.NAVIGATION_SPAN_NAME_FALLBACK : name);
171
+ activeRootSpan.setAttribute(attributes.SENTRY_SEGMENT_NAME_SOURCE, source);
171
172
  if (source === "route") {
172
173
  activeRootSpan.setAttribute(attributes.URL_TEMPLATE, name);
173
174
  }
@@ -179,14 +180,14 @@ function updateNavigationSpan(activeRootSpan, location, allRoutes2, forceUpdate
179
180
  }
180
181
  function setupRouterSubscription(router, routes, version, basename, activeRootSpan) {
181
182
  let isInitialPageloadComplete = false;
182
- let hasSeenPageloadSpan = !!activeRootSpan && core.spanToJSON(activeRootSpan).op === "pageload";
183
+ let hasSeenPageloadSpan = !!activeRootSpan && core.spanToJSON(activeRootSpan).attributes[attributes.SENTRY_OP] === "pageload";
183
184
  let hasSeenPopAfterPageload = false;
184
185
  let scheduledNavigationHandler = null;
185
186
  let lastHandledPathname = null;
186
187
  router.subscribe((state) => {
187
188
  if (!isInitialPageloadComplete) {
188
189
  const currentRootSpan = utils.getActiveRootSpan();
189
- const isCurrentlyInPageload = currentRootSpan && core.spanToJSON(currentRootSpan).op === "pageload";
190
+ const isCurrentlyInPageload = currentRootSpan && core.spanToJSON(currentRootSpan).attributes[attributes.SENTRY_OP] === "pageload";
190
191
  if (isCurrentlyInPageload) {
191
192
  hasSeenPageloadSpan = true;
192
193
  } else if (hasSeenPageloadSpan) {
@@ -372,9 +373,11 @@ function createReactRouterV6CompatibleTracingIntegration(options, version) {
372
373
  const initPathName = browser.WINDOW.location?.pathname;
373
374
  if (instrumentPageLoad && initPathName) {
374
375
  browser.startBrowserTracingPageLoadSpan(client, {
375
- name: initPathName,
376
+ // With span streaming, span names have to be low cardinality. The route is only resolved
377
+ // once the router renders, which updates the span name then.
378
+ name: core.hasSpanStreamingEnabled(client) ? core.PAGELOAD_SPAN_NAME_FALLBACK : initPathName,
376
379
  attributes: {
377
- [core.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: "url",
380
+ [attributes.SENTRY_SEGMENT_NAME_SOURCE]: "url",
378
381
  [core.SEMANTIC_ATTRIBUTE_SENTRY_OP]: "pageload",
379
382
  [core.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: `auto.pageload.react.reactrouter${version ? `_v${version}` : ""}`
380
383
  }
@@ -462,8 +465,8 @@ function wrapPatchRoutesOnNavigation(opts, isMemoryRouter = false, capturedSpan)
462
465
  }
463
466
  }
464
467
  const spanJson = activeRootSpan ? core.spanToJSON(activeRootSpan) : void 0;
465
- if (targetPath && activeRootSpan && spanJson && !spanJson.timestamp && // Span hasn't ended yet
466
- spanJson.op === "navigation") {
468
+ if (targetPath && activeRootSpan && spanJson && !spanJson.end_timestamp && // Span hasn't ended yet
469
+ spanJson.attributes[attributes.SENTRY_OP] === "navigation") {
467
470
  updateNavigationSpan(
468
471
  activeRootSpan,
469
472
  { pathname: targetPath, search: "", hash: "", state: null, key: "default" },
@@ -488,8 +491,8 @@ function wrapPatchRoutesOnNavigation(opts, isMemoryRouter = false, capturedSpan)
488
491
  }
489
492
  }
490
493
  const spanJson = activeRootSpan ? core.spanToJSON(activeRootSpan) : void 0;
491
- if (activeRootSpan && spanJson && !spanJson.timestamp && // Span hasn't ended yet
492
- spanJson.op === "navigation") {
494
+ if (activeRootSpan && spanJson && !spanJson.end_timestamp && // Span hasn't ended yet
495
+ spanJson.attributes[attributes.SENTRY_OP] === "navigation") {
493
496
  const pathname = targetPath;
494
497
  if (pathname) {
495
498
  updateNavigationSpan(
@@ -518,7 +521,7 @@ function handleNavigation(opts) {
518
521
  return;
519
522
  }
520
523
  const activeRootSpan = utils.getActiveRootSpan();
521
- if (activeRootSpan && core.spanToJSON(activeRootSpan).op === "pageload" && navigationType === "POP") {
524
+ if (activeRootSpan && core.spanToJSON(activeRootSpan).attributes[attributes.SENTRY_OP] === "pageload" && navigationType === "POP") {
522
525
  return;
523
526
  }
524
527
  if ((navigationType === "PUSH" || navigationType === "POP") && branches) {
@@ -533,7 +536,7 @@ function handleNavigation(opts) {
533
536
  );
534
537
  const locationKey = computeLocationKey(location);
535
538
  const trackedNav = activeNavigationSpans.get(client);
536
- const trackedSpanHasEnded = trackedNav && !trackedNav.isPlaceholder ? !!core.spanToJSON(trackedNav.span).timestamp : false;
539
+ const trackedSpanHasEnded = trackedNav && !trackedNav.isPlaceholder ? !!core.spanToJSON(trackedNav.span).end_timestamp : false;
537
540
  const { skip, shouldUpdate } = shouldSkipNavigation(trackedNav, locationKey, name, trackedSpanHasEnded);
538
541
  if (skip) {
539
542
  if (shouldUpdate && trackedNav) {
@@ -544,8 +547,9 @@ function handleNavigation(opts) {
544
547
  `[Tracing] Updated placeholder navigation name from "${oldName}" to "${name}" (will apply to real span)`
545
548
  );
546
549
  } else {
547
- trackedNav.span.updateName(name);
548
- trackedNav.span.setAttribute(core.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, source);
550
+ const isUnparameterizedStreamedNavigation = source !== "route" && core.hasSpanStreamingEnabled(client);
551
+ trackedNav.span.updateName(isUnparameterizedStreamedNavigation ? core.NAVIGATION_SPAN_NAME_FALLBACK : name);
552
+ trackedNav.span.setAttribute(attributes.SENTRY_SEGMENT_NAME_SOURCE, source);
549
553
  if (source === "route") {
550
554
  trackedNav.span.setAttribute(attributes.URL_TEMPLATE, name);
551
555
  }
@@ -571,10 +575,11 @@ function handleNavigation(opts) {
571
575
  let navigationSpan;
572
576
  try {
573
577
  navigationSpan = browser.startBrowserTracingNavigationSpan(client, {
574
- name: placeholderEntry.routeName,
575
- // Use placeholder's routeName in case it was updated
578
+ // Use placeholder's routeName in case it was updated. With span streaming, span names have to
579
+ // be low cardinality, so we can't fall back to the URL.
580
+ name: source === "route" || !core.hasSpanStreamingEnabled(client) ? placeholderEntry.routeName : core.NAVIGATION_SPAN_NAME_FALLBACK,
576
581
  attributes: {
577
- [core.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: source,
582
+ [attributes.SENTRY_SEGMENT_NAME_SOURCE]: source,
578
583
  [core.SEMANTIC_ATTRIBUTE_SENTRY_OP]: "navigation",
579
584
  [core.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: `auto.navigation.react.reactrouter${version ? `_v${version}` : ""}`,
580
585
  ...source === "route" && { [attributes.URL_TEMPLATE]: placeholderEntry.routeName }
@@ -649,8 +654,10 @@ function updatePageloadTransaction({
649
654
  );
650
655
  core.getCurrentScope().setTransactionName(name || "/");
651
656
  if (activeRootSpan) {
652
- activeRootSpan.updateName(name);
653
- activeRootSpan.setAttribute(core.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, source);
657
+ const client = core.getClient();
658
+ const isUnparameterizedStreamedPageload = source !== "route" && !!client && core.hasSpanStreamingEnabled(client);
659
+ activeRootSpan.updateName(isUnparameterizedStreamedPageload ? core.PAGELOAD_SPAN_NAME_FALLBACK : name);
660
+ activeRootSpan.setAttribute(attributes.SENTRY_SEGMENT_NAME_SOURCE, source);
654
661
  if (source === "route") {
655
662
  activeRootSpan.setAttribute(attributes.URL_TEMPLATE, name);
656
663
  }
@@ -678,7 +685,7 @@ function shouldUpdateWildcardSpanName(currentName, currentSource, newName, newSo
678
685
  }
679
686
  function tryUpdateSpanNameBeforeEnd(span, spanJson, currentName, location, routes, basename, spanType, allRoutes2) {
680
687
  try {
681
- const currentSource = spanJson.data?.[core.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE];
688
+ const currentSource = spanJson.attributes[attributes.SENTRY_SEGMENT_NAME_SOURCE];
682
689
  if (currentSource === "route" && currentName && !utils.transactionNameHasWildcard(currentName)) {
683
690
  return;
684
691
  }
@@ -698,10 +705,13 @@ function tryUpdateSpanNameBeforeEnd(span, spanJson, currentName, location, route
698
705
  _enableAsyncRouteHandlers
699
706
  );
700
707
  const isImprovement = shouldUpdateWildcardSpanName(currentName, currentSource, name, source, true);
701
- const spanNotEnded = spanType === "pageload" || !spanJson.timestamp;
708
+ const spanNotEnded = spanType === "pageload" || !spanJson.end_timestamp;
702
709
  if (isImprovement && spanNotEnded) {
703
- span.updateName(name);
704
- span.setAttribute(core.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, source);
710
+ const client = core.getClient();
711
+ const isUnparameterizedStreamedSpan = source !== "route" && !!client && core.hasSpanStreamingEnabled(client);
712
+ const fallbackName = spanType === "pageload" ? core.PAGELOAD_SPAN_NAME_FALLBACK : core.NAVIGATION_SPAN_NAME_FALLBACK;
713
+ span.updateName(isUnparameterizedStreamedSpan ? fallbackName : name);
714
+ span.setAttribute(attributes.SENTRY_SEGMENT_NAME_SOURCE, source);
705
715
  if (source === "route") {
706
716
  span.setAttribute(attributes.URL_TEMPLATE, name);
707
717
  }
@@ -725,8 +735,8 @@ function patchSpanEnd(span, location, routes, basename, spanType) {
725
735
  endCalled = true;
726
736
  const endTimestamp = args.length > 0 ? args[0] : Date.now() / 1e3;
727
737
  const spanJson = core.spanToJSON(span);
728
- const currentName = spanJson.description;
729
- const currentSource = spanJson.data?.[core.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE];
738
+ const currentName = spanJson.name;
739
+ const currentSource = spanJson.attributes[attributes.SENTRY_SEGMENT_NAME_SOURCE];
730
740
  const cleanupNavigationSpan = () => {
731
741
  const client = core.getClient();
732
742
  if (client && spanType === "navigation") {
@@ -761,7 +771,7 @@ function patchSpanEnd(span, location, routes, basename, spanType) {
761
771
  tryUpdateSpanNameBeforeEnd(
762
772
  span,
763
773
  updatedSpanJson,
764
- updatedSpanJson.description,
774
+ updatedSpanJson.name,
765
775
  location,
766
776
  routes,
767
777
  basename,