@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.
- package/build/cjs/constants.js +3 -5
- package/build/cjs/constants.js.map +1 -1
- package/build/cjs/debug-build.js +0 -5
- package/build/cjs/debug-build.js.map +1 -1
- package/build/cjs/error.js +12 -72
- package/build/cjs/error.js.map +1 -1
- package/build/cjs/errorboundary.js +22 -77
- package/build/cjs/errorboundary.js.map +1 -1
- package/build/cjs/hoist-non-react-statics.js +16 -84
- package/build/cjs/hoist-non-react-statics.js.map +1 -1
- package/build/cjs/isSyntheticEvent.js +10 -0
- package/build/cjs/isSyntheticEvent.js.map +1 -0
- package/build/cjs/profiler.js +35 -110
- package/build/cjs/profiler.js.map +1 -1
- package/build/cjs/reactrouter-compat-utils/instrumentation.js +219 -690
- package/build/cjs/reactrouter-compat-utils/instrumentation.js.map +1 -1
- package/build/cjs/reactrouter-compat-utils/lazy-routes.js +24 -85
- package/build/cjs/reactrouter-compat-utils/lazy-routes.js.map +1 -1
- package/build/cjs/reactrouter-compat-utils/route-manifest.js +17 -95
- package/build/cjs/reactrouter-compat-utils/route-manifest.js.map +1 -1
- package/build/cjs/reactrouter-compat-utils/utils.js +48 -190
- package/build/cjs/reactrouter-compat-utils/utils.js.map +1 -1
- package/build/cjs/reactrouter.js +33 -113
- package/build/cjs/reactrouter.js.map +1 -1
- package/build/cjs/reactrouterv3.js +27 -59
- package/build/cjs/reactrouterv3.js.map +1 -1
- package/build/cjs/reactrouterv6.js +8 -41
- package/build/cjs/reactrouterv6.js.map +1 -1
- package/build/cjs/reactrouterv7.js +8 -41
- package/build/cjs/reactrouterv7.js.map +1 -1
- package/build/cjs/redux.js +60 -88
- package/build/cjs/redux.js.map +1 -1
- package/build/cjs/sdk.js +13 -8
- package/build/cjs/sdk.js.map +1 -1
- package/build/cjs/tanstackrouter.js +24 -64
- package/build/cjs/tanstackrouter.js.map +1 -1
- package/build/esm/constants.js +3 -5
- package/build/esm/constants.js.map +1 -1
- package/build/esm/debug-build.js +0 -5
- package/build/esm/debug-build.js.map +1 -1
- package/build/esm/error.js +12 -72
- package/build/esm/error.js.map +1 -1
- package/build/esm/errorboundary.js +22 -77
- package/build/esm/errorboundary.js.map +1 -1
- package/build/esm/hoist-non-react-statics.js +16 -84
- package/build/esm/hoist-non-react-statics.js.map +1 -1
- package/build/esm/isSyntheticEvent.js +8 -0
- package/build/esm/isSyntheticEvent.js.map +1 -0
- package/build/esm/package.json +1 -1
- package/build/esm/profiler.js +35 -110
- package/build/esm/profiler.js.map +1 -1
- package/build/esm/reactrouter-compat-utils/instrumentation.js +219 -690
- package/build/esm/reactrouter-compat-utils/instrumentation.js.map +1 -1
- package/build/esm/reactrouter-compat-utils/lazy-routes.js +24 -85
- package/build/esm/reactrouter-compat-utils/lazy-routes.js.map +1 -1
- package/build/esm/reactrouter-compat-utils/route-manifest.js +17 -95
- package/build/esm/reactrouter-compat-utils/route-manifest.js.map +1 -1
- package/build/esm/reactrouter-compat-utils/utils.js +48 -190
- package/build/esm/reactrouter-compat-utils/utils.js.map +1 -1
- package/build/esm/reactrouter.js +33 -113
- package/build/esm/reactrouter.js.map +1 -1
- package/build/esm/reactrouterv3.js +27 -59
- package/build/esm/reactrouterv3.js.map +1 -1
- package/build/esm/reactrouterv6.js +8 -41
- package/build/esm/reactrouterv6.js.map +1 -1
- package/build/esm/reactrouterv7.js +8 -41
- package/build/esm/reactrouterv7.js.map +1 -1
- package/build/esm/redux.js +60 -88
- package/build/esm/redux.js.map +1 -1
- package/build/esm/sdk.js +15 -10
- package/build/esm/sdk.js.map +1 -1
- package/build/esm/tanstackrouter.js +24 -64
- package/build/esm/tanstackrouter.js.map +1 -1
- package/build/types/isSyntheticEvent.d.ts +10 -0
- package/build/types/isSyntheticEvent.d.ts.map +1 -0
- package/build/types/sdk.d.ts.map +1 -1
- package/build/types-ts3.8/isSyntheticEvent.d.ts +10 -0
- package/package.json +3 -3
|
@@ -3,82 +3,49 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
|
3
3
|
const browser = require('@sentry/core/browser');
|
|
4
4
|
const debugBuild = require('../debug-build.js');
|
|
5
5
|
|
|
6
|
-
/**
|
|
7
|
-
* Strip the basename from a pathname if exists.
|
|
8
|
-
*
|
|
9
|
-
* Vendored and modified from `react-router`
|
|
10
|
-
* https://github.com/remix-run/react-router/blob/462bb712156a3f739d6139a0f14810b76b002df6/packages/router/utils.ts#L1038
|
|
11
|
-
*/
|
|
12
6
|
function stripBasenameFromPathname(pathname, basename) {
|
|
13
|
-
if (!basename || basename ===
|
|
7
|
+
if (!basename || basename === "/") {
|
|
14
8
|
return pathname;
|
|
15
9
|
}
|
|
16
|
-
|
|
17
10
|
if (!pathname.toLowerCase().startsWith(basename.toLowerCase())) {
|
|
18
11
|
return pathname;
|
|
19
12
|
}
|
|
20
|
-
|
|
21
|
-
// We want to leave trailing slash behavior in the user's control, so if they
|
|
22
|
-
// specify a basename with a trailing slash, we should support it
|
|
23
|
-
const startIndex = basename.endsWith('/') ? basename.length - 1 : basename.length;
|
|
13
|
+
const startIndex = basename.endsWith("/") ? basename.length - 1 : basename.length;
|
|
24
14
|
const nextChar = pathname.charAt(startIndex);
|
|
25
|
-
if (nextChar && nextChar !==
|
|
26
|
-
// pathname does not start with basename/
|
|
15
|
+
if (nextChar && nextChar !== "/") {
|
|
27
16
|
return pathname;
|
|
28
17
|
}
|
|
29
|
-
|
|
30
|
-
return pathname.slice(startIndex) || '/';
|
|
18
|
+
return pathname.slice(startIndex) || "/";
|
|
31
19
|
}
|
|
32
|
-
|
|
33
|
-
// Cache for sorted manifests - keyed by manifest array reference
|
|
34
|
-
const SORTED_MANIFEST_CACHE = new WeakMap();
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Matches a pathname against a route manifest and returns the matching pattern.
|
|
38
|
-
* Optionally strips a basename prefix before matching.
|
|
39
|
-
*/
|
|
20
|
+
const SORTED_MANIFEST_CACHE = /* @__PURE__ */ new WeakMap();
|
|
40
21
|
function matchRouteManifest(pathname, manifest, basename) {
|
|
41
22
|
if (!pathname || !manifest?.length) {
|
|
42
23
|
return null;
|
|
43
24
|
}
|
|
44
|
-
|
|
45
25
|
const normalizedPathname = basename ? stripBasenameFromPathname(pathname, basename) : pathname;
|
|
46
|
-
|
|
47
26
|
let sorted = SORTED_MANIFEST_CACHE.get(manifest);
|
|
48
27
|
if (!sorted) {
|
|
49
28
|
sorted = sortBySpecificity(manifest);
|
|
50
29
|
SORTED_MANIFEST_CACHE.set(manifest, sorted);
|
|
51
|
-
debugBuild.DEBUG_BUILD && browser.debug.log(
|
|
30
|
+
debugBuild.DEBUG_BUILD && browser.debug.log("[React Router] Sorted route manifest by specificity:", sorted.length, "patterns");
|
|
52
31
|
}
|
|
53
|
-
|
|
54
32
|
for (const pattern of sorted) {
|
|
55
33
|
if (matchesPattern(normalizedPathname, pattern)) {
|
|
56
|
-
debugBuild.DEBUG_BUILD && browser.debug.log(
|
|
34
|
+
debugBuild.DEBUG_BUILD && browser.debug.log("[React Router] Matched pathname", normalizedPathname, "to pattern", pattern);
|
|
57
35
|
return pattern;
|
|
58
36
|
}
|
|
59
37
|
}
|
|
60
|
-
|
|
61
|
-
debugBuild.DEBUG_BUILD && browser.debug.log('[React Router] No manifest match found for pathname:', normalizedPathname);
|
|
38
|
+
debugBuild.DEBUG_BUILD && browser.debug.log("[React Router] No manifest match found for pathname:", normalizedPathname);
|
|
62
39
|
return null;
|
|
63
40
|
}
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* Checks if a pathname matches a route pattern.
|
|
67
|
-
*/
|
|
68
41
|
function matchesPattern(pathname, pattern) {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
return pathname === '/' || pathname === '';
|
|
42
|
+
if (pattern === "/") {
|
|
43
|
+
return pathname === "/" || pathname === "";
|
|
72
44
|
}
|
|
73
|
-
|
|
74
45
|
const pathSegments = splitPath(pathname);
|
|
75
46
|
const patternSegments = splitPath(pattern);
|
|
76
|
-
|
|
77
|
-
// Handle wildcard at end
|
|
78
|
-
const hasWildcard = patternSegments.length > 0 && patternSegments[patternSegments.length - 1] === '*';
|
|
79
|
-
|
|
47
|
+
const hasWildcard = patternSegments.length > 0 && patternSegments[patternSegments.length - 1] === "*";
|
|
80
48
|
if (hasWildcard) {
|
|
81
|
-
// Pattern with wildcard: path must have at least as many segments as pattern (minus wildcard)
|
|
82
49
|
const patternSegmentsWithoutWildcard = patternSegments.slice(0, -1);
|
|
83
50
|
if (pathSegments.length < patternSegmentsWithoutWildcard.length) {
|
|
84
51
|
return false;
|
|
@@ -90,101 +57,56 @@ function matchesPattern(pathname, pattern) {
|
|
|
90
57
|
}
|
|
91
58
|
return true;
|
|
92
59
|
}
|
|
93
|
-
|
|
94
|
-
// Exact segment count match required
|
|
95
60
|
if (pathSegments.length !== patternSegments.length) {
|
|
96
61
|
return false;
|
|
97
62
|
}
|
|
98
|
-
|
|
99
63
|
for (const [i, patternSegment] of patternSegments.entries()) {
|
|
100
64
|
if (!segmentMatches(pathSegments[i], patternSegment)) {
|
|
101
65
|
return false;
|
|
102
66
|
}
|
|
103
67
|
}
|
|
104
|
-
|
|
105
68
|
return true;
|
|
106
69
|
}
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* Checks if a path segment matches a pattern segment.
|
|
110
|
-
*/
|
|
111
70
|
function segmentMatches(pathSegment, patternSegment) {
|
|
112
|
-
if (pathSegment ===
|
|
71
|
+
if (pathSegment === void 0 || patternSegment === void 0) {
|
|
113
72
|
return false;
|
|
114
73
|
}
|
|
115
|
-
// Parameter matches anything
|
|
116
74
|
if (PARAM_RE.test(patternSegment)) {
|
|
117
75
|
return true;
|
|
118
76
|
}
|
|
119
|
-
// Literal must match exactly
|
|
120
77
|
return pathSegment === patternSegment;
|
|
121
78
|
}
|
|
122
|
-
|
|
123
|
-
/**
|
|
124
|
-
* Splits a path into segments, filtering out empty strings.
|
|
125
|
-
*/
|
|
126
79
|
function splitPath(path) {
|
|
127
|
-
return path.split(
|
|
80
|
+
return path.split("/").filter(Boolean);
|
|
128
81
|
}
|
|
129
|
-
|
|
130
|
-
/**
|
|
131
|
-
* React Router scoring weights and param detection.
|
|
132
|
-
* https://github.com/remix-run/react-router/blob/main/packages/react-router/lib/router/utils.ts
|
|
133
|
-
*/
|
|
134
82
|
const PARAM_RE = /^:[\w-]+$/;
|
|
135
83
|
const STATIC_SEGMENT_SCORE = 10;
|
|
136
84
|
const DYNAMIC_SEGMENT_SCORE = 3;
|
|
137
85
|
const EMPTY_SEGMENT_SCORE = 1;
|
|
138
86
|
const SPLAT_PENALTY = -2;
|
|
139
|
-
|
|
140
|
-
/**
|
|
141
|
-
* Computes a specificity score for a route pattern.
|
|
142
|
-
* Matches React Router's computeScore() algorithm exactly.
|
|
143
|
-
*/
|
|
144
87
|
function computeScore(pattern) {
|
|
145
|
-
const segments = pattern.split(
|
|
146
|
-
|
|
147
|
-
// Base score is segment count (including empty segment from leading slash)
|
|
88
|
+
const segments = pattern.split("/");
|
|
148
89
|
let score = segments.length;
|
|
149
|
-
|
|
150
|
-
// Apply splat penalty once if pattern contains wildcard
|
|
151
|
-
if (segments.includes('*')) {
|
|
90
|
+
if (segments.includes("*")) {
|
|
152
91
|
score += SPLAT_PENALTY;
|
|
153
92
|
}
|
|
154
|
-
|
|
155
93
|
for (const segment of segments) {
|
|
156
|
-
if (segment ===
|
|
157
|
-
// Splat penalty already applied globally above
|
|
94
|
+
if (segment === "*") {
|
|
158
95
|
continue;
|
|
159
96
|
} else if (PARAM_RE.test(segment)) {
|
|
160
97
|
score += DYNAMIC_SEGMENT_SCORE;
|
|
161
|
-
} else if (segment ===
|
|
98
|
+
} else if (segment === "") {
|
|
162
99
|
score += EMPTY_SEGMENT_SCORE;
|
|
163
100
|
} else {
|
|
164
101
|
score += STATIC_SEGMENT_SCORE;
|
|
165
102
|
}
|
|
166
103
|
}
|
|
167
|
-
|
|
168
104
|
return score;
|
|
169
105
|
}
|
|
170
|
-
|
|
171
|
-
/**
|
|
172
|
-
* Sorts route patterns by specificity (most specific first).
|
|
173
|
-
* Implements React Router's ranking algorithm from computeScore():
|
|
174
|
-
* https://github.com/remix-run/react-router/blob/main/packages/react-router/lib/router/utils.ts
|
|
175
|
-
*
|
|
176
|
-
* React Router scoring: base=segments.length, static=+10, dynamic=+3, empty=+1, splat=-2 (once)
|
|
177
|
-
* Higher score = more specific pattern.
|
|
178
|
-
* Equal scores preserve manifest order (same as React Router).
|
|
179
|
-
*
|
|
180
|
-
* Note: Users should order their manifest from most specific to least specific
|
|
181
|
-
* when patterns have equal specificity (e.g., `/users/:id/settings` and `/:type/123/settings`).
|
|
182
|
-
*/
|
|
183
106
|
function sortBySpecificity(manifest) {
|
|
184
107
|
return [...manifest].sort((a, b) => {
|
|
185
108
|
const aScore = computeScore(a);
|
|
186
109
|
const bScore = computeScore(b);
|
|
187
|
-
|
|
188
110
|
return bScore - aScore;
|
|
189
111
|
});
|
|
190
112
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"route-manifest.js","sources":["../../../src/reactrouter-compat-utils/route-manifest.ts"],"sourcesContent":["import { debug } from '@sentry/core/browser';\nimport { DEBUG_BUILD } from '../debug-build';\n\n/**\n * Strip the basename from a pathname if exists.\n *\n * Vendored and modified from `react-router`\n * https://github.com/remix-run/react-router/blob/462bb712156a3f739d6139a0f14810b76b002df6/packages/router/utils.ts#L1038\n */\nexport function stripBasenameFromPathname(pathname: string, basename: string): string {\n if (!basename || basename === '/') {\n return pathname;\n }\n\n if (!pathname.toLowerCase().startsWith(basename.toLowerCase())) {\n return pathname;\n }\n\n // We want to leave trailing slash behavior in the user's control, so if they\n // specify a basename with a trailing slash, we should support it\n const startIndex = basename.endsWith('/') ? basename.length - 1 : basename.length;\n const nextChar = pathname.charAt(startIndex);\n if (nextChar && nextChar !== '/') {\n // pathname does not start with basename/\n return pathname;\n }\n\n return pathname.slice(startIndex) || '/';\n}\n\n// Cache for sorted manifests - keyed by manifest array reference\nconst SORTED_MANIFEST_CACHE = new WeakMap<string[], string[]>();\n\n/**\n * Matches a pathname against a route manifest and returns the matching pattern.\n * Optionally strips a basename prefix before matching.\n */\nexport function matchRouteManifest(pathname: string, manifest: string[], basename?: string): string | null {\n if (!pathname || !manifest?.length) {\n return null;\n }\n\n const normalizedPathname = basename ? stripBasenameFromPathname(pathname, basename) : pathname;\n\n let sorted = SORTED_MANIFEST_CACHE.get(manifest);\n if (!sorted) {\n sorted = sortBySpecificity(manifest);\n SORTED_MANIFEST_CACHE.set(manifest, sorted);\n DEBUG_BUILD && debug.log('[React Router] Sorted route manifest by specificity:', sorted.length, 'patterns');\n }\n\n for (const pattern of sorted) {\n if (matchesPattern(normalizedPathname, pattern)) {\n DEBUG_BUILD && debug.log('[React Router] Matched pathname', normalizedPathname, 'to pattern', pattern);\n return pattern;\n }\n }\n\n DEBUG_BUILD && debug.log('[React Router] No manifest match found for pathname:', normalizedPathname);\n return null;\n}\n\n/**\n * Checks if a pathname matches a route pattern.\n */\nfunction matchesPattern(pathname: string, pattern: string): boolean {\n // Handle root path special case\n if (pattern === '/') {\n return pathname === '/' || pathname === '';\n }\n\n const pathSegments = splitPath(pathname);\n const patternSegments = splitPath(pattern);\n\n // Handle wildcard at end\n const hasWildcard = patternSegments.length > 0 && patternSegments[patternSegments.length - 1] === '*';\n\n if (hasWildcard) {\n // Pattern with wildcard: path must have at least as many segments as pattern (minus wildcard)\n const patternSegmentsWithoutWildcard = patternSegments.slice(0, -1);\n if (pathSegments.length < patternSegmentsWithoutWildcard.length) {\n return false;\n }\n for (const [i, patternSegment] of patternSegmentsWithoutWildcard.entries()) {\n if (!segmentMatches(pathSegments[i], patternSegment)) {\n return false;\n }\n }\n return true;\n }\n\n // Exact segment count match required\n if (pathSegments.length !== patternSegments.length) {\n return false;\n }\n\n for (const [i, patternSegment] of patternSegments.entries()) {\n if (!segmentMatches(pathSegments[i], patternSegment)) {\n return false;\n }\n }\n\n return true;\n}\n\n/**\n * Checks if a path segment matches a pattern segment.\n */\nfunction segmentMatches(pathSegment: string | undefined, patternSegment: string | undefined): boolean {\n if (pathSegment === undefined || patternSegment === undefined) {\n return false;\n }\n // Parameter matches anything\n if (PARAM_RE.test(patternSegment)) {\n return true;\n }\n // Literal must match exactly\n return pathSegment === patternSegment;\n}\n\n/**\n * Splits a path into segments, filtering out empty strings.\n */\nfunction splitPath(path: string): string[] {\n return path.split('/').filter(Boolean);\n}\n\n/**\n * React Router scoring weights and param detection.\n * https://github.com/remix-run/react-router/blob/main/packages/react-router/lib/router/utils.ts\n */\nconst PARAM_RE = /^:[\\w-]+$/;\nconst STATIC_SEGMENT_SCORE = 10;\nconst DYNAMIC_SEGMENT_SCORE = 3;\nconst EMPTY_SEGMENT_SCORE = 1;\nconst SPLAT_PENALTY = -2;\n\n/**\n * Computes a specificity score for a route pattern.\n * Matches React Router's computeScore() algorithm exactly.\n */\nfunction computeScore(pattern: string): number {\n const segments = pattern.split('/');\n\n // Base score is segment count (including empty segment from leading slash)\n let score = segments.length;\n\n // Apply splat penalty once if pattern contains wildcard\n if (segments.includes('*')) {\n score += SPLAT_PENALTY;\n }\n\n for (const segment of segments) {\n if (segment === '*') {\n // Splat penalty already applied globally above\n continue;\n } else if (PARAM_RE.test(segment)) {\n score += DYNAMIC_SEGMENT_SCORE;\n } else if (segment === '') {\n score += EMPTY_SEGMENT_SCORE;\n } else {\n score += STATIC_SEGMENT_SCORE;\n }\n }\n\n return score;\n}\n\n/**\n * Sorts route patterns by specificity (most specific first).\n * Implements React Router's ranking algorithm from computeScore():\n * https://github.com/remix-run/react-router/blob/main/packages/react-router/lib/router/utils.ts\n *\n * React Router scoring: base=segments.length, static=+10, dynamic=+3, empty=+1, splat=-2 (once)\n * Higher score = more specific pattern.\n * Equal scores preserve manifest order (same as React Router).\n *\n * Note: Users should order their manifest from most specific to least specific\n * when patterns have equal specificity (e.g., `/users/:id/settings` and `/:type/123/settings`).\n */\nfunction sortBySpecificity(manifest: string[]): string[] {\n return [...manifest].sort((a, b) => {\n const aScore = computeScore(a);\n const bScore = computeScore(b);\n\n return bScore - aScore;\n });\n}\n"],"names":["DEBUG_BUILD","debug"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"route-manifest.js","sources":["../../../src/reactrouter-compat-utils/route-manifest.ts"],"sourcesContent":["import { debug } from '@sentry/core/browser';\nimport { DEBUG_BUILD } from '../debug-build';\n\n/**\n * Strip the basename from a pathname if exists.\n *\n * Vendored and modified from `react-router`\n * https://github.com/remix-run/react-router/blob/462bb712156a3f739d6139a0f14810b76b002df6/packages/router/utils.ts#L1038\n */\nexport function stripBasenameFromPathname(pathname: string, basename: string): string {\n if (!basename || basename === '/') {\n return pathname;\n }\n\n if (!pathname.toLowerCase().startsWith(basename.toLowerCase())) {\n return pathname;\n }\n\n // We want to leave trailing slash behavior in the user's control, so if they\n // specify a basename with a trailing slash, we should support it\n const startIndex = basename.endsWith('/') ? basename.length - 1 : basename.length;\n const nextChar = pathname.charAt(startIndex);\n if (nextChar && nextChar !== '/') {\n // pathname does not start with basename/\n return pathname;\n }\n\n return pathname.slice(startIndex) || '/';\n}\n\n// Cache for sorted manifests - keyed by manifest array reference\nconst SORTED_MANIFEST_CACHE = new WeakMap<string[], string[]>();\n\n/**\n * Matches a pathname against a route manifest and returns the matching pattern.\n * Optionally strips a basename prefix before matching.\n */\nexport function matchRouteManifest(pathname: string, manifest: string[], basename?: string): string | null {\n if (!pathname || !manifest?.length) {\n return null;\n }\n\n const normalizedPathname = basename ? stripBasenameFromPathname(pathname, basename) : pathname;\n\n let sorted = SORTED_MANIFEST_CACHE.get(manifest);\n if (!sorted) {\n sorted = sortBySpecificity(manifest);\n SORTED_MANIFEST_CACHE.set(manifest, sorted);\n DEBUG_BUILD && debug.log('[React Router] Sorted route manifest by specificity:', sorted.length, 'patterns');\n }\n\n for (const pattern of sorted) {\n if (matchesPattern(normalizedPathname, pattern)) {\n DEBUG_BUILD && debug.log('[React Router] Matched pathname', normalizedPathname, 'to pattern', pattern);\n return pattern;\n }\n }\n\n DEBUG_BUILD && debug.log('[React Router] No manifest match found for pathname:', normalizedPathname);\n return null;\n}\n\n/**\n * Checks if a pathname matches a route pattern.\n */\nfunction matchesPattern(pathname: string, pattern: string): boolean {\n // Handle root path special case\n if (pattern === '/') {\n return pathname === '/' || pathname === '';\n }\n\n const pathSegments = splitPath(pathname);\n const patternSegments = splitPath(pattern);\n\n // Handle wildcard at end\n const hasWildcard = patternSegments.length > 0 && patternSegments[patternSegments.length - 1] === '*';\n\n if (hasWildcard) {\n // Pattern with wildcard: path must have at least as many segments as pattern (minus wildcard)\n const patternSegmentsWithoutWildcard = patternSegments.slice(0, -1);\n if (pathSegments.length < patternSegmentsWithoutWildcard.length) {\n return false;\n }\n for (const [i, patternSegment] of patternSegmentsWithoutWildcard.entries()) {\n if (!segmentMatches(pathSegments[i], patternSegment)) {\n return false;\n }\n }\n return true;\n }\n\n // Exact segment count match required\n if (pathSegments.length !== patternSegments.length) {\n return false;\n }\n\n for (const [i, patternSegment] of patternSegments.entries()) {\n if (!segmentMatches(pathSegments[i], patternSegment)) {\n return false;\n }\n }\n\n return true;\n}\n\n/**\n * Checks if a path segment matches a pattern segment.\n */\nfunction segmentMatches(pathSegment: string | undefined, patternSegment: string | undefined): boolean {\n if (pathSegment === undefined || patternSegment === undefined) {\n return false;\n }\n // Parameter matches anything\n if (PARAM_RE.test(patternSegment)) {\n return true;\n }\n // Literal must match exactly\n return pathSegment === patternSegment;\n}\n\n/**\n * Splits a path into segments, filtering out empty strings.\n */\nfunction splitPath(path: string): string[] {\n return path.split('/').filter(Boolean);\n}\n\n/**\n * React Router scoring weights and param detection.\n * https://github.com/remix-run/react-router/blob/main/packages/react-router/lib/router/utils.ts\n */\nconst PARAM_RE = /^:[\\w-]+$/;\nconst STATIC_SEGMENT_SCORE = 10;\nconst DYNAMIC_SEGMENT_SCORE = 3;\nconst EMPTY_SEGMENT_SCORE = 1;\nconst SPLAT_PENALTY = -2;\n\n/**\n * Computes a specificity score for a route pattern.\n * Matches React Router's computeScore() algorithm exactly.\n */\nfunction computeScore(pattern: string): number {\n const segments = pattern.split('/');\n\n // Base score is segment count (including empty segment from leading slash)\n let score = segments.length;\n\n // Apply splat penalty once if pattern contains wildcard\n if (segments.includes('*')) {\n score += SPLAT_PENALTY;\n }\n\n for (const segment of segments) {\n if (segment === '*') {\n // Splat penalty already applied globally above\n continue;\n } else if (PARAM_RE.test(segment)) {\n score += DYNAMIC_SEGMENT_SCORE;\n } else if (segment === '') {\n score += EMPTY_SEGMENT_SCORE;\n } else {\n score += STATIC_SEGMENT_SCORE;\n }\n }\n\n return score;\n}\n\n/**\n * Sorts route patterns by specificity (most specific first).\n * Implements React Router's ranking algorithm from computeScore():\n * https://github.com/remix-run/react-router/blob/main/packages/react-router/lib/router/utils.ts\n *\n * React Router scoring: base=segments.length, static=+10, dynamic=+3, empty=+1, splat=-2 (once)\n * Higher score = more specific pattern.\n * Equal scores preserve manifest order (same as React Router).\n *\n * Note: Users should order their manifest from most specific to least specific\n * when patterns have equal specificity (e.g., `/users/:id/settings` and `/:type/123/settings`).\n */\nfunction sortBySpecificity(manifest: string[]): string[] {\n return [...manifest].sort((a, b) => {\n const aScore = computeScore(a);\n const bScore = computeScore(b);\n\n return bScore - aScore;\n });\n}\n"],"names":["DEBUG_BUILD","debug"],"mappings":"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"}
|
|
@@ -4,183 +4,102 @@ const browser = require('@sentry/core/browser');
|
|
|
4
4
|
const debugBuild = require('../debug-build.js');
|
|
5
5
|
const routeManifest = require('./route-manifest.js');
|
|
6
6
|
|
|
7
|
-
// Global variables that these utilities depend on
|
|
8
7
|
let _matchRoutes;
|
|
9
8
|
let _stripBasename = false;
|
|
10
|
-
|
|
11
|
-
// Navigation context stack for nested/concurrent patchRoutesOnNavigation calls.
|
|
12
|
-
// Required because window.location hasn't updated yet when handlers are invoked.
|
|
13
|
-
|
|
14
9
|
const _navigationContextStack = [];
|
|
15
10
|
const MAX_CONTEXT_STACK_SIZE = 10;
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* Pushes a navigation context and returns a unique token for cleanup.
|
|
19
|
-
* The token uses object identity for uniqueness (no counter needed).
|
|
20
|
-
*/
|
|
21
11
|
function setNavigationContext(targetPath, span) {
|
|
22
12
|
const token = {};
|
|
23
|
-
// Prevent unbounded stack growth - oldest (likely stale) contexts are evicted first
|
|
24
13
|
if (_navigationContextStack.length >= MAX_CONTEXT_STACK_SIZE) {
|
|
25
|
-
debugBuild.DEBUG_BUILD && browser.debug.warn(
|
|
14
|
+
debugBuild.DEBUG_BUILD && browser.debug.warn("[React Router] Navigation context stack overflow - removing oldest context");
|
|
26
15
|
_navigationContextStack.shift();
|
|
27
16
|
}
|
|
28
17
|
_navigationContextStack.push({ token, targetPath, span });
|
|
29
18
|
return token;
|
|
30
19
|
}
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Clears the navigation context if it's on top of the stack (LIFO).
|
|
34
|
-
* If our context is not on top (out-of-order completion), we leave it -
|
|
35
|
-
* it will be cleaned up by overflow protection when the stack fills up.
|
|
36
|
-
*/
|
|
37
20
|
function clearNavigationContext(token) {
|
|
38
21
|
const top = _navigationContextStack[_navigationContextStack.length - 1];
|
|
39
22
|
if (top?.token === token) {
|
|
40
23
|
_navigationContextStack.pop();
|
|
41
24
|
}
|
|
42
25
|
}
|
|
43
|
-
|
|
44
|
-
/** Gets the current (most recent) navigation context if inside a patchRoutesOnNavigation call. */
|
|
45
26
|
function getNavigationContext() {
|
|
46
27
|
const length = _navigationContextStack.length;
|
|
47
|
-
|
|
48
|
-
return length > 0 ? (_navigationContextStack[length - 1] ?? null) : null;
|
|
28
|
+
return length > 0 ? _navigationContextStack[length - 1] ?? null : null;
|
|
49
29
|
}
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* Initialize function to set dependencies that the router utilities need.
|
|
53
|
-
* Must be called before using any of the exported utility functions.
|
|
54
|
-
*/
|
|
55
30
|
function initializeRouterUtils(matchRoutes, stripBasename = false) {
|
|
56
31
|
_matchRoutes = matchRoutes;
|
|
57
32
|
_stripBasename = stripBasename;
|
|
58
33
|
}
|
|
59
|
-
|
|
60
|
-
// Helper functions
|
|
61
34
|
function pickPath(match) {
|
|
62
|
-
return trimWildcard(match.route.path ||
|
|
35
|
+
return trimWildcard(match.route.path || "");
|
|
63
36
|
}
|
|
64
|
-
|
|
65
37
|
function pickSplat(match) {
|
|
66
|
-
return match.params[
|
|
38
|
+
return match.params["*"] || "";
|
|
67
39
|
}
|
|
68
|
-
|
|
69
40
|
function trimWildcard(path) {
|
|
70
|
-
return path[path.length - 1] ===
|
|
41
|
+
return path[path.length - 1] === "*" ? path.slice(0, -1) : path;
|
|
71
42
|
}
|
|
72
|
-
|
|
73
43
|
function trimSlash(path) {
|
|
74
|
-
return path[path.length - 1] ===
|
|
44
|
+
return path[path.length - 1] === "/" ? path.slice(0, -1) : path;
|
|
75
45
|
}
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* Checks if a path ends with a wildcard character (*).
|
|
79
|
-
*/
|
|
80
46
|
function pathEndsWithWildcard(path) {
|
|
81
|
-
return path.endsWith(
|
|
47
|
+
return path.endsWith("*");
|
|
82
48
|
}
|
|
83
|
-
|
|
84
|
-
/** Checks if transaction name has wildcard (/* or ends with *). */
|
|
85
49
|
function transactionNameHasWildcard(name) {
|
|
86
|
-
return name.includes(
|
|
50
|
+
return name.includes("/*") || name.endsWith("*");
|
|
87
51
|
}
|
|
88
|
-
|
|
89
|
-
/**
|
|
90
|
-
* Checks if a path is a wildcard and has child routes.
|
|
91
|
-
*/
|
|
92
52
|
function pathIsWildcardAndHasChildren(path, branch) {
|
|
93
|
-
return
|
|
53
|
+
return pathEndsWithWildcard(path) && !!branch.route.children?.length || false;
|
|
94
54
|
}
|
|
95
|
-
|
|
96
|
-
/** Check if route is in descendant route (<Routes> within <Routes>) */
|
|
97
55
|
function routeIsDescendant(route) {
|
|
98
|
-
return !!(!route.children && route.element && route.path?.endsWith(
|
|
56
|
+
return !!(!route.children && route.element && route.path?.endsWith("/*"));
|
|
99
57
|
}
|
|
100
|
-
|
|
101
58
|
function sendIndexPath(pathBuilder, pathname, basename) {
|
|
102
|
-
const reconstructedPath =
|
|
103
|
-
|
|
104
|
-
? pathBuilder
|
|
105
|
-
: _stripBasename
|
|
106
|
-
? routeManifest.stripBasenameFromPathname(pathname, basename)
|
|
107
|
-
: pathname;
|
|
108
|
-
|
|
109
|
-
let formattedPath =
|
|
59
|
+
const reconstructedPath = pathBuilder && pathBuilder.length > 0 ? pathBuilder : _stripBasename ? routeManifest.stripBasenameFromPathname(pathname, basename) : pathname;
|
|
60
|
+
let formattedPath = (
|
|
110
61
|
// If the path ends with a wildcard suffix, remove both the slash and the asterisk
|
|
111
|
-
reconstructedPath.slice(-2) ===
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
if (formattedPath.length > 1 && formattedPath[formattedPath.length - 1] === '/') {
|
|
62
|
+
reconstructedPath.slice(-2) === "/*" ? reconstructedPath.slice(0, -2) : reconstructedPath
|
|
63
|
+
);
|
|
64
|
+
if (formattedPath.length > 1 && formattedPath[formattedPath.length - 1] === "/") {
|
|
115
65
|
formattedPath = formattedPath.slice(0, -1);
|
|
116
66
|
}
|
|
117
|
-
|
|
118
|
-
return [formattedPath, 'route'];
|
|
67
|
+
return [formattedPath, "route"];
|
|
119
68
|
}
|
|
120
|
-
|
|
121
|
-
/**
|
|
122
|
-
* Returns the number of URL segments in the given URL string.
|
|
123
|
-
* Splits at '/' or '\/' to handle regex URLs correctly.
|
|
124
|
-
*
|
|
125
|
-
* @param url - The URL string to segment.
|
|
126
|
-
* @returns The number of segments in the URL.
|
|
127
|
-
*/
|
|
128
69
|
function getNumberOfUrlSegments(url) {
|
|
129
|
-
|
|
130
|
-
return url.split(/\\?\//).filter(s => s.length > 0 && s !== ',').length;
|
|
70
|
+
return url.split(/\\?\//).filter((s) => s.length > 0 && s !== ",").length;
|
|
131
71
|
}
|
|
132
|
-
|
|
133
|
-
// Exported utility functions
|
|
134
|
-
|
|
135
|
-
/**
|
|
136
|
-
* Ensures a path string starts with a forward slash.
|
|
137
|
-
*/
|
|
138
72
|
function prefixWithSlash(path) {
|
|
139
|
-
return path[0] ===
|
|
73
|
+
return path[0] === "/" ? path : `/${path}`;
|
|
140
74
|
}
|
|
141
|
-
|
|
142
|
-
/**
|
|
143
|
-
* Rebuilds the route path from all available routes by matching against the current location.
|
|
144
|
-
*/
|
|
145
75
|
function rebuildRoutePathFromAllRoutes(allRoutes, location) {
|
|
146
|
-
const matchedRoutes = _matchRoutes(allRoutes, location)
|
|
147
|
-
|
|
76
|
+
const matchedRoutes = _matchRoutes(allRoutes, location);
|
|
148
77
|
if (!matchedRoutes || matchedRoutes.length === 0) {
|
|
149
|
-
return
|
|
78
|
+
return "";
|
|
150
79
|
}
|
|
151
|
-
|
|
152
80
|
for (const match of matchedRoutes) {
|
|
153
|
-
if (match.route.path && match.route.path !==
|
|
81
|
+
if (match.route.path && match.route.path !== "*") {
|
|
154
82
|
const path = pickPath(match);
|
|
155
83
|
const strippedPath = routeManifest.stripBasenameFromPathname(location.pathname, prefixWithSlash(match.pathnameBase));
|
|
156
|
-
|
|
157
84
|
if (location.pathname === strippedPath) {
|
|
158
85
|
return trimSlash(strippedPath);
|
|
159
86
|
}
|
|
160
|
-
|
|
161
87
|
return trimSlash(
|
|
162
|
-
trimSlash(path ||
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
),
|
|
88
|
+
trimSlash(path || "") + prefixWithSlash(
|
|
89
|
+
rebuildRoutePathFromAllRoutes(
|
|
90
|
+
allRoutes.filter((route) => route !== match.route),
|
|
91
|
+
{
|
|
92
|
+
pathname: strippedPath
|
|
93
|
+
}
|
|
94
|
+
)
|
|
95
|
+
)
|
|
171
96
|
);
|
|
172
97
|
}
|
|
173
98
|
}
|
|
174
|
-
|
|
175
|
-
return '';
|
|
99
|
+
return "";
|
|
176
100
|
}
|
|
177
|
-
|
|
178
|
-
/**
|
|
179
|
-
* Checks if the current location is inside a descendant route (route with splat parameter).
|
|
180
|
-
*/
|
|
181
101
|
function locationIsInsideDescendantRoute(location, routes) {
|
|
182
|
-
const matchedRoutes = _matchRoutes(routes, location)
|
|
183
|
-
|
|
102
|
+
const matchedRoutes = _matchRoutes(routes, location);
|
|
184
103
|
if (matchedRoutes) {
|
|
185
104
|
for (const match of matchedRoutes) {
|
|
186
105
|
if (routeIsDescendant(match.route) && pickSplat(match)) {
|
|
@@ -188,134 +107,73 @@ function locationIsInsideDescendantRoute(location, routes) {
|
|
|
188
107
|
}
|
|
189
108
|
}
|
|
190
109
|
}
|
|
191
|
-
|
|
192
110
|
return false;
|
|
193
111
|
}
|
|
194
|
-
|
|
195
|
-
/**
|
|
196
|
-
* Returns a fallback transaction name from location pathname.
|
|
197
|
-
*/
|
|
198
112
|
function getFallbackTransactionName(location, basename) {
|
|
199
|
-
return _stripBasename ? routeManifest.stripBasenameFromPathname(location.pathname, basename) : location.pathname ||
|
|
113
|
+
return _stripBasename ? routeManifest.stripBasenameFromPathname(location.pathname, basename) : location.pathname || "";
|
|
200
114
|
}
|
|
201
|
-
|
|
202
|
-
/**
|
|
203
|
-
* Gets a normalized route name and transaction source from the current routes and location.
|
|
204
|
-
*/
|
|
205
|
-
function getNormalizedName(
|
|
206
|
-
routes,
|
|
207
|
-
location,
|
|
208
|
-
branches,
|
|
209
|
-
basename = '',
|
|
210
|
-
) {
|
|
115
|
+
function getNormalizedName(routes, location, branches, basename = "") {
|
|
211
116
|
if (!routes || routes.length === 0) {
|
|
212
|
-
return [_stripBasename ? routeManifest.stripBasenameFromPathname(location.pathname, basename) : location.pathname,
|
|
117
|
+
return [_stripBasename ? routeManifest.stripBasenameFromPathname(location.pathname, basename) : location.pathname, "url"];
|
|
213
118
|
}
|
|
214
|
-
|
|
215
119
|
if (!branches) {
|
|
216
|
-
return [getFallbackTransactionName(location, basename),
|
|
120
|
+
return [getFallbackTransactionName(location, basename), "url"];
|
|
217
121
|
}
|
|
218
|
-
|
|
219
|
-
let pathBuilder = '';
|
|
220
|
-
|
|
122
|
+
let pathBuilder = "";
|
|
221
123
|
for (const branch of branches) {
|
|
222
124
|
const route = branch.route;
|
|
223
125
|
if (!route) {
|
|
224
126
|
continue;
|
|
225
127
|
}
|
|
226
|
-
|
|
227
|
-
// Early return for index routes
|
|
228
128
|
if (route.index) {
|
|
229
129
|
return sendIndexPath(pathBuilder, branch.pathname, basename);
|
|
230
130
|
}
|
|
231
|
-
|
|
232
131
|
const path = route.path;
|
|
233
132
|
if (!path || pathIsWildcardAndHasChildren(path, branch)) {
|
|
234
133
|
continue;
|
|
235
134
|
}
|
|
236
|
-
|
|
237
|
-
// Build the route path
|
|
238
|
-
const newPath = path[0] === '/' || pathBuilder[pathBuilder.length - 1] === '/' ? path : `/${path}`;
|
|
135
|
+
const newPath = path[0] === "/" || pathBuilder[pathBuilder.length - 1] === "/" ? path : `/${path}`;
|
|
239
136
|
pathBuilder = trimSlash(pathBuilder) + prefixWithSlash(newPath);
|
|
240
|
-
|
|
241
|
-
// Check if this path matches the current location
|
|
242
137
|
if (trimSlash(location.pathname) !== trimSlash(basename + branch.pathname)) {
|
|
243
138
|
continue;
|
|
244
139
|
}
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
if (
|
|
248
|
-
getNumberOfUrlSegments(pathBuilder) !== getNumberOfUrlSegments(branch.pathname) &&
|
|
249
|
-
!pathEndsWithWildcard(pathBuilder)
|
|
250
|
-
) {
|
|
251
|
-
return [(_stripBasename ? '' : basename) + newPath, 'route'];
|
|
140
|
+
if (getNumberOfUrlSegments(pathBuilder) !== getNumberOfUrlSegments(branch.pathname) && !pathEndsWithWildcard(pathBuilder)) {
|
|
141
|
+
return [(_stripBasename ? "" : basename) + newPath, "route"];
|
|
252
142
|
}
|
|
253
|
-
|
|
254
|
-
// Handle wildcard routes with children - strip trailing wildcard
|
|
255
143
|
if (pathIsWildcardAndHasChildren(pathBuilder, branch)) {
|
|
256
144
|
pathBuilder = pathBuilder.slice(0, -1);
|
|
257
145
|
}
|
|
258
|
-
|
|
259
|
-
return [(_stripBasename ? '' : basename) + pathBuilder, 'route'];
|
|
146
|
+
return [(_stripBasename ? "" : basename) + pathBuilder, "route"];
|
|
260
147
|
}
|
|
261
|
-
|
|
262
|
-
// Fallback when no matching route found
|
|
263
|
-
return [getFallbackTransactionName(location, basename), 'url'];
|
|
148
|
+
return [getFallbackTransactionName(location, basename), "url"];
|
|
264
149
|
}
|
|
265
|
-
|
|
266
|
-
/**
|
|
267
|
-
* Shared helper function to resolve route name and source
|
|
268
|
-
*/
|
|
269
|
-
function resolveRouteNameAndSource(
|
|
270
|
-
location,
|
|
271
|
-
routes,
|
|
272
|
-
allRoutes,
|
|
273
|
-
branches,
|
|
274
|
-
basename = '',
|
|
275
|
-
lazyRouteManifest,
|
|
276
|
-
enableAsyncRouteHandlers,
|
|
277
|
-
) {
|
|
278
|
-
// When lazy route manifest is provided, use it as the primary source for transaction names
|
|
150
|
+
function resolveRouteNameAndSource(location, routes, allRoutes, branches, basename = "", lazyRouteManifest, enableAsyncRouteHandlers) {
|
|
279
151
|
if (enableAsyncRouteHandlers && lazyRouteManifest && lazyRouteManifest.length > 0) {
|
|
280
152
|
const manifestMatch = routeManifest.matchRouteManifest(location.pathname, lazyRouteManifest, basename);
|
|
281
153
|
if (manifestMatch) {
|
|
282
|
-
return [(_stripBasename ?
|
|
154
|
+
return [(_stripBasename ? "" : basename) + manifestMatch, "route"];
|
|
283
155
|
}
|
|
284
156
|
}
|
|
285
|
-
|
|
286
|
-
// Fall back to React Router route matching
|
|
287
157
|
let name;
|
|
288
|
-
let source =
|
|
289
|
-
|
|
158
|
+
let source = "url";
|
|
290
159
|
const isInDescendantRoute = locationIsInsideDescendantRoute(location, allRoutes);
|
|
291
|
-
|
|
292
160
|
if (isInDescendantRoute) {
|
|
293
161
|
name = prefixWithSlash(rebuildRoutePathFromAllRoutes(allRoutes, location));
|
|
294
|
-
source =
|
|
162
|
+
source = "route";
|
|
295
163
|
}
|
|
296
|
-
|
|
297
164
|
if (!isInDescendantRoute || !name) {
|
|
298
165
|
[name, source] = getNormalizedName(routes, location, branches, basename);
|
|
299
166
|
}
|
|
300
|
-
|
|
301
167
|
return [name || location.pathname, source];
|
|
302
168
|
}
|
|
303
|
-
|
|
304
|
-
/**
|
|
305
|
-
* Gets the active root span if it's a pageload or navigation span.
|
|
306
|
-
*/
|
|
307
169
|
function getActiveRootSpan() {
|
|
308
170
|
const span = browser.getActiveSpan();
|
|
309
|
-
const rootSpan = span ? browser.getRootSpan(span) :
|
|
310
|
-
|
|
171
|
+
const rootSpan = span ? browser.getRootSpan(span) : void 0;
|
|
311
172
|
if (!rootSpan) {
|
|
312
|
-
return
|
|
173
|
+
return void 0;
|
|
313
174
|
}
|
|
314
|
-
|
|
315
175
|
const op = browser.spanToJSON(rootSpan).op;
|
|
316
|
-
|
|
317
|
-
// Only use this root span if it is a pageload or navigation span
|
|
318
|
-
return op === 'navigation' || op === 'pageload' ? rootSpan : undefined;
|
|
176
|
+
return op === "navigation" || op === "pageload" ? rootSpan : void 0;
|
|
319
177
|
}
|
|
320
178
|
|
|
321
179
|
exports.clearNavigationContext = clearNavigationContext;
|