UNPKG

309 kBJavaScriptView Raw
1/**
2 * react-router v7.0.1
3 *
4 * Copyright (c) Remix Software Inc.
5 *
6 * This source code is licensed under the MIT license found in the
7 * LICENSE.md file in the root directory of this source tree.
8 *
9 * @license MIT
10 */
11
12// lib/router/history.ts
13var Action = /* @__PURE__ */ ((Action2) => {
14 Action2["Pop"] = "POP";
15 Action2["Push"] = "PUSH";
16 Action2["Replace"] = "REPLACE";
17 return Action2;
18})(Action || {});
19var PopStateEventType = "popstate";
20function createMemoryHistory(options = {}) {
21 let { initialEntries = ["/"], initialIndex, v5Compat = false } = options;
22 let entries;
23 entries = initialEntries.map(
24 (entry, index2) => createMemoryLocation(
25 entry,
26 typeof entry === "string" ? null : entry.state,
27 index2 === 0 ? "default" : void 0
28 )
29 );
30 let index = clampIndex(
31 initialIndex == null ? entries.length - 1 : initialIndex
32 );
33 let action = "POP" /* Pop */;
34 let listener = null;
35 function clampIndex(n) {
36 return Math.min(Math.max(n, 0), entries.length - 1);
37 }
38 function getCurrentLocation() {
39 return entries[index];
40 }
41 function createMemoryLocation(to, state = null, key) {
42 let location = createLocation(
43 entries ? getCurrentLocation().pathname : "/",
44 to,
45 state,
46 key
47 );
48 warning(
49 location.pathname.charAt(0) === "/",
50 `relative pathnames are not supported in memory history: ${JSON.stringify(
51 to
52 )}`
53 );
54 return location;
55 }
56 function createHref2(to) {
57 return typeof to === "string" ? to : createPath(to);
58 }
59 let history = {
60 get index() {
61 return index;
62 },
63 get action() {
64 return action;
65 },
66 get location() {
67 return getCurrentLocation();
68 },
69 createHref: createHref2,
70 createURL(to) {
71 return new URL(createHref2(to), "http://localhost");
72 },
73 encodeLocation(to) {
74 let path = typeof to === "string" ? parsePath(to) : to;
75 return {
76 pathname: path.pathname || "",
77 search: path.search || "",
78 hash: path.hash || ""
79 };
80 },
81 push(to, state) {
82 action = "PUSH" /* Push */;
83 let nextLocation = createMemoryLocation(to, state);
84 index += 1;
85 entries.splice(index, entries.length, nextLocation);
86 if (v5Compat && listener) {
87 listener({ action, location: nextLocation, delta: 1 });
88 }
89 },
90 replace(to, state) {
91 action = "REPLACE" /* Replace */;
92 let nextLocation = createMemoryLocation(to, state);
93 entries[index] = nextLocation;
94 if (v5Compat && listener) {
95 listener({ action, location: nextLocation, delta: 0 });
96 }
97 },
98 go(delta) {
99 action = "POP" /* Pop */;
100 let nextIndex = clampIndex(index + delta);
101 let nextLocation = entries[nextIndex];
102 index = nextIndex;
103 if (listener) {
104 listener({ action, location: nextLocation, delta });
105 }
106 },
107 listen(fn) {
108 listener = fn;
109 return () => {
110 listener = null;
111 };
112 }
113 };
114 return history;
115}
116function createBrowserHistory(options = {}) {
117 function createBrowserLocation(window2, globalHistory) {
118 let { pathname, search, hash } = window2.location;
119 return createLocation(
120 "",
121 { pathname, search, hash },
122 // state defaults to `null` because `window.history.state` does
123 globalHistory.state && globalHistory.state.usr || null,
124 globalHistory.state && globalHistory.state.key || "default"
125 );
126 }
127 function createBrowserHref(window2, to) {
128 return typeof to === "string" ? to : createPath(to);
129 }
130 return getUrlBasedHistory(
131 createBrowserLocation,
132 createBrowserHref,
133 null,
134 options
135 );
136}
137function createHashHistory(options = {}) {
138 function createHashLocation(window2, globalHistory) {
139 let {
140 pathname = "/",
141 search = "",
142 hash = ""
143 } = parsePath(window2.location.hash.substring(1));
144 if (!pathname.startsWith("/") && !pathname.startsWith(".")) {
145 pathname = "/" + pathname;
146 }
147 return createLocation(
148 "",
149 { pathname, search, hash },
150 // state defaults to `null` because `window.history.state` does
151 globalHistory.state && globalHistory.state.usr || null,
152 globalHistory.state && globalHistory.state.key || "default"
153 );
154 }
155 function createHashHref(window2, to) {
156 let base = window2.document.querySelector("base");
157 let href = "";
158 if (base && base.getAttribute("href")) {
159 let url = window2.location.href;
160 let hashIndex = url.indexOf("#");
161 href = hashIndex === -1 ? url : url.slice(0, hashIndex);
162 }
163 return href + "#" + (typeof to === "string" ? to : createPath(to));
164 }
165 function validateHashLocation(location, to) {
166 warning(
167 location.pathname.charAt(0) === "/",
168 `relative pathnames are not supported in hash history.push(${JSON.stringify(
169 to
170 )})`
171 );
172 }
173 return getUrlBasedHistory(
174 createHashLocation,
175 createHashHref,
176 validateHashLocation,
177 options
178 );
179}
180function invariant(value, message) {
181 if (value === false || value === null || typeof value === "undefined") {
182 throw new Error(message);
183 }
184}
185function warning(cond, message) {
186 if (!cond) {
187 if (typeof console !== "undefined") console.warn(message);
188 try {
189 throw new Error(message);
190 } catch (e) {
191 }
192 }
193}
194function createKey() {
195 return Math.random().toString(36).substring(2, 10);
196}
197function getHistoryState(location, index) {
198 return {
199 usr: location.state,
200 key: location.key,
201 idx: index
202 };
203}
204function createLocation(current, to, state = null, key) {
205 let location = {
206 pathname: typeof current === "string" ? current : current.pathname,
207 search: "",
208 hash: "",
209 ...typeof to === "string" ? parsePath(to) : to,
210 state,
211 // TODO: This could be cleaned up. push/replace should probably just take
212 // full Locations now and avoid the need to run through this flow at all
213 // But that's a pretty big refactor to the current test suite so going to
214 // keep as is for the time being and just let any incoming keys take precedence
215 key: to && to.key || key || createKey()
216 };
217 return location;
218}
219function createPath({
220 pathname = "/",
221 search = "",
222 hash = ""
223}) {
224 if (search && search !== "?")
225 pathname += search.charAt(0) === "?" ? search : "?" + search;
226 if (hash && hash !== "#")
227 pathname += hash.charAt(0) === "#" ? hash : "#" + hash;
228 return pathname;
229}
230function parsePath(path) {
231 let parsedPath = {};
232 if (path) {
233 let hashIndex = path.indexOf("#");
234 if (hashIndex >= 0) {
235 parsedPath.hash = path.substring(hashIndex);
236 path = path.substring(0, hashIndex);
237 }
238 let searchIndex = path.indexOf("?");
239 if (searchIndex >= 0) {
240 parsedPath.search = path.substring(searchIndex);
241 path = path.substring(0, searchIndex);
242 }
243 if (path) {
244 parsedPath.pathname = path;
245 }
246 }
247 return parsedPath;
248}
249function getUrlBasedHistory(getLocation, createHref2, validateLocation, options = {}) {
250 let { window: window2 = document.defaultView, v5Compat = false } = options;
251 let globalHistory = window2.history;
252 let action = "POP" /* Pop */;
253 let listener = null;
254 let index = getIndex();
255 if (index == null) {
256 index = 0;
257 globalHistory.replaceState({ ...globalHistory.state, idx: index }, "");
258 }
259 function getIndex() {
260 let state = globalHistory.state || { idx: null };
261 return state.idx;
262 }
263 function handlePop() {
264 action = "POP" /* Pop */;
265 let nextIndex = getIndex();
266 let delta = nextIndex == null ? null : nextIndex - index;
267 index = nextIndex;
268 if (listener) {
269 listener({ action, location: history.location, delta });
270 }
271 }
272 function push(to, state) {
273 action = "PUSH" /* Push */;
274 let location = createLocation(history.location, to, state);
275 if (validateLocation) validateLocation(location, to);
276 index = getIndex() + 1;
277 let historyState = getHistoryState(location, index);
278 let url = history.createHref(location);
279 try {
280 globalHistory.pushState(historyState, "", url);
281 } catch (error) {
282 if (error instanceof DOMException && error.name === "DataCloneError") {
283 throw error;
284 }
285 window2.location.assign(url);
286 }
287 if (v5Compat && listener) {
288 listener({ action, location: history.location, delta: 1 });
289 }
290 }
291 function replace2(to, state) {
292 action = "REPLACE" /* Replace */;
293 let location = createLocation(history.location, to, state);
294 if (validateLocation) validateLocation(location, to);
295 index = getIndex();
296 let historyState = getHistoryState(location, index);
297 let url = history.createHref(location);
298 globalHistory.replaceState(historyState, "", url);
299 if (v5Compat && listener) {
300 listener({ action, location: history.location, delta: 0 });
301 }
302 }
303 function createURL(to) {
304 let base = window2.location.origin !== "null" ? window2.location.origin : window2.location.href;
305 let href = typeof to === "string" ? to : createPath(to);
306 href = href.replace(/ $/, "%20");
307 invariant(
308 base,
309 `No window.location.(origin|href) available to create URL for href: ${href}`
310 );
311 return new URL(href, base);
312 }
313 let history = {
314 get action() {
315 return action;
316 },
317 get location() {
318 return getLocation(window2, globalHistory);
319 },
320 listen(fn) {
321 if (listener) {
322 throw new Error("A history only accepts one active listener");
323 }
324 window2.addEventListener(PopStateEventType, handlePop);
325 listener = fn;
326 return () => {
327 window2.removeEventListener(PopStateEventType, handlePop);
328 listener = null;
329 };
330 },
331 createHref(to) {
332 return createHref2(window2, to);
333 },
334 createURL,
335 encodeLocation(to) {
336 let url = createURL(to);
337 return {
338 pathname: url.pathname,
339 search: url.search,
340 hash: url.hash
341 };
342 },
343 push,
344 replace: replace2,
345 go(n) {
346 return globalHistory.go(n);
347 }
348 };
349 return history;
350}
351
352// lib/router/utils.ts
353var immutableRouteKeys = /* @__PURE__ */ new Set([
354 "lazy",
355 "caseSensitive",
356 "path",
357 "id",
358 "index",
359 "children"
360]);
361function isIndexRoute(route) {
362 return route.index === true;
363}
364function convertRoutesToDataRoutes(routes, mapRouteProperties2, parentPath = [], manifest = {}) {
365 return routes.map((route, index) => {
366 let treePath = [...parentPath, String(index)];
367 let id = typeof route.id === "string" ? route.id : treePath.join("-");
368 invariant(
369 route.index !== true || !route.children,
370 `Cannot specify children on an index route`
371 );
372 invariant(
373 !manifest[id],
374 `Found a route id collision on id "${id}". Route id's must be globally unique within Data Router usages`
375 );
376 if (isIndexRoute(route)) {
377 let indexRoute = {
378 ...route,
379 ...mapRouteProperties2(route),
380 id
381 };
382 manifest[id] = indexRoute;
383 return indexRoute;
384 } else {
385 let pathOrLayoutRoute = {
386 ...route,
387 ...mapRouteProperties2(route),
388 id,
389 children: void 0
390 };
391 manifest[id] = pathOrLayoutRoute;
392 if (route.children) {
393 pathOrLayoutRoute.children = convertRoutesToDataRoutes(
394 route.children,
395 mapRouteProperties2,
396 treePath,
397 manifest
398 );
399 }
400 return pathOrLayoutRoute;
401 }
402 });
403}
404function matchRoutes(routes, locationArg, basename = "/") {
405 return matchRoutesImpl(routes, locationArg, basename, false);
406}
407function matchRoutesImpl(routes, locationArg, basename, allowPartial) {
408 let location = typeof locationArg === "string" ? parsePath(locationArg) : locationArg;
409 let pathname = stripBasename(location.pathname || "/", basename);
410 if (pathname == null) {
411 return null;
412 }
413 let branches = flattenRoutes(routes);
414 rankRouteBranches(branches);
415 let matches = null;
416 for (let i = 0; matches == null && i < branches.length; ++i) {
417 let decoded = decodePath(pathname);
418 matches = matchRouteBranch(
419 branches[i],
420 decoded,
421 allowPartial
422 );
423 }
424 return matches;
425}
426function convertRouteMatchToUiMatch(match, loaderData) {
427 let { route, pathname, params } = match;
428 return {
429 id: route.id,
430 pathname,
431 params,
432 data: loaderData[route.id],
433 handle: route.handle
434 };
435}
436function flattenRoutes(routes, branches = [], parentsMeta = [], parentPath = "") {
437 let flattenRoute = (route, index, relativePath) => {
438 let meta = {
439 relativePath: relativePath === void 0 ? route.path || "" : relativePath,
440 caseSensitive: route.caseSensitive === true,
441 childrenIndex: index,
442 route
443 };
444 if (meta.relativePath.startsWith("/")) {
445 invariant(
446 meta.relativePath.startsWith(parentPath),
447 `Absolute route path "${meta.relativePath}" nested under path "${parentPath}" is not valid. An absolute child route path must start with the combined path of all its parent routes.`
448 );
449 meta.relativePath = meta.relativePath.slice(parentPath.length);
450 }
451 let path = joinPaths([parentPath, meta.relativePath]);
452 let routesMeta = parentsMeta.concat(meta);
453 if (route.children && route.children.length > 0) {
454 invariant(
455 // Our types know better, but runtime JS may not!
456 // @ts-expect-error
457 route.index !== true,
458 `Index routes must not have child routes. Please remove all child routes from route path "${path}".`
459 );
460 flattenRoutes(route.children, branches, routesMeta, path);
461 }
462 if (route.path == null && !route.index) {
463 return;
464 }
465 branches.push({
466 path,
467 score: computeScore(path, route.index),
468 routesMeta
469 });
470 };
471 routes.forEach((route, index) => {
472 if (route.path === "" || !route.path?.includes("?")) {
473 flattenRoute(route, index);
474 } else {
475 for (let exploded of explodeOptionalSegments(route.path)) {
476 flattenRoute(route, index, exploded);
477 }
478 }
479 });
480 return branches;
481}
482function explodeOptionalSegments(path) {
483 let segments = path.split("/");
484 if (segments.length === 0) return [];
485 let [first, ...rest] = segments;
486 let isOptional = first.endsWith("?");
487 let required = first.replace(/\?$/, "");
488 if (rest.length === 0) {
489 return isOptional ? [required, ""] : [required];
490 }
491 let restExploded = explodeOptionalSegments(rest.join("/"));
492 let result = [];
493 result.push(
494 ...restExploded.map(
495 (subpath) => subpath === "" ? required : [required, subpath].join("/")
496 )
497 );
498 if (isOptional) {
499 result.push(...restExploded);
500 }
501 return result.map(
502 (exploded) => path.startsWith("/") && exploded === "" ? "/" : exploded
503 );
504}
505function rankRouteBranches(branches) {
506 branches.sort(
507 (a, b) => a.score !== b.score ? b.score - a.score : compareIndexes(
508 a.routesMeta.map((meta) => meta.childrenIndex),
509 b.routesMeta.map((meta) => meta.childrenIndex)
510 )
511 );
512}
513var paramRe = /^:[\w-]+$/;
514var dynamicSegmentValue = 3;
515var indexRouteValue = 2;
516var emptySegmentValue = 1;
517var staticSegmentValue = 10;
518var splatPenalty = -2;
519var isSplat = (s) => s === "*";
520function computeScore(path, index) {
521 let segments = path.split("/");
522 let initialScore = segments.length;
523 if (segments.some(isSplat)) {
524 initialScore += splatPenalty;
525 }
526 if (index) {
527 initialScore += indexRouteValue;
528 }
529 return segments.filter((s) => !isSplat(s)).reduce(
530 (score, segment) => score + (paramRe.test(segment) ? dynamicSegmentValue : segment === "" ? emptySegmentValue : staticSegmentValue),
531 initialScore
532 );
533}
534function compareIndexes(a, b) {
535 let siblings = a.length === b.length && a.slice(0, -1).every((n, i) => n === b[i]);
536 return siblings ? (
537 // If two routes are siblings, we should try to match the earlier sibling
538 // first. This allows people to have fine-grained control over the matching
539 // behavior by simply putting routes with identical paths in the order they
540 // want them tried.
541 a[a.length - 1] - b[b.length - 1]
542 ) : (
543 // Otherwise, it doesn't really make sense to rank non-siblings by index,
544 // so they sort equally.
545 0
546 );
547}
548function matchRouteBranch(branch, pathname, allowPartial = false) {
549 let { routesMeta } = branch;
550 let matchedParams = {};
551 let matchedPathname = "/";
552 let matches = [];
553 for (let i = 0; i < routesMeta.length; ++i) {
554 let meta = routesMeta[i];
555 let end = i === routesMeta.length - 1;
556 let remainingPathname = matchedPathname === "/" ? pathname : pathname.slice(matchedPathname.length) || "/";
557 let match = matchPath(
558 { path: meta.relativePath, caseSensitive: meta.caseSensitive, end },
559 remainingPathname
560 );
561 let route = meta.route;
562 if (!match && end && allowPartial && !routesMeta[routesMeta.length - 1].route.index) {
563 match = matchPath(
564 {
565 path: meta.relativePath,
566 caseSensitive: meta.caseSensitive,
567 end: false
568 },
569 remainingPathname
570 );
571 }
572 if (!match) {
573 return null;
574 }
575 Object.assign(matchedParams, match.params);
576 matches.push({
577 // TODO: Can this as be avoided?
578 params: matchedParams,
579 pathname: joinPaths([matchedPathname, match.pathname]),
580 pathnameBase: normalizePathname(
581 joinPaths([matchedPathname, match.pathnameBase])
582 ),
583 route
584 });
585 if (match.pathnameBase !== "/") {
586 matchedPathname = joinPaths([matchedPathname, match.pathnameBase]);
587 }
588 }
589 return matches;
590}
591function generatePath(originalPath, params = {}) {
592 let path = originalPath;
593 if (path.endsWith("*") && path !== "*" && !path.endsWith("/*")) {
594 warning(
595 false,
596 `Route path "${path}" will be treated as if it were "${path.replace(/\*$/, "/*")}" because the \`*\` character must always follow a \`/\` in the pattern. To get rid of this warning, please change the route path to "${path.replace(/\*$/, "/*")}".`
597 );
598 path = path.replace(/\*$/, "/*");
599 }
600 const prefix = path.startsWith("/") ? "/" : "";
601 const stringify = (p) => p == null ? "" : typeof p === "string" ? p : String(p);
602 const segments = path.split(/\/+/).map((segment, index, array) => {
603 const isLastSegment = index === array.length - 1;
604 if (isLastSegment && segment === "*") {
605 const star = "*";
606 return stringify(params[star]);
607 }
608 const keyMatch = segment.match(/^:([\w-]+)(\??)$/);
609 if (keyMatch) {
610 const [, key, optional] = keyMatch;
611 let param = params[key];
612 invariant(optional === "?" || param != null, `Missing ":${key}" param`);
613 return stringify(param);
614 }
615 return segment.replace(/\?$/g, "");
616 }).filter((segment) => !!segment);
617 return prefix + segments.join("/");
618}
619function matchPath(pattern, pathname) {
620 if (typeof pattern === "string") {
621 pattern = { path: pattern, caseSensitive: false, end: true };
622 }
623 let [matcher, compiledParams] = compilePath(
624 pattern.path,
625 pattern.caseSensitive,
626 pattern.end
627 );
628 let match = pathname.match(matcher);
629 if (!match) return null;
630 let matchedPathname = match[0];
631 let pathnameBase = matchedPathname.replace(/(.)\/+$/, "$1");
632 let captureGroups = match.slice(1);
633 let params = compiledParams.reduce(
634 (memo2, { paramName, isOptional }, index) => {
635 if (paramName === "*") {
636 let splatValue = captureGroups[index] || "";
637 pathnameBase = matchedPathname.slice(0, matchedPathname.length - splatValue.length).replace(/(.)\/+$/, "$1");
638 }
639 const value = captureGroups[index];
640 if (isOptional && !value) {
641 memo2[paramName] = void 0;
642 } else {
643 memo2[paramName] = (value || "").replace(/%2F/g, "/");
644 }
645 return memo2;
646 },
647 {}
648 );
649 return {
650 params,
651 pathname: matchedPathname,
652 pathnameBase,
653 pattern
654 };
655}
656function compilePath(path, caseSensitive = false, end = true) {
657 warning(
658 path === "*" || !path.endsWith("*") || path.endsWith("/*"),
659 `Route path "${path}" will be treated as if it were "${path.replace(/\*$/, "/*")}" because the \`*\` character must always follow a \`/\` in the pattern. To get rid of this warning, please change the route path to "${path.replace(/\*$/, "/*")}".`
660 );
661 let params = [];
662 let regexpSource = "^" + path.replace(/\/*\*?$/, "").replace(/^\/*/, "/").replace(/[\\.*+^${}|()[\]]/g, "\\$&").replace(
663 /\/:([\w-]+)(\?)?/g,
664 (_, paramName, isOptional) => {
665 params.push({ paramName, isOptional: isOptional != null });
666 return isOptional ? "/?([^\\/]+)?" : "/([^\\/]+)";
667 }
668 );
669 if (path.endsWith("*")) {
670 params.push({ paramName: "*" });
671 regexpSource += path === "*" || path === "/*" ? "(.*)$" : "(?:\\/(.+)|\\/*)$";
672 } else if (end) {
673 regexpSource += "\\/*$";
674 } else if (path !== "" && path !== "/") {
675 regexpSource += "(?:(?=\\/|$))";
676 } else {
677 }
678 let matcher = new RegExp(regexpSource, caseSensitive ? void 0 : "i");
679 return [matcher, params];
680}
681function decodePath(value) {
682 try {
683 return value.split("/").map((v) => decodeURIComponent(v).replace(/\//g, "%2F")).join("/");
684 } catch (error) {
685 warning(
686 false,
687 `The URL path "${value}" could not be decoded because it is is a malformed URL segment. This is probably due to a bad percent encoding (${error}).`
688 );
689 return value;
690 }
691}
692function stripBasename(pathname, basename) {
693 if (basename === "/") return pathname;
694 if (!pathname.toLowerCase().startsWith(basename.toLowerCase())) {
695 return null;
696 }
697 let startIndex = basename.endsWith("/") ? basename.length - 1 : basename.length;
698 let nextChar = pathname.charAt(startIndex);
699 if (nextChar && nextChar !== "/") {
700 return null;
701 }
702 return pathname.slice(startIndex) || "/";
703}
704function resolvePath(to, fromPathname = "/") {
705 let {
706 pathname: toPathname,
707 search = "",
708 hash = ""
709 } = typeof to === "string" ? parsePath(to) : to;
710 let pathname = toPathname ? toPathname.startsWith("/") ? toPathname : resolvePathname(toPathname, fromPathname) : fromPathname;
711 return {
712 pathname,
713 search: normalizeSearch(search),
714 hash: normalizeHash(hash)
715 };
716}
717function resolvePathname(relativePath, fromPathname) {
718 let segments = fromPathname.replace(/\/+$/, "").split("/");
719 let relativeSegments = relativePath.split("/");
720 relativeSegments.forEach((segment) => {
721 if (segment === "..") {
722 if (segments.length > 1) segments.pop();
723 } else if (segment !== ".") {
724 segments.push(segment);
725 }
726 });
727 return segments.length > 1 ? segments.join("/") : "/";
728}
729function getInvalidPathError(char, field, dest, path) {
730 return `Cannot include a '${char}' character in a manually specified \`to.${field}\` field [${JSON.stringify(
731 path
732 )}]. Please separate it out to the \`to.${dest}\` field. Alternatively you may provide the full path as a string in <Link to="..."> and the router will parse it for you.`;
733}
734function getPathContributingMatches(matches) {
735 return matches.filter(
736 (match, index) => index === 0 || match.route.path && match.route.path.length > 0
737 );
738}
739function getResolveToMatches(matches) {
740 let pathMatches = getPathContributingMatches(matches);
741 return pathMatches.map(
742 (match, idx) => idx === pathMatches.length - 1 ? match.pathname : match.pathnameBase
743 );
744}
745function resolveTo(toArg, routePathnames, locationPathname, isPathRelative = false) {
746 let to;
747 if (typeof toArg === "string") {
748 to = parsePath(toArg);
749 } else {
750 to = { ...toArg };
751 invariant(
752 !to.pathname || !to.pathname.includes("?"),
753 getInvalidPathError("?", "pathname", "search", to)
754 );
755 invariant(
756 !to.pathname || !to.pathname.includes("#"),
757 getInvalidPathError("#", "pathname", "hash", to)
758 );
759 invariant(
760 !to.search || !to.search.includes("#"),
761 getInvalidPathError("#", "search", "hash", to)
762 );
763 }
764 let isEmptyPath = toArg === "" || to.pathname === "";
765 let toPathname = isEmptyPath ? "/" : to.pathname;
766 let from;
767 if (toPathname == null) {
768 from = locationPathname;
769 } else {
770 let routePathnameIndex = routePathnames.length - 1;
771 if (!isPathRelative && toPathname.startsWith("..")) {
772 let toSegments = toPathname.split("/");
773 while (toSegments[0] === "..") {
774 toSegments.shift();
775 routePathnameIndex -= 1;
776 }
777 to.pathname = toSegments.join("/");
778 }
779 from = routePathnameIndex >= 0 ? routePathnames[routePathnameIndex] : "/";
780 }
781 let path = resolvePath(to, from);
782 let hasExplicitTrailingSlash = toPathname && toPathname !== "/" && toPathname.endsWith("/");
783 let hasCurrentTrailingSlash = (isEmptyPath || toPathname === ".") && locationPathname.endsWith("/");
784 if (!path.pathname.endsWith("/") && (hasExplicitTrailingSlash || hasCurrentTrailingSlash)) {
785 path.pathname += "/";
786 }
787 return path;
788}
789var joinPaths = (paths) => paths.join("/").replace(/\/\/+/g, "/");
790var normalizePathname = (pathname) => pathname.replace(/\/+$/, "").replace(/^\/*/, "/");
791var normalizeSearch = (search) => !search || search === "?" ? "" : search.startsWith("?") ? search : "?" + search;
792var normalizeHash = (hash) => !hash || hash === "#" ? "" : hash.startsWith("#") ? hash : "#" + hash;
793var DataWithResponseInit = class {
794 constructor(data2, init) {
795 this.type = "DataWithResponseInit";
796 this.data = data2;
797 this.init = init || null;
798 }
799};
800function data(data2, init) {
801 return new DataWithResponseInit(
802 data2,
803 typeof init === "number" ? { status: init } : init
804 );
805}
806var redirect = (url, init = 302) => {
807 let responseInit = init;
808 if (typeof responseInit === "number") {
809 responseInit = { status: responseInit };
810 } else if (typeof responseInit.status === "undefined") {
811 responseInit.status = 302;
812 }
813 let headers = new Headers(responseInit.headers);
814 headers.set("Location", url);
815 return new Response(null, {
816 ...responseInit,
817 headers
818 });
819};
820var redirectDocument = (url, init) => {
821 let response = redirect(url, init);
822 response.headers.set("X-Remix-Reload-Document", "true");
823 return response;
824};
825var replace = (url, init) => {
826 let response = redirect(url, init);
827 response.headers.set("X-Remix-Replace", "true");
828 return response;
829};
830var ErrorResponseImpl = class {
831 constructor(status, statusText, data2, internal = false) {
832 this.status = status;
833 this.statusText = statusText || "";
834 this.internal = internal;
835 if (data2 instanceof Error) {
836 this.data = data2.toString();
837 this.error = data2;
838 } else {
839 this.data = data2;
840 }
841 }
842};
843function isRouteErrorResponse(error) {
844 return error != null && typeof error.status === "number" && typeof error.statusText === "string" && typeof error.internal === "boolean" && "data" in error;
845}
846
847// lib/router/router.ts
848var validMutationMethodsArr = [
849 "POST",
850 "PUT",
851 "PATCH",
852 "DELETE"
853];
854var validMutationMethods = new Set(
855 validMutationMethodsArr
856);
857var validRequestMethodsArr = [
858 "GET",
859 ...validMutationMethodsArr
860];
861var validRequestMethods = new Set(validRequestMethodsArr);
862var redirectStatusCodes = /* @__PURE__ */ new Set([301, 302, 303, 307, 308]);
863var redirectPreserveMethodStatusCodes = /* @__PURE__ */ new Set([307, 308]);
864var IDLE_NAVIGATION = {
865 state: "idle",
866 location: void 0,
867 formMethod: void 0,
868 formAction: void 0,
869 formEncType: void 0,
870 formData: void 0,
871 json: void 0,
872 text: void 0
873};
874var IDLE_FETCHER = {
875 state: "idle",
876 data: void 0,
877 formMethod: void 0,
878 formAction: void 0,
879 formEncType: void 0,
880 formData: void 0,
881 json: void 0,
882 text: void 0
883};
884var IDLE_BLOCKER = {
885 state: "unblocked",
886 proceed: void 0,
887 reset: void 0,
888 location: void 0
889};
890var ABSOLUTE_URL_REGEX = /^(?:[a-z][a-z0-9+.-]*:|\/\/)/i;
891var defaultMapRouteProperties = (route) => ({
892 hasErrorBoundary: Boolean(route.hasErrorBoundary)
893});
894var TRANSITIONS_STORAGE_KEY = "remix-router-transitions";
895var ResetLoaderDataSymbol = Symbol("ResetLoaderData");
896function createRouter(init) {
897 const routerWindow = init.window ? init.window : typeof window !== "undefined" ? window : void 0;
898 const isBrowser2 = typeof routerWindow !== "undefined" && typeof routerWindow.document !== "undefined" && typeof routerWindow.document.createElement !== "undefined";
899 invariant(
900 init.routes.length > 0,
901 "You must provide a non-empty routes array to createRouter"
902 );
903 let mapRouteProperties2 = init.mapRouteProperties || defaultMapRouteProperties;
904 let manifest = {};
905 let dataRoutes = convertRoutesToDataRoutes(
906 init.routes,
907 mapRouteProperties2,
908 void 0,
909 manifest
910 );
911 let inFlightDataRoutes;
912 let basename = init.basename || "/";
913 let dataStrategyImpl = init.dataStrategy || defaultDataStrategy;
914 let patchRoutesOnNavigationImpl = init.patchRoutesOnNavigation;
915 let future = {
916 ...init.future
917 };
918 let unlistenHistory = null;
919 let subscribers = /* @__PURE__ */ new Set();
920 let savedScrollPositions2 = null;
921 let getScrollRestorationKey2 = null;
922 let getScrollPosition = null;
923 let initialScrollRestored = init.hydrationData != null;
924 let initialMatches = matchRoutes(dataRoutes, init.history.location, basename);
925 let initialErrors = null;
926 if (initialMatches == null && !patchRoutesOnNavigationImpl) {
927 let error = getInternalRouterError(404, {
928 pathname: init.history.location.pathname
929 });
930 let { matches, route } = getShortCircuitMatches(dataRoutes);
931 initialMatches = matches;
932 initialErrors = { [route.id]: error };
933 }
934 if (initialMatches && !init.hydrationData) {
935 let fogOfWar = checkFogOfWar(
936 initialMatches,
937 dataRoutes,
938 init.history.location.pathname
939 );
940 if (fogOfWar.active) {
941 initialMatches = null;
942 }
943 }
944 let initialized;
945 if (!initialMatches) {
946 initialized = false;
947 initialMatches = [];
948 let fogOfWar = checkFogOfWar(
949 null,
950 dataRoutes,
951 init.history.location.pathname
952 );
953 if (fogOfWar.active && fogOfWar.matches) {
954 initialMatches = fogOfWar.matches;
955 }
956 } else if (initialMatches.some((m) => m.route.lazy)) {
957 initialized = false;
958 } else if (!initialMatches.some((m) => m.route.loader)) {
959 initialized = true;
960 } else {
961 let loaderData = init.hydrationData ? init.hydrationData.loaderData : null;
962 let errors = init.hydrationData ? init.hydrationData.errors : null;
963 if (errors) {
964 let idx = initialMatches.findIndex(
965 (m) => errors[m.route.id] !== void 0
966 );
967 initialized = initialMatches.slice(0, idx + 1).every((m) => !shouldLoadRouteOnHydration(m.route, loaderData, errors));
968 } else {
969 initialized = initialMatches.every(
970 (m) => !shouldLoadRouteOnHydration(m.route, loaderData, errors)
971 );
972 }
973 }
974 let router;
975 let state = {
976 historyAction: init.history.action,
977 location: init.history.location,
978 matches: initialMatches,
979 initialized,
980 navigation: IDLE_NAVIGATION,
981 // Don't restore on initial updateState() if we were SSR'd
982 restoreScrollPosition: init.hydrationData != null ? false : null,
983 preventScrollReset: false,
984 revalidation: "idle",
985 loaderData: init.hydrationData && init.hydrationData.loaderData || {},
986 actionData: init.hydrationData && init.hydrationData.actionData || null,
987 errors: init.hydrationData && init.hydrationData.errors || initialErrors,
988 fetchers: /* @__PURE__ */ new Map(),
989 blockers: /* @__PURE__ */ new Map()
990 };
991 let pendingAction = "POP" /* Pop */;
992 let pendingPreventScrollReset = false;
993 let pendingNavigationController;
994 let pendingViewTransitionEnabled = false;
995 let appliedViewTransitions = /* @__PURE__ */ new Map();
996 let removePageHideEventListener = null;
997 let isUninterruptedRevalidation = false;
998 let isRevalidationRequired = false;
999 let cancelledFetcherLoads = /* @__PURE__ */ new Set();
1000 let fetchControllers = /* @__PURE__ */ new Map();
1001 let incrementingLoadId = 0;
1002 let pendingNavigationLoadId = -1;
1003 let fetchReloadIds = /* @__PURE__ */ new Map();
1004 let fetchRedirectIds = /* @__PURE__ */ new Set();
1005 let fetchLoadMatches = /* @__PURE__ */ new Map();
1006 let activeFetchers = /* @__PURE__ */ new Map();
1007 let fetchersQueuedForDeletion = /* @__PURE__ */ new Set();
1008 let blockerFunctions = /* @__PURE__ */ new Map();
1009 let unblockBlockerHistoryUpdate = void 0;
1010 let pendingRevalidationDfd = null;
1011 function initialize() {
1012 unlistenHistory = init.history.listen(
1013 ({ action: historyAction, location, delta }) => {
1014 if (unblockBlockerHistoryUpdate) {
1015 unblockBlockerHistoryUpdate();
1016 unblockBlockerHistoryUpdate = void 0;
1017 return;
1018 }
1019 warning(
1020 blockerFunctions.size === 0 || delta != null,
1021 "You are trying to use a blocker on a POP navigation to a location that was not created by @remix-run/router. This will fail silently in production. This can happen if you are navigating outside the router via `window.history.pushState`/`window.location.hash` instead of using router navigation APIs. This can also happen if you are using createHashRouter and the user manually changes the URL."
1022 );
1023 let blockerKey = shouldBlockNavigation({
1024 currentLocation: state.location,
1025 nextLocation: location,
1026 historyAction
1027 });
1028 if (blockerKey && delta != null) {
1029 let nextHistoryUpdatePromise = new Promise((resolve) => {
1030 unblockBlockerHistoryUpdate = resolve;
1031 });
1032 init.history.go(delta * -1);
1033 updateBlocker(blockerKey, {
1034 state: "blocked",
1035 location,
1036 proceed() {
1037 updateBlocker(blockerKey, {
1038 state: "proceeding",
1039 proceed: void 0,
1040 reset: void 0,
1041 location
1042 });
1043 nextHistoryUpdatePromise.then(() => init.history.go(delta));
1044 },
1045 reset() {
1046 let blockers = new Map(state.blockers);
1047 blockers.set(blockerKey, IDLE_BLOCKER);
1048 updateState({ blockers });
1049 }
1050 });
1051 return;
1052 }
1053 return startNavigation(historyAction, location);
1054 }
1055 );
1056 if (isBrowser2) {
1057 restoreAppliedTransitions(routerWindow, appliedViewTransitions);
1058 let _saveAppliedTransitions = () => persistAppliedTransitions(routerWindow, appliedViewTransitions);
1059 routerWindow.addEventListener("pagehide", _saveAppliedTransitions);
1060 removePageHideEventListener = () => routerWindow.removeEventListener("pagehide", _saveAppliedTransitions);
1061 }
1062 if (!state.initialized) {
1063 startNavigation("POP" /* Pop */, state.location, {
1064 initialHydration: true
1065 });
1066 }
1067 return router;
1068 }
1069 function dispose() {
1070 if (unlistenHistory) {
1071 unlistenHistory();
1072 }
1073 if (removePageHideEventListener) {
1074 removePageHideEventListener();
1075 }
1076 subscribers.clear();
1077 pendingNavigationController && pendingNavigationController.abort();
1078 state.fetchers.forEach((_, key) => deleteFetcher(key));
1079 state.blockers.forEach((_, key) => deleteBlocker(key));
1080 }
1081 function subscribe(fn) {
1082 subscribers.add(fn);
1083 return () => subscribers.delete(fn);
1084 }
1085 function updateState(newState, opts = {}) {
1086 state = {
1087 ...state,
1088 ...newState
1089 };
1090 let unmountedFetchers = [];
1091 let mountedFetchers = [];
1092 state.fetchers.forEach((fetcher, key) => {
1093 if (fetcher.state === "idle") {
1094 if (fetchersQueuedForDeletion.has(key)) {
1095 unmountedFetchers.push(key);
1096 } else {
1097 mountedFetchers.push(key);
1098 }
1099 }
1100 });
1101 [...subscribers].forEach(
1102 (subscriber) => subscriber(state, {
1103 deletedFetchers: unmountedFetchers,
1104 viewTransitionOpts: opts.viewTransitionOpts,
1105 flushSync: opts.flushSync === true
1106 })
1107 );
1108 unmountedFetchers.forEach((key) => deleteFetcher(key));
1109 mountedFetchers.forEach((key) => state.fetchers.delete(key));
1110 }
1111 function completeNavigation(location, newState, { flushSync } = {}) {
1112 let isActionReload = state.actionData != null && state.navigation.formMethod != null && isMutationMethod(state.navigation.formMethod) && state.navigation.state === "loading" && location.state?._isRedirect !== true;
1113 let actionData;
1114 if (newState.actionData) {
1115 if (Object.keys(newState.actionData).length > 0) {
1116 actionData = newState.actionData;
1117 } else {
1118 actionData = null;
1119 }
1120 } else if (isActionReload) {
1121 actionData = state.actionData;
1122 } else {
1123 actionData = null;
1124 }
1125 let loaderData = newState.loaderData ? mergeLoaderData(
1126 state.loaderData,
1127 newState.loaderData,
1128 newState.matches || [],
1129 newState.errors
1130 ) : state.loaderData;
1131 let blockers = state.blockers;
1132 if (blockers.size > 0) {
1133 blockers = new Map(blockers);
1134 blockers.forEach((_, k) => blockers.set(k, IDLE_BLOCKER));
1135 }
1136 let preventScrollReset = pendingPreventScrollReset === true || state.navigation.formMethod != null && isMutationMethod(state.navigation.formMethod) && location.state?._isRedirect !== true;
1137 if (inFlightDataRoutes) {
1138 dataRoutes = inFlightDataRoutes;
1139 inFlightDataRoutes = void 0;
1140 }
1141 if (isUninterruptedRevalidation) {
1142 } else if (pendingAction === "POP" /* Pop */) {
1143 } else if (pendingAction === "PUSH" /* Push */) {
1144 init.history.push(location, location.state);
1145 } else if (pendingAction === "REPLACE" /* Replace */) {
1146 init.history.replace(location, location.state);
1147 }
1148 let viewTransitionOpts;
1149 if (pendingAction === "POP" /* Pop */) {
1150 let priorPaths = appliedViewTransitions.get(state.location.pathname);
1151 if (priorPaths && priorPaths.has(location.pathname)) {
1152 viewTransitionOpts = {
1153 currentLocation: state.location,
1154 nextLocation: location
1155 };
1156 } else if (appliedViewTransitions.has(location.pathname)) {
1157 viewTransitionOpts = {
1158 currentLocation: location,
1159 nextLocation: state.location
1160 };
1161 }
1162 } else if (pendingViewTransitionEnabled) {
1163 let toPaths = appliedViewTransitions.get(state.location.pathname);
1164 if (toPaths) {
1165 toPaths.add(location.pathname);
1166 } else {
1167 toPaths = /* @__PURE__ */ new Set([location.pathname]);
1168 appliedViewTransitions.set(state.location.pathname, toPaths);
1169 }
1170 viewTransitionOpts = {
1171 currentLocation: state.location,
1172 nextLocation: location
1173 };
1174 }
1175 updateState(
1176 {
1177 ...newState,
1178 // matches, errors, fetchers go through as-is
1179 actionData,
1180 loaderData,
1181 historyAction: pendingAction,
1182 location,
1183 initialized: true,
1184 navigation: IDLE_NAVIGATION,
1185 revalidation: "idle",
1186 restoreScrollPosition: getSavedScrollPosition(
1187 location,
1188 newState.matches || state.matches
1189 ),
1190 preventScrollReset,
1191 blockers
1192 },
1193 {
1194 viewTransitionOpts,
1195 flushSync: flushSync === true
1196 }
1197 );
1198 pendingAction = "POP" /* Pop */;
1199 pendingPreventScrollReset = false;
1200 pendingViewTransitionEnabled = false;
1201 isUninterruptedRevalidation = false;
1202 isRevalidationRequired = false;
1203 pendingRevalidationDfd?.resolve();
1204 pendingRevalidationDfd = null;
1205 }
1206 async function navigate(to, opts) {
1207 if (typeof to === "number") {
1208 init.history.go(to);
1209 return;
1210 }
1211 let normalizedPath = normalizeTo(
1212 state.location,
1213 state.matches,
1214 basename,
1215 to,
1216 opts?.fromRouteId,
1217 opts?.relative
1218 );
1219 let { path, submission, error } = normalizeNavigateOptions(
1220 false,
1221 normalizedPath,
1222 opts
1223 );
1224 let currentLocation = state.location;
1225 let nextLocation = createLocation(state.location, path, opts && opts.state);
1226 nextLocation = {
1227 ...nextLocation,
1228 ...init.history.encodeLocation(nextLocation)
1229 };
1230 let userReplace = opts && opts.replace != null ? opts.replace : void 0;
1231 let historyAction = "PUSH" /* Push */;
1232 if (userReplace === true) {
1233 historyAction = "REPLACE" /* Replace */;
1234 } else if (userReplace === false) {
1235 } else if (submission != null && isMutationMethod(submission.formMethod) && submission.formAction === state.location.pathname + state.location.search) {
1236 historyAction = "REPLACE" /* Replace */;
1237 }
1238 let preventScrollReset = opts && "preventScrollReset" in opts ? opts.preventScrollReset === true : void 0;
1239 let flushSync = (opts && opts.flushSync) === true;
1240 let blockerKey = shouldBlockNavigation({
1241 currentLocation,
1242 nextLocation,
1243 historyAction
1244 });
1245 if (blockerKey) {
1246 updateBlocker(blockerKey, {
1247 state: "blocked",
1248 location: nextLocation,
1249 proceed() {
1250 updateBlocker(blockerKey, {
1251 state: "proceeding",
1252 proceed: void 0,
1253 reset: void 0,
1254 location: nextLocation
1255 });
1256 navigate(to, opts);
1257 },
1258 reset() {
1259 let blockers = new Map(state.blockers);
1260 blockers.set(blockerKey, IDLE_BLOCKER);
1261 updateState({ blockers });
1262 }
1263 });
1264 return;
1265 }
1266 await startNavigation(historyAction, nextLocation, {
1267 submission,
1268 // Send through the formData serialization error if we have one so we can
1269 // render at the right error boundary after we match routes
1270 pendingError: error,
1271 preventScrollReset,
1272 replace: opts && opts.replace,
1273 enableViewTransition: opts && opts.viewTransition,
1274 flushSync
1275 });
1276 }
1277 function revalidate() {
1278 if (!pendingRevalidationDfd) {
1279 pendingRevalidationDfd = createDeferred();
1280 }
1281 interruptActiveLoads();
1282 updateState({ revalidation: "loading" });
1283 let promise = pendingRevalidationDfd.promise;
1284 if (state.navigation.state === "submitting") {
1285 return promise;
1286 }
1287 if (state.navigation.state === "idle") {
1288 startNavigation(state.historyAction, state.location, {
1289 startUninterruptedRevalidation: true
1290 });
1291 return promise;
1292 }
1293 startNavigation(
1294 pendingAction || state.historyAction,
1295 state.navigation.location,
1296 {
1297 overrideNavigation: state.navigation,
1298 // Proxy through any rending view transition
1299 enableViewTransition: pendingViewTransitionEnabled === true
1300 }
1301 );
1302 return promise;
1303 }
1304 async function startNavigation(historyAction, location, opts) {
1305 pendingNavigationController && pendingNavigationController.abort();
1306 pendingNavigationController = null;
1307 pendingAction = historyAction;
1308 isUninterruptedRevalidation = (opts && opts.startUninterruptedRevalidation) === true;
1309 saveScrollPosition(state.location, state.matches);
1310 pendingPreventScrollReset = (opts && opts.preventScrollReset) === true;
1311 pendingViewTransitionEnabled = (opts && opts.enableViewTransition) === true;
1312 let routesToUse = inFlightDataRoutes || dataRoutes;
1313 let loadingNavigation = opts && opts.overrideNavigation;
1314 let matches = matchRoutes(routesToUse, location, basename);
1315 let flushSync = (opts && opts.flushSync) === true;
1316 let fogOfWar = checkFogOfWar(matches, routesToUse, location.pathname);
1317 if (fogOfWar.active && fogOfWar.matches) {
1318 matches = fogOfWar.matches;
1319 }
1320 if (!matches) {
1321 let { error, notFoundMatches, route } = handleNavigational404(
1322 location.pathname
1323 );
1324 completeNavigation(
1325 location,
1326 {
1327 matches: notFoundMatches,
1328 loaderData: {},
1329 errors: {
1330 [route.id]: error
1331 }
1332 },
1333 { flushSync }
1334 );
1335 return;
1336 }
1337 if (state.initialized && !isRevalidationRequired && isHashChangeOnly(state.location, location) && !(opts && opts.submission && isMutationMethod(opts.submission.formMethod))) {
1338 completeNavigation(location, { matches }, { flushSync });
1339 return;
1340 }
1341 pendingNavigationController = new AbortController();
1342 let request = createClientSideRequest(
1343 init.history,
1344 location,
1345 pendingNavigationController.signal,
1346 opts && opts.submission
1347 );
1348 let pendingActionResult;
1349 if (opts && opts.pendingError) {
1350 pendingActionResult = [
1351 findNearestBoundary(matches).route.id,
1352 { type: "error" /* error */, error: opts.pendingError }
1353 ];
1354 } else if (opts && opts.submission && isMutationMethod(opts.submission.formMethod)) {
1355 let actionResult = await handleAction(
1356 request,
1357 location,
1358 opts.submission,
1359 matches,
1360 fogOfWar.active,
1361 { replace: opts.replace, flushSync }
1362 );
1363 if (actionResult.shortCircuited) {
1364 return;
1365 }
1366 if (actionResult.pendingActionResult) {
1367 let [routeId, result] = actionResult.pendingActionResult;
1368 if (isErrorResult(result) && isRouteErrorResponse(result.error) && result.error.status === 404) {
1369 pendingNavigationController = null;
1370 completeNavigation(location, {
1371 matches: actionResult.matches,
1372 loaderData: {},
1373 errors: {
1374 [routeId]: result.error
1375 }
1376 });
1377 return;
1378 }
1379 }
1380 matches = actionResult.matches || matches;
1381 pendingActionResult = actionResult.pendingActionResult;
1382 loadingNavigation = getLoadingNavigation(location, opts.submission);
1383 flushSync = false;
1384 fogOfWar.active = false;
1385 request = createClientSideRequest(
1386 init.history,
1387 request.url,
1388 request.signal
1389 );
1390 }
1391 let {
1392 shortCircuited,
1393 matches: updatedMatches,
1394 loaderData,
1395 errors
1396 } = await handleLoaders(
1397 request,
1398 location,
1399 matches,
1400 fogOfWar.active,
1401 loadingNavigation,
1402 opts && opts.submission,
1403 opts && opts.fetcherSubmission,
1404 opts && opts.replace,
1405 opts && opts.initialHydration === true,
1406 flushSync,
1407 pendingActionResult
1408 );
1409 if (shortCircuited) {
1410 return;
1411 }
1412 pendingNavigationController = null;
1413 completeNavigation(location, {
1414 matches: updatedMatches || matches,
1415 ...getActionDataForCommit(pendingActionResult),
1416 loaderData,
1417 errors
1418 });
1419 }
1420 async function handleAction(request, location, submission, matches, isFogOfWar, opts = {}) {
1421 interruptActiveLoads();
1422 let navigation = getSubmittingNavigation(location, submission);
1423 updateState({ navigation }, { flushSync: opts.flushSync === true });
1424 if (isFogOfWar) {
1425 let discoverResult = await discoverRoutes(
1426 matches,
1427 location.pathname,
1428 request.signal
1429 );
1430 if (discoverResult.type === "aborted") {
1431 return { shortCircuited: true };
1432 } else if (discoverResult.type === "error") {
1433 let boundaryId = findNearestBoundary(discoverResult.partialMatches).route.id;
1434 return {
1435 matches: discoverResult.partialMatches,
1436 pendingActionResult: [
1437 boundaryId,
1438 {
1439 type: "error" /* error */,
1440 error: discoverResult.error
1441 }
1442 ]
1443 };
1444 } else if (!discoverResult.matches) {
1445 let { notFoundMatches, error, route } = handleNavigational404(
1446 location.pathname
1447 );
1448 return {
1449 matches: notFoundMatches,
1450 pendingActionResult: [
1451 route.id,
1452 {
1453 type: "error" /* error */,
1454 error
1455 }
1456 ]
1457 };
1458 } else {
1459 matches = discoverResult.matches;
1460 }
1461 }
1462 let result;
1463 let actionMatch = getTargetMatch(matches, location);
1464 if (!actionMatch.route.action && !actionMatch.route.lazy) {
1465 result = {
1466 type: "error" /* error */,
1467 error: getInternalRouterError(405, {
1468 method: request.method,
1469 pathname: location.pathname,
14