@sentry/react 10.53.1 → 10.55.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. package/build/cjs/constants.js +3 -5
  2. package/build/cjs/constants.js.map +1 -1
  3. package/build/cjs/debug-build.js +0 -5
  4. package/build/cjs/debug-build.js.map +1 -1
  5. package/build/cjs/error.js +12 -72
  6. package/build/cjs/error.js.map +1 -1
  7. package/build/cjs/errorboundary.js +22 -77
  8. package/build/cjs/errorboundary.js.map +1 -1
  9. package/build/cjs/hoist-non-react-statics.js +16 -84
  10. package/build/cjs/hoist-non-react-statics.js.map +1 -1
  11. package/build/cjs/isSyntheticEvent.js +10 -0
  12. package/build/cjs/isSyntheticEvent.js.map +1 -0
  13. package/build/cjs/profiler.js +35 -110
  14. package/build/cjs/profiler.js.map +1 -1
  15. package/build/cjs/reactrouter-compat-utils/instrumentation.js +219 -690
  16. package/build/cjs/reactrouter-compat-utils/instrumentation.js.map +1 -1
  17. package/build/cjs/reactrouter-compat-utils/lazy-routes.js +24 -85
  18. package/build/cjs/reactrouter-compat-utils/lazy-routes.js.map +1 -1
  19. package/build/cjs/reactrouter-compat-utils/route-manifest.js +17 -95
  20. package/build/cjs/reactrouter-compat-utils/route-manifest.js.map +1 -1
  21. package/build/cjs/reactrouter-compat-utils/utils.js +48 -190
  22. package/build/cjs/reactrouter-compat-utils/utils.js.map +1 -1
  23. package/build/cjs/reactrouter.js +33 -113
  24. package/build/cjs/reactrouter.js.map +1 -1
  25. package/build/cjs/reactrouterv3.js +27 -59
  26. package/build/cjs/reactrouterv3.js.map +1 -1
  27. package/build/cjs/reactrouterv6.js +8 -41
  28. package/build/cjs/reactrouterv6.js.map +1 -1
  29. package/build/cjs/reactrouterv7.js +8 -41
  30. package/build/cjs/reactrouterv7.js.map +1 -1
  31. package/build/cjs/redux.js +60 -88
  32. package/build/cjs/redux.js.map +1 -1
  33. package/build/cjs/sdk.js +13 -8
  34. package/build/cjs/sdk.js.map +1 -1
  35. package/build/cjs/tanstackrouter.js +24 -64
  36. package/build/cjs/tanstackrouter.js.map +1 -1
  37. package/build/esm/constants.js +3 -5
  38. package/build/esm/constants.js.map +1 -1
  39. package/build/esm/debug-build.js +0 -5
  40. package/build/esm/debug-build.js.map +1 -1
  41. package/build/esm/error.js +12 -72
  42. package/build/esm/error.js.map +1 -1
  43. package/build/esm/errorboundary.js +22 -77
  44. package/build/esm/errorboundary.js.map +1 -1
  45. package/build/esm/hoist-non-react-statics.js +16 -84
  46. package/build/esm/hoist-non-react-statics.js.map +1 -1
  47. package/build/esm/isSyntheticEvent.js +8 -0
  48. package/build/esm/isSyntheticEvent.js.map +1 -0
  49. package/build/esm/package.json +1 -1
  50. package/build/esm/profiler.js +35 -110
  51. package/build/esm/profiler.js.map +1 -1
  52. package/build/esm/reactrouter-compat-utils/instrumentation.js +219 -690
  53. package/build/esm/reactrouter-compat-utils/instrumentation.js.map +1 -1
  54. package/build/esm/reactrouter-compat-utils/lazy-routes.js +24 -85
  55. package/build/esm/reactrouter-compat-utils/lazy-routes.js.map +1 -1
  56. package/build/esm/reactrouter-compat-utils/route-manifest.js +17 -95
  57. package/build/esm/reactrouter-compat-utils/route-manifest.js.map +1 -1
  58. package/build/esm/reactrouter-compat-utils/utils.js +48 -190
  59. package/build/esm/reactrouter-compat-utils/utils.js.map +1 -1
  60. package/build/esm/reactrouter.js +33 -113
  61. package/build/esm/reactrouter.js.map +1 -1
  62. package/build/esm/reactrouterv3.js +27 -59
  63. package/build/esm/reactrouterv3.js.map +1 -1
  64. package/build/esm/reactrouterv6.js +8 -41
  65. package/build/esm/reactrouterv6.js.map +1 -1
  66. package/build/esm/reactrouterv7.js +8 -41
  67. package/build/esm/reactrouterv7.js.map +1 -1
  68. package/build/esm/redux.js +60 -88
  69. package/build/esm/redux.js.map +1 -1
  70. package/build/esm/sdk.js +15 -10
  71. package/build/esm/sdk.js.map +1 -1
  72. package/build/esm/tanstackrouter.js +24 -64
  73. package/build/esm/tanstackrouter.js.map +1 -1
  74. package/build/types/isSyntheticEvent.d.ts +10 -0
  75. package/build/types/isSyntheticEvent.d.ts.map +1 -0
  76. package/build/types/sdk.d.ts.map +1 -1
  77. package/build/types-ts3.8/isSyntheticEvent.d.ts +10 -0
  78. package/package.json +3 -3
@@ -8,52 +8,26 @@ const hoistNonReactStatics = require('../hoist-non-react-statics.js');
8
8
  const lazyRoutes = require('./lazy-routes.js');
9
9
  const utils = require('./utils.js');
10
10
 
11
- /* eslint-disable max-lines */
12
- // Inspired from Donnie McNeal's solution:
13
- // https://gist.github.com/wontondon/e8c4bdf2888875e4c755712e99279536
14
-
15
-
16
11
  let _useEffect;
17
12
  let _useLocation;
18
13
  let _useNavigationType;
19
14
  let _createRoutesFromChildren;
20
15
  let _matchRoutes;
21
-
22
16
  let _enableAsyncRouteHandlers = false;
23
- let _lazyRouteTimeout = 3000;
17
+ let _lazyRouteTimeout = 3e3;
24
18
  let _lazyRouteManifest;
25
- let _basename = '';
26
-
27
- const CLIENTS_WITH_INSTRUMENT_NAVIGATION = new WeakSet();
28
-
29
- // Prevents duplicate spans when router.subscribe fires multiple times
30
- const activeNavigationSpans = new WeakMap
31
-
32
- ();
33
-
34
- // Exported for testing only
35
- const allRoutes = new Set();
36
-
37
- // Tracks lazy route loads to wait before finalizing span names
38
- const pendingLazyRouteLoads = new WeakMap();
39
-
40
- // Tracks deferred lazy route promises that can be resolved when patchRoutesOnNavigation is called
41
- const deferredLazyRouteResolvers = new WeakMap();
42
-
43
- /**
44
- * Schedules a callback using requestAnimationFrame when available (browser),
45
- * or falls back to setTimeout for SSR environments (Node.js, createMemoryRouter tests).
46
- */
19
+ let _basename = "";
20
+ const CLIENTS_WITH_INSTRUMENT_NAVIGATION = /* @__PURE__ */ new WeakSet();
21
+ const activeNavigationSpans = /* @__PURE__ */ new WeakMap();
22
+ const allRoutes = /* @__PURE__ */ new Set();
23
+ const pendingLazyRouteLoads = /* @__PURE__ */ new WeakMap();
24
+ const deferredLazyRouteResolvers = /* @__PURE__ */ new WeakMap();
47
25
  function scheduleCallback(callback) {
48
26
  if (browser.WINDOW?.requestAnimationFrame) {
49
27
  return browser.WINDOW.requestAnimationFrame(callback);
50
28
  }
51
- return setTimeout(callback, 0) ;
29
+ return setTimeout(callback, 0);
52
30
  }
53
-
54
- /**
55
- * Cancels a scheduled callback, handling both RAF (browser) and timeout (SSR) IDs.
56
- */
57
31
  function cancelScheduledCallback(id) {
58
32
  if (browser.WINDOW?.cancelAnimationFrame) {
59
33
  browser.WINDOW.cancelAnimationFrame(id);
@@ -61,103 +35,48 @@ function cancelScheduledCallback(id) {
61
35
  clearTimeout(id);
62
36
  }
63
37
  }
64
-
65
- /**
66
- * Computes location key for duplicate detection. Normalizes undefined/null to empty strings.
67
- * Exported for testing.
68
- */
69
38
  function computeLocationKey(location) {
70
- return `${location.pathname}${location.search || ''}${location.hash || ''}`;
39
+ return `${location.pathname}${location.search || ""}${location.hash || ""}`;
71
40
  }
72
-
73
- /**
74
- * Checks if a route name is parameterized (contains route parameters like :id or wildcards like *)
75
- * vs a raw URL path.
76
- */
77
41
  function isParameterizedRoute(routeName) {
78
- return routeName.includes(':') || routeName.includes('*');
42
+ return routeName.includes(":") || routeName.includes("*");
79
43
  }
80
-
81
- /**
82
- * Determines if a navigation should be skipped as a duplicate, and if an existing span should be updated.
83
- * Exported for testing.
84
- *
85
- * @returns An object with:
86
- * - skip: boolean - Whether to skip creating a new span
87
- * - shouldUpdate: boolean - Whether to update the existing span name (wildcard upgrade)
88
- */
89
- function shouldSkipNavigation(
90
- trackedNav
91
-
92
- ,
93
- locationKey,
94
- proposedName,
95
- spanHasEnded,
96
- ) {
44
+ function shouldSkipNavigation(trackedNav, locationKey, proposedName, spanHasEnded) {
97
45
  if (!trackedNav) {
98
46
  return { skip: false, shouldUpdate: false };
99
47
  }
100
-
101
- // Check if this is a duplicate navigation (same location)
102
- // 1. If it's a placeholder, it's always a duplicate (we're waiting for the real one)
103
- // 2. If it's a real span, it's a duplicate only if it hasn't ended yet
104
48
  const isDuplicate = trackedNav.locationKey === locationKey && (trackedNav.isPlaceholder || !spanHasEnded);
105
-
106
49
  if (isDuplicate) {
107
- // Check if we should update the span name with a better route
108
- // Allow updates if:
109
- // 1. Current has wildcard and new doesn't (wildcard → parameterized upgrade)
110
- // 2. Current is raw path and new is parameterized (raw → parameterized upgrade)
111
- // 3. New name is different and more specific (longer, indicating nested routes resolved)
112
50
  const currentHasWildcard = !!trackedNav.routeName && utils.transactionNameHasWildcard(trackedNav.routeName);
113
51
  const proposedHasWildcard = utils.transactionNameHasWildcard(proposedName);
114
52
  const currentIsParameterized = !!trackedNav.routeName && isParameterizedRoute(trackedNav.routeName);
115
53
  const proposedIsParameterized = isParameterizedRoute(proposedName);
116
-
117
54
  const isWildcardUpgrade = currentHasWildcard && !proposedHasWildcard;
118
55
  const isRawToParameterized = !currentIsParameterized && proposedIsParameterized;
119
- const isMoreSpecific =
120
- proposedName !== trackedNav.routeName &&
121
- proposedName.length > (trackedNav.routeName?.length || 0) &&
122
- !proposedHasWildcard;
123
-
56
+ const isMoreSpecific = proposedName !== trackedNav.routeName && proposedName.length > (trackedNav.routeName?.length || 0) && !proposedHasWildcard;
124
57
  const shouldUpdate = !!(trackedNav.routeName && (isWildcardUpgrade || isRawToParameterized || isMoreSpecific));
125
-
126
58
  return { skip: true, shouldUpdate };
127
59
  }
128
-
129
60
  return { skip: false, shouldUpdate: false };
130
61
  }
131
-
132
62
  function addResolvedRoutesToParent(resolvedRoutes, parentRoute) {
133
63
  const existingChildren = parentRoute.children || [];
134
-
135
64
  const newRoutes = resolvedRoutes.filter(
136
- newRoute =>
137
- !existingChildren.some(
138
- existing =>
139
- existing === newRoute ||
140
- (newRoute.path && existing.path === newRoute.path) ||
141
- (newRoute.id && existing.id === newRoute.id),
142
- ),
65
+ (newRoute) => !existingChildren.some(
66
+ (existing) => existing === newRoute || newRoute.path && existing.path === newRoute.path || newRoute.id && existing.id === newRoute.id
67
+ )
143
68
  );
144
-
145
69
  if (newRoutes.length > 0) {
146
70
  parentRoute.children = [...existingChildren, ...newRoutes];
147
71
  }
148
72
  }
149
-
150
- /** Registers a pending lazy route load promise for a span. */
151
73
  function trackLazyRouteLoad(span, promise) {
152
74
  let promises = pendingLazyRouteLoads.get(span);
153
75
  if (!promises) {
154
- promises = new Set();
76
+ promises = /* @__PURE__ */ new Set();
155
77
  pendingLazyRouteLoads.set(span, promises);
156
78
  }
157
79
  promises.add(promise);
158
-
159
- // Clean up when promise resolves/rejects
160
- // oxlint-disable-next-line typescript/no-floating-promises
161
80
  promise.finally(() => {
162
81
  const currentPromises = pendingLazyRouteLoads.get(span);
163
82
  if (currentPromises) {
@@ -165,192 +84,122 @@ function trackLazyRouteLoad(span, promise) {
165
84
  }
166
85
  });
167
86
  }
168
-
169
- /**
170
- * Creates a deferred promise for a span that will be resolved when patchRoutesOnNavigation is called.
171
- * This ensures that patchedEnd waits for patchRoutesOnNavigation to be called before ending the span.
172
- */
173
87
  function createDeferredLazyRoutePromise(span) {
174
- const deferredPromise = new Promise(resolve => {
88
+ const deferredPromise = new Promise((resolve) => {
175
89
  deferredLazyRouteResolvers.set(span, resolve);
176
90
  });
177
-
178
91
  trackLazyRouteLoad(span, deferredPromise);
179
92
  }
180
-
181
- /**
182
- * Resolves the deferred lazy route promise for a span.
183
- * Called when patchRoutesOnNavigation is invoked.
184
- */
185
93
  function resolveDeferredLazyRoutePromise(span) {
186
94
  const resolver = deferredLazyRouteResolvers.get(span);
187
95
  if (resolver) {
188
96
  resolver();
189
97
  deferredLazyRouteResolvers.delete(span);
190
- // Clear the flag so patchSpanEnd doesn't wait unnecessarily for routes that have already loaded
191
- if ((span ).__sentry_may_have_lazy_routes__) {
192
- (span ).__sentry_may_have_lazy_routes__ = false;
98
+ if (span.__sentry_may_have_lazy_routes__) {
99
+ span.__sentry_may_have_lazy_routes__ = false;
193
100
  }
194
101
  }
195
102
  }
196
-
197
- /**
198
- * Processes resolved routes by adding them to allRoutes and checking for nested async handlers.
199
- * When capturedSpan is provided, updates that specific span instead of the current active span.
200
- * This prevents race conditions where a lazy handler resolves after the user has navigated away.
201
- */
202
- function processResolvedRoutes(
203
- resolvedRoutes,
204
- parentRoute,
205
- currentLocation = null,
206
- capturedSpan,
207
- ) {
208
- resolvedRoutes.forEach(child => {
103
+ function processResolvedRoutes(resolvedRoutes, parentRoute, currentLocation = null, capturedSpan) {
104
+ resolvedRoutes.forEach((child) => {
209
105
  allRoutes.add(child);
210
- // Only check for async handlers if the feature is enabled
211
106
  if (_enableAsyncRouteHandlers) {
212
107
  lazyRoutes.checkRouteForAsyncHandler(child, processResolvedRoutes);
213
108
  }
214
109
  });
215
-
216
110
  if (parentRoute) {
217
- // If a parent route is provided, add the resolved routes as children to the parent route
218
111
  addResolvedRoutesToParent(resolvedRoutes, parentRoute);
219
112
  }
220
-
221
- // Use captured span if provided, otherwise fall back to current active span
222
113
  const targetSpan = capturedSpan ?? utils.getActiveRootSpan();
223
114
  if (targetSpan) {
224
115
  const spanJson = core.spanToJSON(targetSpan);
225
-
226
- // Skip update if span has already ended (timestamp is set when span.end() is called)
227
116
  if (spanJson.timestamp) {
228
- debugBuild.DEBUG_BUILD && core.debug.warn('[React Router] Lazy handler resolved after span ended - skipping update');
117
+ debugBuild.DEBUG_BUILD && core.debug.warn("[React Router] Lazy handler resolved after span ended - skipping update");
229
118
  return;
230
119
  }
231
-
232
120
  const spanOp = spanJson.op;
233
-
234
- // Use captured location for route matching (ensures we match against the correct route)
235
- // Fall back to window.location only if no captured location and no captured span
236
- // (i.e., this is not from an async handler)
237
121
  let location = currentLocation;
238
122
  if (!location && !capturedSpan) {
239
- if (typeof browser.WINDOW !== 'undefined') {
123
+ if (typeof browser.WINDOW !== "undefined") {
240
124
  const globalLocation = browser.WINDOW.location;
241
125
  if (globalLocation?.pathname) {
242
126
  location = { pathname: globalLocation.pathname };
243
127
  }
244
128
  }
245
129
  }
246
-
247
130
  if (location) {
248
- if (spanOp === 'pageload') {
249
- // Re-run the pageload transaction update with the newly loaded routes
131
+ if (spanOp === "pageload") {
250
132
  updatePageloadTransaction({
251
133
  activeRootSpan: targetSpan,
252
134
  location: { pathname: location.pathname },
253
135
  routes: Array.from(allRoutes),
254
- allRoutes: Array.from(allRoutes),
136
+ allRoutes: Array.from(allRoutes)
255
137
  });
256
- } else if (spanOp === 'navigation') {
257
- // For navigation spans, update the name with the newly loaded routes
138
+ } else if (spanOp === "navigation") {
258
139
  updateNavigationSpan(targetSpan, location, Array.from(allRoutes), false, _matchRoutes);
259
140
  }
260
141
  }
261
142
  }
262
143
  }
263
-
264
- /**
265
- * Updates a navigation span with the correct route name after lazy routes have been loaded.
266
- */
267
- function updateNavigationSpan(
268
- activeRootSpan,
269
- location,
270
- allRoutes,
271
- forceUpdate = false,
272
- matchRoutes,
273
- ) {
144
+ function updateNavigationSpan(activeRootSpan, location, allRoutes2, forceUpdate = false, matchRoutes) {
274
145
  const spanJson = core.spanToJSON(activeRootSpan);
275
146
  const currentName = spanJson.description;
276
-
277
- const hasBeenNamed = (activeRootSpan )?.__sentry_navigation_name_set__;
147
+ const hasBeenNamed = activeRootSpan?.__sentry_navigation_name_set__;
278
148
  const currentNameHasWildcard = currentName && utils.transactionNameHasWildcard(currentName);
279
149
  const shouldUpdate = !hasBeenNamed || forceUpdate || currentNameHasWildcard;
280
-
281
150
  if (shouldUpdate && !spanJson.timestamp) {
282
- const currentBranches = matchRoutes(allRoutes, location);
151
+ const currentBranches = matchRoutes(allRoutes2, location);
283
152
  const [name, source] = utils.resolveRouteNameAndSource(
284
153
  location,
285
- allRoutes,
286
- allRoutes,
287
- (currentBranches ) || [],
154
+ allRoutes2,
155
+ allRoutes2,
156
+ currentBranches || [],
288
157
  _basename,
289
158
  _lazyRouteManifest,
290
- _enableAsyncRouteHandlers,
159
+ _enableAsyncRouteHandlers
291
160
  );
292
-
293
161
  const currentSource = spanJson.data?.[core.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE];
294
- const isImprovement =
295
- name &&
296
- (!currentName || // No current name - always set
297
- (!hasBeenNamed && (currentSource !== 'route' || source === 'route')) || // Not finalized - allow unless downgrading route→url
298
- (currentSource !== 'route' && source === 'route') || // URL → route upgrade
299
- (currentSource === 'route' && source === 'route' && currentNameHasWildcard)); // Route → better route (only if current has wildcard)
162
+ const isImprovement = name && (!currentName || // No current name - always set
163
+ !hasBeenNamed && (currentSource !== "route" || source === "route") || // Not finalized - allow unless downgrading route→url
164
+ currentSource !== "route" && source === "route" || // URL route upgrade
165
+ currentSource === "route" && source === "route" && currentNameHasWildcard);
300
166
  if (isImprovement) {
301
167
  activeRootSpan.updateName(name);
302
168
  activeRootSpan.setAttribute(core.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, source);
303
-
304
- // Only mark as finalized for non-wildcard route names (allows URL→route upgrades).
305
- if (!utils.transactionNameHasWildcard(name) && source === 'route') {
169
+ if (!utils.transactionNameHasWildcard(name) && source === "route") {
306
170
  core.addNonEnumerableProperty(
307
- activeRootSpan ,
308
- '__sentry_navigation_name_set__',
309
- true,
171
+ activeRootSpan,
172
+ "__sentry_navigation_name_set__",
173
+ true
310
174
  );
311
175
  }
312
176
  }
313
177
  }
314
178
  }
315
-
316
- function setupRouterSubscription(
317
- router,
318
- routes,
319
- version,
320
- basename,
321
- activeRootSpan,
322
- ) {
179
+ function setupRouterSubscription(router, routes, version, basename, activeRootSpan) {
323
180
  let isInitialPageloadComplete = false;
324
- let hasSeenPageloadSpan = !!activeRootSpan && core.spanToJSON(activeRootSpan).op === 'pageload';
181
+ let hasSeenPageloadSpan = !!activeRootSpan && core.spanToJSON(activeRootSpan).op === "pageload";
325
182
  let hasSeenPopAfterPageload = false;
326
183
  let scheduledNavigationHandler = null;
327
184
  let lastHandledPathname = null;
328
-
329
185
  router.subscribe((state) => {
330
186
  if (!isInitialPageloadComplete) {
331
187
  const currentRootSpan = utils.getActiveRootSpan();
332
- const isCurrentlyInPageload = currentRootSpan && core.spanToJSON(currentRootSpan).op === 'pageload';
333
-
188
+ const isCurrentlyInPageload = currentRootSpan && core.spanToJSON(currentRootSpan).op === "pageload";
334
189
  if (isCurrentlyInPageload) {
335
190
  hasSeenPageloadSpan = true;
336
191
  } else if (hasSeenPageloadSpan) {
337
- if (state.historyAction === 'POP' && !hasSeenPopAfterPageload) {
192
+ if (state.historyAction === "POP" && !hasSeenPopAfterPageload) {
338
193
  hasSeenPopAfterPageload = true;
339
194
  } else {
340
195
  isInitialPageloadComplete = true;
341
196
  }
342
197
  }
343
198
  }
344
-
345
- const shouldHandleNavigation =
346
- state.historyAction === 'PUSH' || (state.historyAction === 'POP' && isInitialPageloadComplete);
347
-
199
+ const shouldHandleNavigation = state.historyAction === "PUSH" || state.historyAction === "POP" && isInitialPageloadComplete;
348
200
  if (shouldHandleNavigation) {
349
- // Include search and hash to allow query/hash-only navigations
350
- // Use computeLocationKey() to ensure undefined/null values are normalized to empty strings
351
201
  const currentLocationKey = computeLocationKey(state.location);
352
202
  const navigationHandler = () => {
353
- // Prevent multiple calls for the same location within the same navigation cycle
354
203
  if (lastHandledPathname === currentLocationKey) {
355
204
  return;
356
205
  }
@@ -362,207 +211,119 @@ function setupRouterSubscription(
362
211
  navigationType: state.historyAction,
363
212
  version,
364
213
  basename,
365
- allRoutes: Array.from(allRoutes),
214
+ allRoutes: Array.from(allRoutes)
366
215
  });
367
216
  };
368
-
369
- if (state.navigation.state !== 'idle') {
370
- // Navigation in progress - reset if location changed
217
+ if (state.navigation.state !== "idle") {
371
218
  if (lastHandledPathname !== currentLocationKey) {
372
219
  lastHandledPathname = null;
373
220
  }
374
- // Cancel any previously scheduled handler to avoid duplicates
375
221
  if (scheduledNavigationHandler !== null) {
376
222
  cancelScheduledCallback(scheduledNavigationHandler);
377
223
  }
378
224
  scheduledNavigationHandler = scheduleCallback(navigationHandler);
379
225
  } else {
380
- // Navigation completed - cancel scheduled handler if any, then call immediately
381
226
  if (scheduledNavigationHandler !== null) {
382
227
  cancelScheduledCallback(scheduledNavigationHandler);
383
228
  scheduledNavigationHandler = null;
384
229
  }
385
230
  navigationHandler();
386
- // Don't reset - next navigation cycle resets to prevent duplicates within same cycle.
387
231
  }
388
232
  }
389
233
  });
390
234
  }
391
-
392
- /**
393
- * Creates a wrapCreateBrowserRouter function that can be used with all React Router v6 compatible versions.
394
- */
395
- function createV6CompatibleWrapCreateBrowserRouter
396
-
397
- (
398
- createRouterFunction,
399
- version,
400
- ) {
235
+ function createV6CompatibleWrapCreateBrowserRouter(createRouterFunction, version) {
401
236
  if (!_useEffect || !_useLocation || !_useNavigationType || !_matchRoutes) {
402
- debugBuild.DEBUG_BUILD &&
403
- core.debug.warn(
404
- `reactRouterV${version}Instrumentation was unable to wrap the \`createRouter\` function because of one or more missing parameters.`,
405
- );
406
-
237
+ debugBuild.DEBUG_BUILD && core.debug.warn(
238
+ `reactRouterV${version}Instrumentation was unable to wrap the \`createRouter\` function because of one or more missing parameters.`
239
+ );
407
240
  return createRouterFunction;
408
241
  }
409
-
410
- return function (routes, opts) {
242
+ return function(routes, opts) {
411
243
  addRoutesToAllRoutes(routes);
412
-
413
244
  if (_enableAsyncRouteHandlers) {
414
245
  for (const route of routes) {
415
246
  lazyRoutes.checkRouteForAsyncHandler(route, processResolvedRoutes);
416
247
  }
417
248
  }
418
-
419
- // Capture the active span BEFORE creating the router.
420
- // This is important because the span might end (due to idle timeout) before
421
- // patchRoutesOnNavigation is called by React Router.
422
249
  const activeRootSpan = utils.getActiveRootSpan();
423
-
424
- // If patchRoutesOnNavigation is provided and we have an active span,
425
- // mark the span as having potential lazy routes and create a deferred promise.
426
- const hasPatchRoutesOnNavigation =
427
- opts && 'patchRoutesOnNavigation' in opts && typeof opts.patchRoutesOnNavigation === 'function';
250
+ const hasPatchRoutesOnNavigation = opts && "patchRoutesOnNavigation" in opts && typeof opts.patchRoutesOnNavigation === "function";
428
251
  if (hasPatchRoutesOnNavigation && activeRootSpan) {
429
- // Mark the span as potentially having lazy routes
430
252
  core.addNonEnumerableProperty(
431
- activeRootSpan ,
432
- '__sentry_may_have_lazy_routes__',
433
- true,
253
+ activeRootSpan,
254
+ "__sentry_may_have_lazy_routes__",
255
+ true
434
256
  );
435
257
  createDeferredLazyRoutePromise(activeRootSpan);
436
258
  }
437
-
438
- // Pass the captured span to wrapPatchRoutesOnNavigation so it uses the same span
439
- // even if the span has ended by the time patchRoutesOnNavigation is called.
440
259
  const wrappedOpts = wrapPatchRoutesOnNavigation(opts, false, activeRootSpan);
441
260
  const router = createRouterFunction(routes, wrappedOpts);
442
261
  const basename = opts?.basename;
443
-
444
- if (router.state.historyAction === 'POP' && activeRootSpan) {
262
+ if (router.state.historyAction === "POP" && activeRootSpan) {
445
263
  updatePageloadTransaction({
446
264
  activeRootSpan,
447
265
  location: router.state.location,
448
266
  routes,
449
267
  basename,
450
- allRoutes: Array.from(allRoutes),
268
+ allRoutes: Array.from(allRoutes)
451
269
  });
452
270
  }
453
-
454
- // Store basename for use in updateNavigationSpan
455
- _basename = basename || '';
456
-
271
+ _basename = basename || "";
457
272
  setupRouterSubscription(router, routes, version, basename, activeRootSpan);
458
-
459
273
  return router;
460
274
  };
461
275
  }
462
-
463
- /**
464
- * Creates a wrapCreateMemoryRouter function that can be used with all React Router v6 compatible versions.
465
- */
466
- function createV6CompatibleWrapCreateMemoryRouter
467
-
468
- (
469
- createRouterFunction,
470
- version,
471
- ) {
276
+ function createV6CompatibleWrapCreateMemoryRouter(createRouterFunction, version) {
472
277
  if (!_useEffect || !_useLocation || !_useNavigationType || !_matchRoutes) {
473
- debugBuild.DEBUG_BUILD &&
474
- core.debug.warn(
475
- `reactRouterV${version}Instrumentation was unable to wrap the \`createMemoryRouter\` function because of one or more missing parameters.`,
476
- );
477
-
278
+ debugBuild.DEBUG_BUILD && core.debug.warn(
279
+ `reactRouterV${version}Instrumentation was unable to wrap the \`createMemoryRouter\` function because of one or more missing parameters.`
280
+ );
478
281
  return createRouterFunction;
479
282
  }
480
-
481
- return function (
482
- routes,
483
- opts
484
-
485
- ,
486
- ) {
283
+ return function(routes, opts) {
487
284
  addRoutesToAllRoutes(routes);
488
-
489
285
  if (_enableAsyncRouteHandlers) {
490
286
  for (const route of routes) {
491
287
  lazyRoutes.checkRouteForAsyncHandler(route, processResolvedRoutes);
492
288
  }
493
289
  }
494
-
495
- // Capture the active span BEFORE creating the router (same as browser router)
496
290
  const memoryActiveRootSpanEarly = utils.getActiveRootSpan();
497
-
498
- // If patchRoutesOnNavigation is provided and we have an active span,
499
- // mark the span as having potential lazy routes and create a deferred promise.
500
- const hasPatchRoutesOnNavigation =
501
- opts && 'patchRoutesOnNavigation' in opts && typeof opts.patchRoutesOnNavigation === 'function';
291
+ const hasPatchRoutesOnNavigation = opts && "patchRoutesOnNavigation" in opts && typeof opts.patchRoutesOnNavigation === "function";
502
292
  if (hasPatchRoutesOnNavigation && memoryActiveRootSpanEarly) {
503
293
  core.addNonEnumerableProperty(
504
- memoryActiveRootSpanEarly ,
505
- '__sentry_may_have_lazy_routes__',
506
- true,
294
+ memoryActiveRootSpanEarly,
295
+ "__sentry_may_have_lazy_routes__",
296
+ true
507
297
  );
508
298
  createDeferredLazyRoutePromise(memoryActiveRootSpanEarly);
509
299
  }
510
-
511
300
  const wrappedOpts = wrapPatchRoutesOnNavigation(opts, true, memoryActiveRootSpanEarly);
512
-
513
301
  const router = createRouterFunction(routes, wrappedOpts);
514
302
  const basename = opts?.basename;
515
-
516
- let initialEntry = undefined;
517
-
303
+ let initialEntry = void 0;
518
304
  const initialEntries = opts?.initialEntries;
519
305
  const initialIndex = opts?.initialIndex;
520
-
521
306
  const hasOnlyOneInitialEntry = initialEntries?.length === 1;
522
- const hasIndexedEntry = initialIndex !== undefined && initialEntries?.[initialIndex];
523
-
524
- initialEntry = hasOnlyOneInitialEntry
525
- ? initialEntries[0]
526
- : hasIndexedEntry
527
- ? initialEntries[initialIndex]
528
- : undefined;
529
-
530
- const location = initialEntry
531
- ? typeof initialEntry === 'string'
532
- ? { pathname: initialEntry }
533
- : initialEntry
534
- : router.state.location;
535
-
307
+ const hasIndexedEntry = initialIndex !== void 0 && initialEntries?.[initialIndex];
308
+ initialEntry = hasOnlyOneInitialEntry ? initialEntries[0] : hasIndexedEntry ? initialEntries[initialIndex] : void 0;
309
+ const location = initialEntry ? typeof initialEntry === "string" ? { pathname: initialEntry } : initialEntry : router.state.location;
536
310
  const memoryActiveRootSpan = utils.getActiveRootSpan();
537
-
538
- if (router.state.historyAction === 'POP' && memoryActiveRootSpan) {
311
+ if (router.state.historyAction === "POP" && memoryActiveRootSpan) {
539
312
  updatePageloadTransaction({
540
313
  activeRootSpan: memoryActiveRootSpan,
541
314
  location,
542
315
  routes,
543
316
  basename,
544
- allRoutes: Array.from(allRoutes),
317
+ allRoutes: Array.from(allRoutes)
545
318
  });
546
319
  }
547
-
548
- // Store basename for use in updateNavigationSpan
549
- _basename = basename || '';
550
-
320
+ _basename = basename || "";
551
321
  setupRouterSubscription(router, routes, version, basename, memoryActiveRootSpan);
552
-
553
322
  return router;
554
323
  };
555
324
  }
556
-
557
- /**
558
- * Creates a browser tracing integration that can be used with all React Router v6 compatible versions.
559
- */
560
- function createReactRouterV6CompatibleTracingIntegration(
561
- options,
562
- version,
563
- ) {
325
+ function createReactRouterV6CompatibleTracingIntegration(options, version) {
564
326
  const integration = browser.browserTracingIntegration({ ...options, instrumentPageLoad: false, instrumentNavigation: false });
565
-
566
327
  const {
567
328
  useEffect,
568
329
  useLocation,
@@ -574,44 +335,36 @@ function createReactRouterV6CompatibleTracingIntegration(
574
335
  instrumentPageLoad = true,
575
336
  instrumentNavigation = true,
576
337
  lazyRouteTimeout,
577
- lazyRouteManifest,
338
+ lazyRouteManifest
578
339
  } = options;
579
-
580
340
  return {
581
341
  ...integration,
582
342
  setup(client) {
583
343
  integration.setup(client);
584
-
585
- const finalTimeout = options.finalTimeout ?? 30000;
586
- const defaultMaxWait = (options.idleTimeout ?? 1000) * 3;
344
+ const finalTimeout = options.finalTimeout ?? 3e4;
345
+ const defaultMaxWait = (options.idleTimeout ?? 1e3) * 3;
587
346
  const configuredMaxWait = lazyRouteTimeout ?? defaultMaxWait;
588
-
589
- // Cap Infinity at finalTimeout to prevent indefinite hangs
590
347
  if (configuredMaxWait === Infinity) {
591
348
  _lazyRouteTimeout = finalTimeout;
592
- debugBuild.DEBUG_BUILD &&
593
- core.debug.log(
594
- '[React Router] lazyRouteTimeout set to Infinity, capping at finalTimeout:',
595
- finalTimeout,
596
- 'ms to prevent indefinite hangs',
597
- );
349
+ debugBuild.DEBUG_BUILD && core.debug.log(
350
+ "[React Router] lazyRouteTimeout set to Infinity, capping at finalTimeout:",
351
+ finalTimeout,
352
+ "ms to prevent indefinite hangs"
353
+ );
598
354
  } else if (Number.isNaN(configuredMaxWait)) {
599
- debugBuild.DEBUG_BUILD &&
600
- core.debug.warn('[React Router] lazyRouteTimeout must be a number, falling back to default:', defaultMaxWait);
355
+ debugBuild.DEBUG_BUILD && core.debug.warn("[React Router] lazyRouteTimeout must be a number, falling back to default:", defaultMaxWait);
601
356
  _lazyRouteTimeout = defaultMaxWait;
602
357
  } else if (configuredMaxWait < 0) {
603
- debugBuild.DEBUG_BUILD &&
604
- core.debug.warn(
605
- '[React Router] lazyRouteTimeout must be non-negative or Infinity, got:',
606
- configuredMaxWait,
607
- 'falling back to:',
608
- defaultMaxWait,
609
- );
358
+ debugBuild.DEBUG_BUILD && core.debug.warn(
359
+ "[React Router] lazyRouteTimeout must be non-negative or Infinity, got:",
360
+ configuredMaxWait,
361
+ "falling back to:",
362
+ defaultMaxWait
363
+ );
610
364
  _lazyRouteTimeout = defaultMaxWait;
611
365
  } else {
612
366
  _lazyRouteTimeout = configuredMaxWait;
613
367
  }
614
-
615
368
  _useEffect = useEffect;
616
369
  _useLocation = useLocation;
617
370
  _useNavigationType = useNavigationType;
@@ -619,278 +372,188 @@ function createReactRouterV6CompatibleTracingIntegration(
619
372
  _createRoutesFromChildren = createRoutesFromChildren;
620
373
  _enableAsyncRouteHandlers = enableAsyncRouteHandlers;
621
374
  _lazyRouteManifest = lazyRouteManifest;
622
-
623
- // Initialize the router utils with the required dependencies
624
375
  utils.initializeRouterUtils(matchRoutes, stripBasename || false);
625
376
  },
626
377
  afterAllSetup(client) {
627
378
  integration.afterAllSetup(client);
628
-
629
379
  const initPathName = browser.WINDOW.location?.pathname;
630
380
  if (instrumentPageLoad && initPathName) {
631
381
  browser.startBrowserTracingPageLoadSpan(client, {
632
382
  name: initPathName,
633
383
  attributes: {
634
- [core.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'url',
635
- [core.SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'pageload',
636
- [core.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: `auto.pageload.react.reactrouter_v${version}`,
637
- },
384
+ [core.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: "url",
385
+ [core.SEMANTIC_ATTRIBUTE_SENTRY_OP]: "pageload",
386
+ [core.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: `auto.pageload.react.reactrouter_v${version}`
387
+ }
638
388
  });
639
389
  }
640
-
641
390
  if (instrumentNavigation) {
642
391
  CLIENTS_WITH_INSTRUMENT_NAVIGATION.add(client);
643
392
  }
644
- },
393
+ }
645
394
  };
646
395
  }
647
-
648
396
  function createV6CompatibleWrapUseRoutes(origUseRoutes, version) {
649
397
  if (!_useEffect || !_useLocation || !_useNavigationType || !_matchRoutes) {
650
- debugBuild.DEBUG_BUILD &&
651
- core.debug.warn(
652
- 'reactRouterV6Instrumentation was unable to wrap `useRoutes` because of one or more missing parameters.',
653
- );
654
-
398
+ debugBuild.DEBUG_BUILD && core.debug.warn(
399
+ "reactRouterV6Instrumentation was unable to wrap `useRoutes` because of one or more missing parameters."
400
+ );
655
401
  return origUseRoutes;
656
402
  }
657
-
658
- const SentryRoutes
659
-
660
- = (props) => {
403
+ const SentryRoutes = (props) => {
661
404
  const isMountRenderPass = React.useRef(true);
662
405
  const { routes, locationArg } = props;
663
-
664
406
  const Routes = origUseRoutes(routes, locationArg);
665
-
666
407
  const location = _useLocation();
667
408
  const navigationType = _useNavigationType();
668
-
669
- // A value with stable identity to either pick `locationArg` if available or `location` if not
670
- const stableLocationParam =
671
- typeof locationArg === 'string' || locationArg?.pathname ? (locationArg ) : location;
672
-
409
+ const stableLocationParam = typeof locationArg === "string" || locationArg?.pathname ? locationArg : location;
673
410
  _useEffect(() => {
674
- const normalizedLocation =
675
- typeof stableLocationParam === 'string' ? { pathname: stableLocationParam } : stableLocationParam;
676
-
411
+ const normalizedLocation = typeof stableLocationParam === "string" ? { pathname: stableLocationParam } : stableLocationParam;
677
412
  if (isMountRenderPass.current) {
678
413
  addRoutesToAllRoutes(routes);
679
-
680
414
  updatePageloadTransaction({
681
415
  activeRootSpan: utils.getActiveRootSpan(),
682
416
  location: normalizedLocation,
683
417
  routes,
684
- allRoutes: Array.from(allRoutes),
418
+ allRoutes: Array.from(allRoutes)
685
419
  });
686
420
  isMountRenderPass.current = false;
687
421
  } else {
688
- // Note: Component-based routes don't support lazy route tracking via lazyRouteTimeout
689
- // because React.lazy() loads happen at the component level, not the router level.
690
- // Use createBrowserRouter with patchRoutesOnNavigation for lazy route tracking.
691
422
  handleNavigation({
692
423
  location: normalizedLocation,
693
424
  routes,
694
425
  navigationType,
695
426
  version,
696
- allRoutes: Array.from(allRoutes),
427
+ allRoutes: Array.from(allRoutes)
697
428
  });
698
429
  }
699
430
  }, [navigationType, stableLocationParam]);
700
-
701
431
  return Routes;
702
432
  };
703
-
704
- // eslint-disable-next-line react/display-name
705
433
  return (routes, locationArg) => {
706
- return React.createElement(SentryRoutes, { routes: routes, locationArg: locationArg,} );
434
+ return /* @__PURE__ */ React.createElement(SentryRoutes, { routes, locationArg });
707
435
  };
708
436
  }
709
- function wrapPatchRoutesOnNavigation(
710
- opts,
711
- isMemoryRouter = false,
712
- capturedSpan,
713
- ) {
714
- if (!opts || !('patchRoutesOnNavigation' in opts) || typeof opts.patchRoutesOnNavigation !== 'function') {
437
+ function wrapPatchRoutesOnNavigation(opts, isMemoryRouter = false, capturedSpan) {
438
+ if (!opts || !("patchRoutesOnNavigation" in opts) || typeof opts.patchRoutesOnNavigation !== "function") {
715
439
  return opts || {};
716
440
  }
717
-
718
441
  const originalPatchRoutes = opts.patchRoutesOnNavigation;
719
442
  return {
720
443
  ...opts,
721
444
  patchRoutesOnNavigation: async (args) => {
722
- // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-member-access
723
- const targetPath = (args )?.path;
724
-
725
- // Use current active span if available, otherwise fall back to captured span (from router creation time).
726
- // This ensures navigation spans use their own span (not the stale pageload span), while still
727
- // supporting pageload spans that may have ended before patchRoutesOnNavigation is called.
445
+ const targetPath = args?.path;
728
446
  const activeRootSpan = utils.getActiveRootSpan() ?? capturedSpan;
729
-
730
447
  if (!isMemoryRouter) {
731
- // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-member-access
732
- const originalPatch = (args )?.patch;
733
- // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-member-access
734
- const matches = (args )?.matches ;
448
+ const originalPatch = args?.patch;
449
+ const matches = args?.matches;
735
450
  if (originalPatch) {
736
- // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-member-access
737
- (args ).patch = (routeId, children) => {
451
+ args.patch = (routeId, children) => {
738
452
  addRoutesToAllRoutes(children);
739
-
740
- // Find the parent route from matches and attach children to it in allRoutes.
741
- // React Router's patch attaches children to its internal route copies, but we need
742
- // to update the route objects in our allRoutes Set for proper route matching.
743
453
  if (matches && matches.length > 0) {
744
454
  const leafMatch = matches[matches.length - 1];
745
455
  const leafRoute = leafMatch?.route;
746
456
  if (leafRoute) {
747
- // Find the matching route in allRoutes by id, reference, or path
748
- const matchingRoute = Array.from(allRoutes).find(route => {
749
- const idMatches = route.id !== undefined && route.id === routeId;
457
+ const matchingRoute = Array.from(allRoutes).find((route) => {
458
+ const idMatches = route.id !== void 0 && route.id === routeId;
750
459
  const referenceMatches = route === leafRoute;
751
- const pathMatches =
752
- route.path !== undefined && leafRoute.path !== undefined && route.path === leafRoute.path;
753
-
460
+ const pathMatches = route.path !== void 0 && leafRoute.path !== void 0 && route.path === leafRoute.path;
754
461
  return idMatches || referenceMatches || pathMatches;
755
462
  });
756
-
757
463
  if (matchingRoute) {
758
464
  addResolvedRoutesToParent(children, matchingRoute);
759
465
  }
760
466
  }
761
467
  }
762
-
763
- // Use the captured activeRootSpan instead of getActiveRootSpan() to avoid race conditions
764
- // where user navigates away during lazy route loading and we'd update the wrong span
765
- const spanJson = activeRootSpan ? core.spanToJSON(activeRootSpan) : undefined;
766
- // Only update if we have a valid targetPath (patchRoutesOnNavigation can be called without path),
767
- // the captured span exists, hasn't ended, and is a navigation span
768
- if (
769
- targetPath &&
770
- activeRootSpan &&
771
- spanJson &&
772
- !spanJson.timestamp && // Span hasn't ended yet
773
- spanJson.op === 'navigation'
774
- ) {
468
+ const spanJson = activeRootSpan ? core.spanToJSON(activeRootSpan) : void 0;
469
+ if (targetPath && activeRootSpan && spanJson && !spanJson.timestamp && // Span hasn't ended yet
470
+ spanJson.op === "navigation") {
775
471
  updateNavigationSpan(
776
472
  activeRootSpan,
777
- { pathname: targetPath, search: '', hash: '', state: null, key: 'default' },
473
+ { pathname: targetPath, search: "", hash: "", state: null, key: "default" },
778
474
  Array.from(allRoutes),
779
475
  true,
780
- _matchRoutes,
476
+ _matchRoutes
781
477
  );
782
478
  }
783
479
  return originalPatch(routeId, children);
784
480
  };
785
481
  }
786
482
  }
787
-
788
483
  const lazyLoadPromise = (async () => {
789
- // Set context so async handlers can access correct targetPath and span
790
484
  const contextToken = utils.setNavigationContext(targetPath, activeRootSpan);
791
485
  let result;
792
486
  try {
793
487
  result = await originalPatchRoutes(args);
794
488
  } finally {
795
489
  utils.clearNavigationContext(contextToken);
796
- // Resolve the deferred promise now that patchRoutesOnNavigation has completed.
797
- // This ensures patchedEnd has waited long enough for the lazy routes to load.
798
490
  if (activeRootSpan) {
799
491
  resolveDeferredLazyRoutePromise(activeRootSpan);
800
492
  }
801
493
  }
802
-
803
- // Use the captured activeRootSpan instead of getActiveRootSpan() to avoid race conditions
804
- // where user navigates away during lazy route loading and we'd update the wrong span
805
- const spanJson = activeRootSpan ? core.spanToJSON(activeRootSpan) : undefined;
806
- if (
807
- activeRootSpan &&
808
- spanJson &&
809
- !spanJson.timestamp && // Span hasn't ended yet
810
- spanJson.op === 'navigation'
811
- ) {
812
- // Use targetPath consistently - don't fall back to WINDOW.location which may have changed
813
- // if the user navigated away during async loading
494
+ const spanJson = activeRootSpan ? core.spanToJSON(activeRootSpan) : void 0;
495
+ if (activeRootSpan && spanJson && !spanJson.timestamp && // Span hasn't ended yet
496
+ spanJson.op === "navigation") {
814
497
  const pathname = targetPath;
815
-
816
498
  if (pathname) {
817
499
  updateNavigationSpan(
818
500
  activeRootSpan,
819
- { pathname, search: '', hash: '', state: null, key: 'default' },
501
+ { pathname, search: "", hash: "", state: null, key: "default" },
820
502
  Array.from(allRoutes),
821
503
  false,
822
- _matchRoutes,
504
+ _matchRoutes
823
505
  );
824
506
  }
825
507
  }
826
-
827
508
  return result;
828
509
  })();
829
-
830
510
  if (activeRootSpan) {
831
511
  trackLazyRouteLoad(activeRootSpan, lazyLoadPromise);
832
512
  }
833
-
834
513
  return lazyLoadPromise;
835
- },
514
+ }
836
515
  };
837
516
  }
838
-
839
- // eslint-disable-next-line complexity
840
- function handleNavigation(opts
841
-
842
- ) {
843
- const { location, routes, navigationType, version, matches, basename, allRoutes } = opts;
844
- const branches = Array.isArray(matches) ? matches : _matchRoutes(allRoutes || routes, location, basename);
845
-
517
+ function handleNavigation(opts) {
518
+ const { location, routes, navigationType, version, matches, basename, allRoutes: allRoutes2 } = opts;
519
+ const branches = Array.isArray(matches) ? matches : _matchRoutes(allRoutes2 || routes, location, basename);
846
520
  const client = core.getClient();
847
521
  if (!client || !CLIENTS_WITH_INSTRUMENT_NAVIGATION.has(client)) {
848
522
  return;
849
523
  }
850
-
851
524
  const activeRootSpan = utils.getActiveRootSpan();
852
- if (activeRootSpan && core.spanToJSON(activeRootSpan).op === 'pageload' && navigationType === 'POP') {
525
+ if (activeRootSpan && core.spanToJSON(activeRootSpan).op === "pageload" && navigationType === "POP") {
853
526
  return;
854
527
  }
855
-
856
- if ((navigationType === 'PUSH' || navigationType === 'POP') && branches) {
528
+ if ((navigationType === "PUSH" || navigationType === "POP") && branches) {
857
529
  const [name, source] = utils.resolveRouteNameAndSource(
858
530
  location,
859
- allRoutes || routes,
860
- allRoutes || routes,
861
- branches ,
531
+ allRoutes2 || routes,
532
+ allRoutes2 || routes,
533
+ branches,
862
534
  basename,
863
535
  _lazyRouteManifest,
864
- _enableAsyncRouteHandlers,
536
+ _enableAsyncRouteHandlers
865
537
  );
866
-
867
538
  const locationKey = computeLocationKey(location);
868
539
  const trackedNav = activeNavigationSpans.get(client);
869
-
870
- // Determine if this navigation should be skipped as a duplicate
871
- const trackedSpanHasEnded =
872
- trackedNav && !trackedNav.isPlaceholder ? !!core.spanToJSON(trackedNav.span).timestamp : false;
540
+ const trackedSpanHasEnded = trackedNav && !trackedNav.isPlaceholder ? !!core.spanToJSON(trackedNav.span).timestamp : false;
873
541
  const { skip, shouldUpdate } = shouldSkipNavigation(trackedNav, locationKey, name, trackedSpanHasEnded);
874
-
875
542
  if (skip) {
876
543
  if (shouldUpdate && trackedNav) {
877
544
  const oldName = trackedNav.routeName;
878
-
879
545
  if (trackedNav.isPlaceholder) {
880
- // Update placeholder's route name - the real span will be created with this name
881
546
  trackedNav.routeName = name;
882
- debugBuild.DEBUG_BUILD &&
883
- core.debug.log(
884
- `[Tracing] Updated placeholder navigation name from "${oldName}" to "${name}" (will apply to real span)`,
885
- );
547
+ debugBuild.DEBUG_BUILD && core.debug.log(
548
+ `[Tracing] Updated placeholder navigation name from "${oldName}" to "${name}" (will apply to real span)`
549
+ );
886
550
  } else {
887
- // Update existing real span from wildcard to parameterized route name
888
551
  trackedNav.span.updateName(name);
889
- trackedNav.span.setAttribute(core.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, source );
552
+ trackedNav.span.setAttribute(core.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, source);
890
553
  core.addNonEnumerableProperty(
891
- trackedNav.span ,
892
- '__sentry_navigation_name_set__',
893
- true,
554
+ trackedNav.span,
555
+ "__sentry_navigation_name_set__",
556
+ true
894
557
  );
895
558
  trackedNav.routeName = name;
896
559
  debugBuild.DEBUG_BUILD && core.debug.log(`[Tracing] Updated navigation span name from "${oldName}" to "${name}"`);
@@ -900,191 +563,124 @@ function handleNavigation(opts
900
563
  }
901
564
  return;
902
565
  }
903
-
904
- // Create new navigation span (first navigation or legitimate new navigation)
905
- // Reserve the spot in the map first to prevent race conditions
906
- // Mark as placeholder to prevent concurrent handleNavigation calls from creating duplicates
907
- const placeholderSpan = { end: () => {} } ;
566
+ const placeholderSpan = { end: () => {
567
+ } };
908
568
  const placeholderEntry = {
909
569
  span: placeholderSpan,
910
570
  routeName: name,
911
571
  pathname: location.pathname,
912
572
  locationKey,
913
- isPlaceholder: true ,
573
+ isPlaceholder: true
914
574
  };
915
575
  activeNavigationSpans.set(client, placeholderEntry);
916
-
917
576
  let navigationSpan;
918
577
  try {
919
578
  navigationSpan = browser.startBrowserTracingNavigationSpan(client, {
920
- name: placeholderEntry.routeName, // Use placeholder's routeName in case it was updated
579
+ name: placeholderEntry.routeName,
580
+ // Use placeholder's routeName in case it was updated
921
581
  attributes: {
922
582
  [core.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: source,
923
- [core.SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'navigation',
924
- [core.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: `auto.navigation.react.reactrouter_v${version}`,
925
- },
583
+ [core.SEMANTIC_ATTRIBUTE_SENTRY_OP]: "navigation",
584
+ [core.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: `auto.navigation.react.reactrouter_v${version}`
585
+ }
926
586
  });
927
587
  } catch (e) {
928
- // If span creation fails, remove the placeholder so we don't block future navigations
929
588
  activeNavigationSpans.delete(client);
930
589
  throw e;
931
590
  }
932
-
933
591
  if (navigationSpan) {
934
- // Update the map with the real span (isPlaceholder omitted, defaults to false)
935
592
  activeNavigationSpans.set(client, {
936
593
  span: navigationSpan,
937
- routeName: placeholderEntry.routeName, // Use the (potentially updated) placeholder routeName
594
+ routeName: placeholderEntry.routeName,
595
+ // Use the (potentially updated) placeholder routeName
938
596
  pathname: location.pathname,
939
- locationKey,
597
+ locationKey
940
598
  });
941
- patchSpanEnd(navigationSpan, location, routes, basename, 'navigation');
599
+ patchSpanEnd(navigationSpan, location, routes, basename, "navigation");
942
600
  } else {
943
- // If no span was created, remove the placeholder
944
601
  activeNavigationSpans.delete(client);
945
602
  }
946
603
  }
947
604
  }
948
-
949
- /* Only exported for testing purposes */
950
605
  function addRoutesToAllRoutes(routes) {
951
- routes.forEach(route => {
606
+ routes.forEach((route) => {
952
607
  const extractedChildRoutes = getChildRoutesRecursively(route);
953
-
954
- extractedChildRoutes.forEach(r => {
608
+ extractedChildRoutes.forEach((r) => {
955
609
  allRoutes.add(r);
956
610
  });
957
611
  });
958
612
  }
959
-
960
- function getChildRoutesRecursively(route, allRoutes = new Set()) {
961
- if (!allRoutes.has(route)) {
962
- allRoutes.add(route);
963
-
613
+ function getChildRoutesRecursively(route, allRoutes2 = /* @__PURE__ */ new Set()) {
614
+ if (!allRoutes2.has(route)) {
615
+ allRoutes2.add(route);
964
616
  if (route.children && !route.index) {
965
- route.children.forEach(child => {
966
- const childRoutes = getChildRoutesRecursively(child, allRoutes);
967
-
968
- childRoutes.forEach(r => {
969
- allRoutes.add(r);
617
+ route.children.forEach((child) => {
618
+ const childRoutes = getChildRoutesRecursively(child, allRoutes2);
619
+ childRoutes.forEach((r) => {
620
+ allRoutes2.add(r);
970
621
  });
971
622
  });
972
623
  }
973
624
  }
974
-
975
- return allRoutes;
625
+ return allRoutes2;
976
626
  }
977
-
978
627
  function updatePageloadTransaction({
979
628
  activeRootSpan,
980
629
  location,
981
630
  routes,
982
631
  matches,
983
632
  basename,
984
- allRoutes,
985
- }
986
-
987
- ) {
988
- const branches = Array.isArray(matches)
989
- ? matches
990
- : (_matchRoutes(allRoutes || routes, location, basename) );
991
-
633
+ allRoutes: allRoutes2
634
+ }) {
635
+ const branches = Array.isArray(matches) ? matches : _matchRoutes(allRoutes2 || routes, location, basename);
992
636
  if (branches) {
993
637
  const [name, source] = utils.resolveRouteNameAndSource(
994
638
  location,
995
- allRoutes || routes,
996
- allRoutes || routes,
639
+ allRoutes2 || routes,
640
+ allRoutes2 || routes,
997
641
  branches,
998
642
  basename,
999
643
  _lazyRouteManifest,
1000
- _enableAsyncRouteHandlers,
644
+ _enableAsyncRouteHandlers
1001
645
  );
1002
-
1003
- core.getCurrentScope().setTransactionName(name || '/');
1004
-
646
+ core.getCurrentScope().setTransactionName(name || "/");
1005
647
  if (activeRootSpan) {
1006
648
  activeRootSpan.updateName(name);
1007
649
  activeRootSpan.setAttribute(core.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, source);
1008
-
1009
- // Patch span.end() to ensure we update the name one last time before the span is sent
1010
- patchSpanEnd(activeRootSpan, location, routes, basename, 'pageload');
650
+ patchSpanEnd(activeRootSpan, location, routes, basename, "pageload");
1011
651
  }
1012
652
  } else if (activeRootSpan) {
1013
- // Even if branches is null (can happen when lazy routes haven't loaded yet),
1014
- // we still need to patch span.end() so that when lazy routes load and the span ends,
1015
- // we can update the transaction name correctly.
1016
- patchSpanEnd(activeRootSpan, location, routes, basename, 'pageload');
653
+ patchSpanEnd(activeRootSpan, location, routes, basename, "pageload");
1017
654
  }
1018
655
  }
1019
-
1020
- /**
1021
- * Determines if a span name should be updated during wildcard route resolution.
1022
- *
1023
- * Update conditions (in priority order):
1024
- * 1. No current name + allowNoCurrentName: true → always update (pageload spans)
1025
- * 2. Current name has wildcard + new is route without wildcard → upgrade (e.g., "/users/*" → "/users/:id")
1026
- * 3. Current source is not 'route' + new source is 'route' → upgrade (e.g., URL → parameterized route)
1027
- *
1028
- * @param currentName - The current span name (may be undefined)
1029
- * @param currentSource - The current span source ('route', 'url', or undefined)
1030
- * @param newName - The proposed new span name
1031
- * @param newSource - The proposed new span source
1032
- * @param allowNoCurrentName - If true, allow updates when there's no current name (for pageload spans)
1033
- * @returns true if the span name should be updated
1034
- */
1035
- function shouldUpdateWildcardSpanName(
1036
- currentName,
1037
- currentSource,
1038
- newName,
1039
- newSource,
1040
- allowNoCurrentName = false,
1041
- ) {
656
+ function shouldUpdateWildcardSpanName(currentName, currentSource, newName, newSource, allowNoCurrentName = false) {
1042
657
  if (!newName) {
1043
658
  return false;
1044
659
  }
1045
-
1046
660
  if (!currentName && allowNoCurrentName) {
1047
661
  return true;
1048
662
  }
1049
-
1050
663
  const hasWildcard = currentName && utils.transactionNameHasWildcard(currentName);
1051
-
1052
- if (hasWildcard && newSource === 'route' && !utils.transactionNameHasWildcard(newName)) {
664
+ if (hasWildcard && newSource === "route" && !utils.transactionNameHasWildcard(newName)) {
1053
665
  return true;
1054
666
  }
1055
-
1056
- if (currentSource !== 'route' && newSource === 'route') {
667
+ if (currentSource !== "route" && newSource === "route") {
1057
668
  return true;
1058
669
  }
1059
-
1060
670
  return false;
1061
671
  }
1062
-
1063
- function tryUpdateSpanNameBeforeEnd(
1064
- span,
1065
- spanJson,
1066
- currentName,
1067
- location,
1068
- routes,
1069
- basename,
1070
- spanType,
1071
- allRoutes,
1072
- ) {
672
+ function tryUpdateSpanNameBeforeEnd(span, spanJson, currentName, location, routes, basename, spanType, allRoutes2) {
1073
673
  try {
1074
674
  const currentSource = spanJson.data?.[core.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE];
1075
-
1076
- if (currentSource === 'route' && currentName && !utils.transactionNameHasWildcard(currentName)) {
675
+ if (currentSource === "route" && currentName && !utils.transactionNameHasWildcard(currentName)) {
1077
676
  return;
1078
677
  }
1079
-
1080
- const currentAllRoutes = Array.from(allRoutes);
678
+ const currentAllRoutes = Array.from(allRoutes2);
1081
679
  const routesToUse = currentAllRoutes.length > 0 ? currentAllRoutes : routes;
1082
- const branches = _matchRoutes(routesToUse, location, basename) ;
1083
-
680
+ const branches = _matchRoutes(routesToUse, location, basename);
1084
681
  if (!branches) {
1085
682
  return;
1086
683
  }
1087
-
1088
684
  const [name, source] = utils.resolveRouteNameAndSource(
1089
685
  location,
1090
686
  routesToUse,
@@ -1092,12 +688,10 @@ function tryUpdateSpanNameBeforeEnd(
1092
688
  branches,
1093
689
  basename,
1094
690
  _lazyRouteManifest,
1095
- _enableAsyncRouteHandlers,
691
+ _enableAsyncRouteHandlers
1096
692
  );
1097
-
1098
693
  const isImprovement = shouldUpdateWildcardSpanName(currentName, currentSource, name, source, true);
1099
- const spanNotEnded = spanType === 'pageload' || !spanJson.timestamp;
1100
-
694
+ const spanNotEnded = spanType === "pageload" || !spanJson.timestamp;
1101
695
  if (isImprovement && spanNotEnded) {
1102
696
  span.updateName(name);
1103
697
  span.setAttribute(core.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, source);
@@ -1106,68 +700,36 @@ function tryUpdateSpanNameBeforeEnd(
1106
700
  debugBuild.DEBUG_BUILD && core.debug.warn(`Error updating span details before ending: ${error}`);
1107
701
  }
1108
702
  }
1109
-
1110
- /**
1111
- * Patches the span.end() method to update the transaction name one last time before the span is sent.
1112
- * This handles cases where the span is cancelled early (e.g., document.hidden) before lazy routes have finished loading.
1113
- */
1114
- function patchSpanEnd(
1115
- span,
1116
- location,
1117
- routes,
1118
- basename,
1119
- spanType,
1120
- ) {
1121
- const patchedPropertyName = `__sentry_${spanType}_end_patched__` ;
1122
- const hasEndBeenPatched = (span )?.[patchedPropertyName];
1123
-
703
+ function patchSpanEnd(span, location, routes, basename, spanType) {
704
+ const patchedPropertyName = `__sentry_${spanType}_end_patched__`;
705
+ const hasEndBeenPatched = span?.[patchedPropertyName];
1124
706
  if (hasEndBeenPatched || !span.end) {
1125
707
  return;
1126
708
  }
1127
-
1128
- // Uses global allRoutes to access lazy-loaded routes added after this function was called.
1129
-
1130
709
  const originalEnd = span.end.bind(span);
1131
710
  let endCalled = false;
1132
-
1133
711
  span.end = function patchedEnd(...args) {
1134
712
  if (endCalled) {
1135
713
  return;
1136
714
  }
1137
715
  endCalled = true;
1138
-
1139
- // Capture timestamp immediately to avoid delay from async operations
1140
- // If no timestamp was provided, capture the current time now
1141
- const endTimestamp = args.length > 0 ? args[0] : Date.now() / 1000;
1142
-
716
+ const endTimestamp = args.length > 0 ? args[0] : Date.now() / 1e3;
1143
717
  const spanJson = core.spanToJSON(span);
1144
718
  const currentName = spanJson.description;
1145
719
  const currentSource = spanJson.data?.[core.SEMANTIC_ATTRIBUTE_SENTRY_SOURCE];
1146
-
1147
- // Helper to clean up activeNavigationSpans after span ends
1148
720
  const cleanupNavigationSpan = () => {
1149
721
  const client = core.getClient();
1150
- if (client && spanType === 'navigation') {
722
+ if (client && spanType === "navigation") {
1151
723
  const trackedNav = activeNavigationSpans.get(client);
1152
724
  if (trackedNav && trackedNav.span === span) {
1153
725
  activeNavigationSpans.delete(client);
1154
726
  }
1155
727
  }
1156
728
  };
1157
-
1158
729
  const pendingPromises = pendingLazyRouteLoads.get(span);
1159
- const mayHaveLazyRoutes = (span ).__sentry_may_have_lazy_routes__;
1160
-
1161
- // Wait for lazy routes if:
1162
- // 1. (There are pending promises OR the span was marked as potentially having lazy routes) AND
1163
- // 2. Current name exists AND
1164
- // 3. Either the name has a wildcard OR the source is not 'route' (URL-based names)
1165
- const hasPendingOrMayHaveLazyRoutes = (pendingPromises && pendingPromises.size > 0) || mayHaveLazyRoutes;
1166
- const shouldWaitForLazyRoutes =
1167
- hasPendingOrMayHaveLazyRoutes &&
1168
- currentName &&
1169
- (utils.transactionNameHasWildcard(currentName) || currentSource !== 'route');
1170
-
730
+ const mayHaveLazyRoutes = span.__sentry_may_have_lazy_routes__;
731
+ const hasPendingOrMayHaveLazyRoutes = pendingPromises && pendingPromises.size > 0 || mayHaveLazyRoutes;
732
+ const shouldWaitForLazyRoutes = hasPendingOrMayHaveLazyRoutes && currentName && (utils.transactionNameHasWildcard(currentName) || currentSource !== "route");
1171
733
  if (shouldWaitForLazyRoutes) {
1172
734
  if (_lazyRouteTimeout === 0) {
1173
735
  tryUpdateSpanNameBeforeEnd(span, spanJson, currentName, location, routes, basename, spanType, allRoutes);
@@ -1175,107 +737,74 @@ function patchSpanEnd(
1175
737
  originalEnd(endTimestamp);
1176
738
  return;
1177
739
  }
1178
-
1179
- // If we have pending promises, wait for them. Otherwise, just wait for the timeout.
1180
- // This handles the case where we know lazy routes might load but patchRoutesOnNavigation
1181
- // hasn't been called yet.
1182
- const timeoutPromise = new Promise(r => setTimeout(r, _lazyRouteTimeout));
740
+ const timeoutPromise = new Promise((r) => setTimeout(r, _lazyRouteTimeout));
1183
741
  let waitPromise;
1184
-
1185
742
  if (pendingPromises && pendingPromises.size > 0) {
1186
- const allSettled = Promise.allSettled(pendingPromises).then(() => {});
743
+ const allSettled = Promise.allSettled(pendingPromises).then(() => {
744
+ });
1187
745
  waitPromise = _lazyRouteTimeout === Infinity ? allSettled : Promise.race([allSettled, timeoutPromise]);
1188
746
  } else {
1189
- // No pending promises yet, but we know lazy routes might load
1190
- // Wait for the timeout to give React Router time to call patchRoutesOnNavigation
1191
747
  waitPromise = timeoutPromise;
1192
748
  }
1193
-
1194
- waitPromise
1195
- .then(() => {
1196
- const updatedSpanJson = core.spanToJSON(span);
1197
- tryUpdateSpanNameBeforeEnd(
1198
- span,
1199
- updatedSpanJson,
1200
- updatedSpanJson.description,
1201
- location,
1202
- routes,
1203
- basename,
1204
- spanType,
1205
- allRoutes,
1206
- );
1207
- cleanupNavigationSpan();
1208
- originalEnd(endTimestamp);
1209
- })
1210
- .catch(() => {
1211
- cleanupNavigationSpan();
1212
- originalEnd(endTimestamp);
1213
- });
749
+ waitPromise.then(() => {
750
+ const updatedSpanJson = core.spanToJSON(span);
751
+ tryUpdateSpanNameBeforeEnd(
752
+ span,
753
+ updatedSpanJson,
754
+ updatedSpanJson.description,
755
+ location,
756
+ routes,
757
+ basename,
758
+ spanType,
759
+ allRoutes
760
+ );
761
+ cleanupNavigationSpan();
762
+ originalEnd(endTimestamp);
763
+ }).catch(() => {
764
+ cleanupNavigationSpan();
765
+ originalEnd(endTimestamp);
766
+ });
1214
767
  return;
1215
768
  }
1216
-
1217
769
  tryUpdateSpanNameBeforeEnd(span, spanJson, currentName, location, routes, basename, spanType, allRoutes);
1218
770
  cleanupNavigationSpan();
1219
771
  originalEnd(endTimestamp);
1220
772
  };
1221
-
1222
- core.addNonEnumerableProperty(span , patchedPropertyName, true);
773
+ core.addNonEnumerableProperty(span, patchedPropertyName, true);
1223
774
  }
1224
-
1225
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
1226
- function createV6CompatibleWithSentryReactRouterRouting(
1227
- Routes,
1228
- version,
1229
- ) {
775
+ function createV6CompatibleWithSentryReactRouterRouting(Routes, version) {
1230
776
  if (!_useEffect || !_useLocation || !_useNavigationType || !_createRoutesFromChildren || !_matchRoutes) {
1231
- debugBuild.DEBUG_BUILD &&
1232
- core.debug.warn(`reactRouterV6Instrumentation was unable to wrap Routes because of one or more missing parameters.
777
+ debugBuild.DEBUG_BUILD && core.debug.warn(`reactRouterV6Instrumentation was unable to wrap Routes because of one or more missing parameters.
1233
778
  useEffect: ${_useEffect}. useLocation: ${_useLocation}. useNavigationType: ${_useNavigationType}.
1234
779
  createRoutesFromChildren: ${_createRoutesFromChildren}. matchRoutes: ${_matchRoutes}.`);
1235
-
1236
780
  return Routes;
1237
781
  }
1238
-
1239
782
  const SentryRoutes = (props) => {
1240
783
  const isMountRenderPass = React.useRef(true);
1241
-
1242
784
  const location = _useLocation();
1243
785
  const navigationType = _useNavigationType();
1244
-
1245
786
  _useEffect(
1246
787
  () => {
1247
- const routes = _createRoutesFromChildren(props.children) ;
1248
-
788
+ const routes = _createRoutesFromChildren(props.children);
1249
789
  if (isMountRenderPass.current) {
1250
790
  addRoutesToAllRoutes(routes);
1251
-
1252
791
  updatePageloadTransaction({
1253
792
  activeRootSpan: utils.getActiveRootSpan(),
1254
793
  location,
1255
794
  routes,
1256
- allRoutes: Array.from(allRoutes),
795
+ allRoutes: Array.from(allRoutes)
1257
796
  });
1258
797
  isMountRenderPass.current = false;
1259
798
  } else {
1260
- // Note: Component-based routes don't support lazy route tracking via lazyRouteTimeout
1261
- // because React.lazy() loads happen at the component level, not the router level.
1262
- // Use createBrowserRouter with patchRoutesOnNavigation for lazy route tracking.
1263
799
  handleNavigation({ location, routes, navigationType, version, allRoutes: Array.from(allRoutes) });
1264
800
  }
1265
801
  },
1266
802
  // Re-run only on location/navigation changes, not children changes
1267
- [location, navigationType],
803
+ [location, navigationType]
1268
804
  );
1269
-
1270
- // @ts-expect-error Setting more specific React Component typing for `R` generic above
1271
- // will break advanced type inference done by react router params
1272
- return React.createElement(Routes, { ...props,} );
805
+ return /* @__PURE__ */ React.createElement(Routes, { ...props });
1273
806
  };
1274
-
1275
807
  hoistNonReactStatics.hoistNonReactStatics(SentryRoutes, Routes);
1276
-
1277
- // @ts-expect-error Setting more specific React Component typing for `R` generic above
1278
- // will break advanced type inference done by react router params
1279
808
  return SentryRoutes;
1280
809
  }
1281
810