UNPKG

309 kBJavaScriptView Raw
1/**
2 * react-router v7.1.5
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 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, { ...responseInit, headers });
816};
817var redirectDocument = (url, init) => {
818 let response = redirect(url, init);
819 response.headers.set("X-Remix-Reload-Document", "true");
820 return response;
821};
822var replace = (url, init) => {
823 let response = redirect(url, init);
824 response.headers.set("X-Remix-Replace", "true");
825 return response;
826};
827var ErrorResponseImpl = class {
828 constructor(status, statusText, data2, internal = false) {
829 this.status = status;
830 this.statusText = statusText || "";
831 this.internal = internal;
832 if (data2 instanceof Error) {
833 this.data = data2.toString();
834 this.error = data2;
835 } else {
836 this.data = data2;
837 }
838 }
839};
840function isRouteErrorResponse(error) {
841 return error != null && typeof error.status === "number" && typeof error.statusText === "string" && typeof error.internal === "boolean" && "data" in error;
842}
843
844// lib/router/router.ts
845var validMutationMethodsArr = [
846 "POST",
847 "PUT",
848 "PATCH",
849 "DELETE"
850];
851var validMutationMethods = new Set(
852 validMutationMethodsArr
853);
854var validRequestMethodsArr = [
855 "GET",
856 ...validMutationMethodsArr
857];
858var validRequestMethods = new Set(validRequestMethodsArr);
859var redirectStatusCodes = /* @__PURE__ */ new Set([301, 302, 303, 307, 308]);
860var redirectPreserveMethodStatusCodes = /* @__PURE__ */ new Set([307, 308]);
861var IDLE_NAVIGATION = {
862 state: "idle",
863 location: void 0,
864 formMethod: void 0,
865 formAction: void 0,
866 formEncType: void 0,
867 formData: void 0,
868 json: void 0,
869 text: void 0
870};
871var IDLE_FETCHER = {
872 state: "idle",
873 data: void 0,
874 formMethod: void 0,
875 formAction: void 0,
876 formEncType: void 0,
877 formData: void 0,
878 json: void 0,
879 text: void 0
880};
881var IDLE_BLOCKER = {
882 state: "unblocked",
883 proceed: void 0,
884 reset: void 0,
885 location: void 0
886};
887var ABSOLUTE_URL_REGEX = /^(?:[a-z][a-z0-9+.-]*:|\/\/)/i;
888var defaultMapRouteProperties = (route) => ({
889 hasErrorBoundary: Boolean(route.hasErrorBoundary)
890});
891var TRANSITIONS_STORAGE_KEY = "remix-router-transitions";
892var ResetLoaderDataSymbol = Symbol("ResetLoaderData");
893function createRouter(init) {
894 const routerWindow = init.window ? init.window : typeof window !== "undefined" ? window : void 0;
895 const isBrowser2 = typeof routerWindow !== "undefined" && typeof routerWindow.document !== "undefined" && typeof routerWindow.document.createElement !== "undefined";
896 invariant(
897 init.routes.length > 0,
898 "You must provide a non-empty routes array to createRouter"
899 );
900 let mapRouteProperties2 = init.mapRouteProperties || defaultMapRouteProperties;
901 let manifest = {};
902 let dataRoutes = convertRoutesToDataRoutes(
903 init.routes,
904 mapRouteProperties2,
905 void 0,
906 manifest
907 );
908 let inFlightDataRoutes;
909 let basename = init.basename || "/";
910 let dataStrategyImpl = init.dataStrategy || defaultDataStrategy;
911 let patchRoutesOnNavigationImpl = init.patchRoutesOnNavigation;
912 let future = {
913 ...init.future
914 };
915 let unlistenHistory = null;
916 let subscribers = /* @__PURE__ */ new Set();
917 let savedScrollPositions2 = null;
918 let getScrollRestorationKey2 = null;
919 let getScrollPosition = null;
920 let initialScrollRestored = init.hydrationData != null;
921 let initialMatches = matchRoutes(dataRoutes, init.history.location, basename);
922 let initialMatchesIsFOW = false;
923 let initialErrors = null;
924 if (initialMatches == null && !patchRoutesOnNavigationImpl) {
925 let error = getInternalRouterError(404, {
926 pathname: init.history.location.pathname
927 });
928 let { matches, route } = getShortCircuitMatches(dataRoutes);
929 initialMatches = matches;
930 initialErrors = { [route.id]: error };
931 }
932 if (initialMatches && !init.hydrationData) {
933 let fogOfWar = checkFogOfWar(
934 initialMatches,
935 dataRoutes,
936 init.history.location.pathname
937 );
938 if (fogOfWar.active) {
939 initialMatches = null;
940 }
941 }
942 let initialized;
943 if (!initialMatches) {
944 initialized = false;
945 initialMatches = [];
946 let fogOfWar = checkFogOfWar(
947 null,
948 dataRoutes,
949 init.history.location.pathname
950 );
951 if (fogOfWar.active && fogOfWar.matches) {
952 initialMatchesIsFOW = true;
953 initialMatches = fogOfWar.matches;
954 }
955 } else if (initialMatches.some((m) => m.route.lazy)) {
956 initialized = false;
957 } else if (!initialMatches.some((m) => m.route.loader)) {
958 initialized = true;
959 } else {
960 let loaderData = init.hydrationData ? init.hydrationData.loaderData : null;
961 let errors = init.hydrationData ? init.hydrationData.errors : null;
962 if (errors) {
963 let idx = initialMatches.findIndex(
964 (m) => errors[m.route.id] !== void 0
965 );
966 initialized = initialMatches.slice(0, idx + 1).every((m) => !shouldLoadRouteOnHydration(m.route, loaderData, errors));
967 } else {
968 initialized = initialMatches.every(
969 (m) => !shouldLoadRouteOnHydration(m.route, loaderData, errors)
970 );
971 }
972 }
973 let router;
974 let state = {
975 historyAction: init.history.action,
976 location: init.history.location,
977 matches: initialMatches,
978 initialized,
979 navigation: IDLE_NAVIGATION,
980 // Don't restore on initial updateState() if we were SSR'd
981 restoreScrollPosition: init.hydrationData != null ? false : null,
982 preventScrollReset: false,
983 revalidation: "idle",
984 loaderData: init.hydrationData && init.hydrationData.loaderData || {},
985 actionData: init.hydrationData && init.hydrationData.actionData || null,
986 errors: init.hydrationData && init.hydrationData.errors || initialErrors,
987 fetchers: /* @__PURE__ */ new Map(),
988 blockers: /* @__PURE__ */ new Map()
989 };
990 let pendingAction = "POP" /* Pop */;
991 let pendingPreventScrollReset = false;
992 let pendingNavigationController;
993 let pendingViewTransitionEnabled = false;
994 let appliedViewTransitions = /* @__PURE__ */ new Map();
995 let removePageHideEventListener = null;
996 let isUninterruptedRevalidation = false;
997 let isRevalidationRequired = false;
998 let cancelledFetcherLoads = /* @__PURE__ */ new Set();
999 let fetchControllers = /* @__PURE__ */ new Map();
1000 let incrementingLoadId = 0;
1001 let pendingNavigationLoadId = -1;
1002 let fetchReloadIds = /* @__PURE__ */ new Map();
1003 let fetchRedirectIds = /* @__PURE__ */ new Set();
1004 let fetchLoadMatches = /* @__PURE__ */ new Map();
1005 let activeFetchers = /* @__PURE__ */ new Map();
1006 let fetchersQueuedForDeletion = /* @__PURE__ */ new Set();
1007 let blockerFunctions = /* @__PURE__ */ new Map();
1008 let unblockBlockerHistoryUpdate = void 0;
1009 let pendingRevalidationDfd = null;
1010 function initialize() {
1011 unlistenHistory = init.history.listen(
1012 ({ action: historyAction, location, delta }) => {
1013 if (unblockBlockerHistoryUpdate) {
1014 unblockBlockerHistoryUpdate();
1015 unblockBlockerHistoryUpdate = void 0;
1016 return;
1017 }
1018 warning(
1019 blockerFunctions.size === 0 || delta != null,
1020 "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."
1021 );
1022 let blockerKey = shouldBlockNavigation({
1023 currentLocation: state.location,
1024 nextLocation: location,
1025 historyAction
1026 });
1027 if (blockerKey && delta != null) {
1028 let nextHistoryUpdatePromise = new Promise((resolve) => {
1029 unblockBlockerHistoryUpdate = resolve;
1030 });
1031 init.history.go(delta * -1);
1032 updateBlocker(blockerKey, {
1033 state: "blocked",
1034 location,
1035 proceed() {
1036 updateBlocker(blockerKey, {
1037 state: "proceeding",
1038 proceed: void 0,
1039 reset: void 0,
1040 location
1041 });
1042 nextHistoryUpdatePromise.then(() => init.history.go(delta));
1043 },
1044 reset() {
1045 let blockers = new Map(state.blockers);
1046 blockers.set(blockerKey, IDLE_BLOCKER);
1047 updateState({ blockers });
1048 }
1049 });
1050 return;
1051 }
1052 return startNavigation(historyAction, location);
1053 }
1054 );
1055 if (isBrowser2) {
1056 restoreAppliedTransitions(routerWindow, appliedViewTransitions);
1057 let _saveAppliedTransitions = () => persistAppliedTransitions(routerWindow, appliedViewTransitions);
1058 routerWindow.addEventListener("pagehide", _saveAppliedTransitions);
1059 removePageHideEventListener = () => routerWindow.removeEventListener("pagehide", _saveAppliedTransitions);
1060 }
1061 if (!state.initialized) {
1062 startNavigation("POP" /* Pop */, state.location, {
1063 initialHydration: true
1064 });
1065 }
1066 return router;
1067 }
1068 function dispose() {
1069 if (unlistenHistory) {
1070 unlistenHistory();
1071 }
1072 if (removePageHideEventListener) {
1073 removePageHideEventListener();
1074 }
1075 subscribers.clear();
1076 pendingNavigationController && pendingNavigationController.abort();
1077 state.fetchers.forEach((_, key) => deleteFetcher(key));
1078 state.blockers.forEach((_, key) => deleteBlocker(key));
1079 }
1080 function subscribe(fn) {
1081 subscribers.add(fn);
1082 return () => subscribers.delete(fn);
1083 }
1084 function updateState(newState, opts = {}) {
1085 state = {
1086 ...state,
1087 ...newState
1088 };
1089 let unmountedFetchers = [];
1090 let mountedFetchers = [];
1091 state.fetchers.forEach((fetcher, key) => {
1092 if (fetcher.state === "idle") {
1093 if (fetchersQueuedForDeletion.has(key)) {
1094 unmountedFetchers.push(key);
1095 } else {
1096 mountedFetchers.push(key);
1097 }
1098 }
1099 });
1100 fetchersQueuedForDeletion.forEach((key) => {
1101 if (!state.fetchers.has(key) && !fetchControllers.has(key)) {
1102 unmountedFetchers.push(key);
1103 }
1104 });
1105 [...subscribers].forEach(
1106 (subscriber) => subscriber(state, {
1107 deletedFetchers: unmountedFetchers,
1108 viewTransitionOpts: opts.viewTransitionOpts,
1109 flushSync: opts.flushSync === true
1110 })
1111 );
1112 unmountedFetchers.forEach((key) => deleteFetcher(key));
1113 mountedFetchers.forEach((key) => state.fetchers.delete(key));
1114 }
1115 function completeNavigation(location, newState, { flushSync } = {}) {
1116 let isActionReload = state.actionData != null && state.navigation.formMethod != null && isMutationMethod(state.navigation.formMethod) && state.navigation.state === "loading" && location.state?._isRedirect !== true;
1117 let actionData;
1118 if (newState.actionData) {
1119 if (Object.keys(newState.actionData).length > 0) {
1120 actionData = newState.actionData;
1121 } else {
1122 actionData = null;
1123 }
1124 } else if (isActionReload) {
1125 actionData = state.actionData;
1126 } else {
1127 actionData = null;
1128 }
1129 let loaderData = newState.loaderData ? mergeLoaderData(
1130 state.loaderData,
1131 newState.loaderData,
1132 newState.matches || [],
1133 newState.errors
1134 ) : state.loaderData;
1135 let blockers = state.blockers;
1136 if (blockers.size > 0) {
1137 blockers = new Map(blockers);
1138 blockers.forEach((_, k) => blockers.set(k, IDLE_BLOCKER));
1139 }
1140 let preventScrollReset = pendingPreventScrollReset === true || state.navigation.formMethod != null && isMutationMethod(state.navigation.formMethod) && location.state?._isRedirect !== true;
1141 if (inFlightDataRoutes) {
1142 dataRoutes = inFlightDataRoutes;
1143 inFlightDataRoutes = void 0;
1144 }
1145 if (isUninterruptedRevalidation) {
1146 } else if (pendingAction === "POP" /* Pop */) {
1147 } else if (pendingAction === "PUSH" /* Push */) {
1148 init.history.push(location, location.state);
1149 } else if (pendingAction === "REPLACE" /* Replace */) {
1150 init.history.replace(location, location.state);
1151 }
1152 let viewTransitionOpts;
1153 if (pendingAction === "POP" /* Pop */) {
1154 let priorPaths = appliedViewTransitions.get(state.location.pathname);
1155 if (priorPaths && priorPaths.has(location.pathname)) {
1156 viewTransitionOpts = {
1157 currentLocation: state.location,
1158 nextLocation: location
1159 };
1160 } else if (appliedViewTransitions.has(location.pathname)) {
1161 viewTransitionOpts = {
1162 currentLocation: location,
1163 nextLocation: state.location
1164 };
1165 }
1166 } else if (pendingViewTransitionEnabled) {
1167 let toPaths = appliedViewTransitions.get(state.location.pathname);
1168 if (toPaths) {
1169 toPaths.add(location.pathname);
1170 } else {
1171 toPaths = /* @__PURE__ */ new Set([location.pathname]);
1172 appliedViewTransitions.set(state.location.pathname, toPaths);
1173 }
1174 viewTransitionOpts = {
1175 currentLocation: state.location,
1176 nextLocation: location
1177 };
1178 }
1179 updateState(
1180 {
1181 ...newState,
1182 // matches, errors, fetchers go through as-is
1183 actionData,
1184 loaderData,
1185 historyAction: pendingAction,
1186 location,
1187 initialized: true,
1188 navigation: IDLE_NAVIGATION,
1189 revalidation: "idle",
1190 restoreScrollPosition: getSavedScrollPosition(
1191 location,
1192 newState.matches || state.matches
1193 ),
1194 preventScrollReset,
1195 blockers
1196 },
1197 {
1198 viewTransitionOpts,
1199 flushSync: flushSync === true
1200 }
1201 );
1202 pendingAction = "POP" /* Pop */;
1203 pendingPreventScrollReset = false;
1204 pendingViewTransitionEnabled = false;
1205 isUninterruptedRevalidation = false;
1206 isRevalidationRequired = false;
1207 pendingRevalidationDfd?.resolve();
1208 pendingRevalidationDfd = null;
1209 }
1210 async function navigate(to, opts) {
1211 if (typeof to === "number") {
1212 init.history.go(to);
1213 return;
1214 }
1215 let normalizedPath = normalizeTo(
1216 state.location,
1217 state.matches,
1218 basename,
1219 to,
1220 opts?.fromRouteId,
1221 opts?.relative
1222 );
1223 let { path, submission, error } = normalizeNavigateOptions(
1224 false,
1225 normalizedPath,
1226 opts
1227 );
1228 let currentLocation = state.location;
1229 let nextLocation = createLocation(state.location, path, opts && opts.state);
1230 nextLocation = {
1231 ...nextLocation,
1232 ...init.history.encodeLocation(nextLocation)
1233 };
1234 let userReplace = opts && opts.replace != null ? opts.replace : void 0;
1235 let historyAction = "PUSH" /* Push */;
1236 if (userReplace === true) {
1237 historyAction = "REPLACE" /* Replace */;
1238 } else if (userReplace === false) {
1239 } else if (submission != null && isMutationMethod(submission.formMethod) && submission.formAction === state.location.pathname + state.location.search) {
1240 historyAction = "REPLACE" /* Replace */;
1241 }
1242 let preventScrollReset = opts && "preventScrollReset" in opts ? opts.preventScrollReset === true : void 0;
1243 let flushSync = (opts && opts.flushSync) === true;
1244 let blockerKey = shouldBlockNavigation({
1245 currentLocation,
1246 nextLocation,
1247 historyAction
1248 });
1249 if (blockerKey) {
1250 updateBlocker(blockerKey, {
1251 state: "blocked",
1252 location: nextLocation,
1253 proceed() {
1254 updateBlocker(blockerKey, {
1255 state: "proceeding",
1256 proceed: void 0,
1257 reset: void 0,
1258 location: nextLocation
1259 });
1260 navigate(to, opts);
1261 },
1262 reset() {
1263 let blockers = new Map(state.blockers);
1264 blockers.set(blockerKey, IDLE_BLOCKER);
1265 updateState({ blockers });
1266 }
1267 });
1268 return;
1269 }
1270 await startNavigation(historyAction, nextLocation, {
1271 submission,
1272 // Send through the formData serialization error if we have one so we can
1273 // render at the right error boundary after we match routes
1274 pendingError: error,
1275 preventScrollReset,
1276 replace: opts && opts.replace,
1277 enableViewTransition: opts && opts.viewTransition,
1278 flushSync
1279 });
1280 }
1281 function revalidate() {
1282 if (!pendingRevalidationDfd) {
1283 pendingRevalidationDfd = createDeferred();
1284 }
1285 interruptActiveLoads();
1286 updateState({ revalidation: "loading" });
1287 let promise = pendingRevalidationDfd.promise;
1288 if (state.navigation.state === "submitting") {
1289 return promise;
1290 }
1291 if (state.navigation.state === "idle") {
1292 startNavigation(state.historyAction, state.location, {
1293 startUninterruptedRevalidation: true
1294 });
1295 return promise;
1296 }
1297 startNavigation(
1298 pendingAction || state.historyAction,
1299 state.navigation.location,
1300 {
1301 overrideNavigation: state.navigation,
1302 // Proxy through any rending view transition
1303 enableViewTransition: pendingViewTransitionEnabled === true
1304 }
1305 );
1306 return promise;
1307 }
1308 async function startNavigation(historyAction, location, opts) {
1309 pendingNavigationController && pendingNavigationController.abort();
1310 pendingNavigationController = null;
1311 pendingAction = historyAction;
1312 isUninterruptedRevalidation = (opts && opts.startUninterruptedRevalidation) === true;
1313 saveScrollPosition(state.location, state.matches);
1314 pendingPreventScrollReset = (opts && opts.preventScrollReset) === true;
1315 pendingViewTransitionEnabled = (opts && opts.enableViewTransition) === true;
1316 let routesToUse = inFlightDataRoutes || dataRoutes;
1317 let loadingNavigation = opts && opts.overrideNavigation;
1318 let matches = opts?.initialHydration && state.matches && state.matches.length > 0 && !initialMatchesIsFOW ? (
1319 // `matchRoutes()` has already been called if we're in here via `router.initialize()`
1320 state.matches
1321 ) : matchRoutes(routesToUse, location, basename);
1322 let flushSync = (opts && opts.flushSync) === true;
1323 if (matches && state.initialized && !isRevalidationRequired && isHashChangeOnly(state.location, location) && !(opts && opts.submission && isMutationMethod(opts.submission.formMethod))) {
1324 completeNavigation(location, { matches }, { flushSync });
1325 return;
1326 }
1327 let fogOfWar = checkFogOfWar(matches, routesToUse, location.pathname);
1328 if (fogOfWar.active && fogOfWar.matches) {
1329 matches = fogOfWar.matches;
1330 }
1331 if (!matches) {
1332 let { error, notFoundMatches, route } = handleNavigational404(
1333 location.pathname
1334 );
1335 completeNavigation(
1336 location,
1337 {
1338 matches: notFoundMatches,
1339 loaderData: {},
1340 errors: {
1341 [route.id]: error
1342 }
1343 },
1344 { flushSync }
1345 );
1346 return;
1347 }
1348 pendingNavigationController = new AbortController();
1349 let request = createClientSideRequest(
1350 init.history,
1351 location,
1352 pendingNavigationController.signal,
1353 opts && opts.submission
1354 );
1355 let pendingActionResult;
1356 if (opts && opts.pendingError) {
1357 pendingActionResult = [
1358 findNearestBoundary(matches).route.id,
1359 { type: "error" /* error */, error: opts.pendingError }
1360 ];
1361 } else if (opts && opts.submission && isMutationMethod(opts.submission.formMethod)) {
1362 let actionResult = await handleAction(
1363 request,
1364 location,
1365 opts.submission,
1366 matches,
1367 fogOfWar.active,
1368 { replace: opts.replace, flushSync }
1369 );
1370 if (actionResult.shortCircuited) {
1371 return;
1372 }
1373 if (actionResult.pendingActionResult) {
1374 let [routeId, result] = actionResult.pendingActionResult;
1375 if (isErrorResult(result) && isRouteErrorResponse(result.error) && result.error.status === 404) {
1376 pendingNavigationController = null;
1377 completeNavigation(location, {
1378 matches: actionResult.matches,
1379 loaderData: {},
1380 errors: {
1381 [routeId]: result.error
1382 }
1383 });
1384 return;
1385 }
1386 }
1387 matches = actionResult.matches || matches;
1388 pendingActionResult = actionResult.pendingActionResult;
1389 loadingNavigation = getLoadingNavigation(location, opts.submission);
1390 flushSync = false;
1391 fogOfWar.active = false;
1392 request = createClientSideRequest(
1393 init.history,
1394 request.url,
1395 request.signal
1396 );
1397 }
1398 let {
1399 shortCircuited,
1400 matches: updatedMatches,
1401 loaderData,
1402 errors
1403 } = await handleLoaders(
1404 request,
1405 location,
1406 matches,
1407 fogOfWar.active,
1408 loadingNavigation,
1409 opts && opts.submission,
1410 opts && opts.fetcherSubmission,
1411 opts && opts.replace,
1412 opts && opts.initialHydration === true,
1413 flushSync,
1414 pendingActionResult
1415 );
1416 if (shortCircuited) {
1417 return;
1418 }
1419 pendingNavigationController = null;
1420 completeNavigation(location, {
1421 matches: updatedMatches || matches,
1422 ...getActionDataForCommit(pendingActionResult),
1423 loaderData,
1424 errors
1425 });
1426 }
1427 async function handleAction(request, location, submission, matches, isFogOfWar, opts = {}) {
1428 interruptActiveLoads();
1429 let navigation = getSubmittingNavigation(location, submission);
1430 updateState({ navigation }, { flushSync: opts.flushSync === true });
1431 if (isFogOfWar) {
1432 let discoverResult = await discoverRoutes(
1433 matches,
1434 location.pathname,
1435 request.signal
1436 );
1437 if (discoverResult.type === "aborted") {
1438 return { shortCircuited: true };
1439 } else if (discoverResult.type === "error") {
1440 let boundaryId = findNearestBoundary(discoverResult.partialMatches).route.id;
1441 return {
1442 matches: discoverResult.partialMatches,
1443 pendingActionResult: [
1444 boundaryId,
1445 {
1446 type: "error" /* error */,
1447 error: discoverResult.error
1448 }
1449 ]
1450 };
1451 } else if (!discoverResult.matches) {
1452 let { notFoundMatches, error, route } = handleNavigational404(
1453 location.pathname
1454 );
1455 return {
1456 matches: notFoundMatches,
1457 pendingActionResult: [
1458 route.id,
1459 {
1460 type: "error" /* error */,
1461 error
1462 }
1463 ]
1464 };
1465 } else {
1466 matches = discoverResult.matches;
1467 }
1468 }
1469 let result;
1470 let actionMatch = getTargetMatch(matches, location);
1471 if (!actionMatch.route.action && !actionMatch.route.lazy) {
1472 result = {
1473 type: "error" /* error */,
1474 error: getInternalRouterError(405, {
1475 method: request.method,
1476 pathname: location.pathname,
1477 routeId: actionMatch.route.id
1478 })
1479 };
1480 } else {
1481 let results = await callDataStrategy(
1482 "action",
1483 state,
1484 request,
1485 [actionMatch],
1486 matches,
1487 null
1488 );
1489 result = results[actionMatch.route.id];
1490 if (request.signal.aborted) {
1491 return { shortCircuited: true };
1492 }
1493 }
1494 if (isRedirectResult(result)) {
1495 let replace2;
1496 if (opts && opts.replace != null) {
1497 replace2 = opts.replace;
1498 } else {
1499 let location2 = normalizeRedirectLocation(
1500 result.response.headers.get("Location"),
1501 new URL(request.url),
1502 basename
1503 );
1504 replace2 = location2 === state.location.pathname + state.location.search;
1505 }
1506 await startRedirectNavigation(request, result, true, {
1507 submission,
1508 replace: replace2
1509 });
1510 return { shortCircuited: true };
1511 }
1512 if (isErrorResult(result)) {
1513 let boundaryMatch = findNearestBoundary(matches, actionMatch.route.id);
1514 if ((opts && opts.replace) !== true) {
1515 pendingAction = "PUSH" /* Push */;
1516 }
1517 return {
1518 matches,
1519 pendingActionResult: [boundaryMatch.route.id, result]
1520 };
1521 }
1522 return {
1523 matches,
1524 pendingActionResult: [actionMatch.route.id, result]
1525 };
1526 }
1527 async function handleLoaders(request, location, matches, isFogOfWar, overrideNavigation, submission, fetcherSubmission, replace2, initialHydration, flushSync, pendingActionResult) {
1528 let loadingNavigation = overrideNavigation || getLoadingNavigation(location, submission);
1529 let activeSubmission = submission || fetcherSubmission || getSubmissionFromNavigation(loadingNavigation);
1530 let shouldUpdateNavigationState = !isUninterruptedRevalidation && !initialHydration;
1531 if (isFogOfWar) {
1532 if (shouldUpdateNavigationState) {
1533 let actionData = getUpdatedActionData(pendingActionResult);
1534 updateState(
1535 {
1536 navigation: loadingNavigation,
1537 ...actionData !== void 0 ? { actionData } : {}
1538 },
1539 {
1540 flushSync
1541 }
1542 );
1543 }
1544 let discoverResult = await discoverRoutes(
1545 matches,
1546 location.pathname,
1547 request.signal
1548 );
1549 if (discoverResult.type === "aborted") {
1550 return { shortCircuited: true };
1551 } else if (discoverResult.type === "error") {
1552 let boundaryId = findNearestBoundary(discoverResult.partialMatches).route.id;
1553 return {
1554 matches: discoverResult.partialMatches,
1555 loaderData: {},
1556 errors: {
1557 [boundaryId]: discoverResult.error
1558 }
1559 };
1560 } else if (!discoverResult.matches) {
1561 let { error, notFoundMatches, route } = handleNavigational404(
1562 location.pathname
1563 );
1564 return {
1565 matches: notFoundMatches,
1566 loaderData: {},
1567 errors: {
1568 [route.id]: error
1569 }
1570 };
1571 } else {
1572 matches = discoverResult.matches;
1573 }
1574 }
1575 let routesToUse = inFlightDataRoutes || dataRoutes;
1576 let [matchesToLoad, revalidatingFetchers] = getMatchesToLoad(
1577 init.history,
1578 state,
1579 matches,
1580 activeSubmission,
1581 location,
1582 initialHydration === true,
1583 isRevalidationRequired,
1584 cancelledFetcherLoads,
1585 fetchersQueuedForDeletion,
1586 fetchLoadMatches,
1587 fetchRedirectIds,
1588 routesToUse,
1589 basename,
1590 pendingActionResult
1591 );
1592 pendingNavigationLoadId = ++incrementingLoadId;
1593 if (matchesToLoad.length === 0 && revalidatingFetchers.length === 0) {
1594 let updatedFetchers2 = markFetchRedirectsDone();
1595 completeNavigation(
1596 location,
1597 {
1598 matches,
1599 loaderData: {},
1600 // Commit pending error if we're short circuiting
1601 errors: pendingActionResult && isErrorResult(pendingActionResult[1]) ? { [pendingActionResult[0]]: pendingActionResult[1].error } : null,
1602 ...getActionDataForCommit(pendingActionResult),
1603 ...updatedFetchers2 ? { fetchers: new Map(state.fetchers) } : {}
1604 },
1605 { flushSync }
1606 );
1607 return { shortCircuited: true };
1608 }
1609 if (shouldUpdateNavigationState) {
1610 let updates = {};
1611 if (!isFogOfWar) {
1612 updates.navigation = loadingNavigation;
1613 let actionData = getUpdatedActionData(pendingActionResult);
1614 if (actionData !== void 0) {
1615 updates.actionData = actionData;
1616 }
1617 }
1618 if (revalidatingFetchers.length > 0) {
1619 updates.fetchers = getUpdatedRevalidatingFetchers(revalidatingFetchers);
1620 }
1621 updateState(updates, { flushSync });
1622 }
1623 revalidatingFetchers.forEach((rf) => {
1624 abortFetcher(rf.key);
1625 if (rf.controller) {
1626 fetchControllers.set(rf.key, rf.controller);
1627 }
1628 });
1629 let abortPendingFetchRevalidations = () => revalidatingFetchers.forEach((f) => abortFetcher(f.key));
1630 if (pendingNavigationController) {
1631 pendingNavigationController.signal.addEventListener(
1632 "abort",
1633 abortPendingFetchRevalidations
1634 );
1635 }
1636 let { loaderResults, fetcherResults } = await callLoadersAndMaybeResolveData(
1637 state,
1638 matches,
1639 matchesToLoad,
1640 revalidatingFetchers,
1641 request
1642 );
1643 if (request.signal.aborted) {
1644 return { shortCircuited: true };
1645 }
1646 if (pendingNavigationController) {
1647 pendingNavigationController.signal.removeEventListener(
1648 "abort",
1649 abortPendingFetchRevalidations
1650 );
1651 }
1652 revalidatingFetchers.forEach((rf) => fetchControllers.delete(rf.key));
1653 let redirect2 = findRedirect(loaderResults);
1654 if (redirect2) {
1655 await startRedirectNavigation(request, redirect2.result, true, {
1656 replace: replace2
1657 });
1658 return { shortCircuited: true };
1659 }
1660 redirect2 = findRedirect(fetcherResults);
1661 if (redirect2) {
1662 fetchRedirectIds.add(redirect2.key);
1663 await startRedirectNavigation(request, redirect2.result, true, {
1664 replace: replace2
1665 });
1666 return { shortCircuited: true };
1667 }
1668 let { loaderData, errors } = processLoaderData(
1669 state,
1670 matches,
1671 loaderResults,
1672 pendingActionResult,
1673 revalidatingFetchers,
1674 fetcherResults
1675 );
1676 if (initialHydration && state.errors) {
1677 errors = { ...state.errors, ...errors };
1678 }
1679 let updatedFetchers = markFetchRedirectsDone();
1680 let didAbortFetchLoads = abortStaleFetchLoads(pendingNavigationLoadId);
1681 let shouldUpdateFetchers = updatedFetchers || didAbortFetchLoads || revalidatingFetchers.length > 0;
1682 return {
1683 matches,
1684 loaderData,
1685 errors,
1686 ...shouldUpdateFetchers ? { fetchers: new Map(state.fetchers) } : {}
1687 };
1688 }
1689 function getUpdatedActionData(pendingActionResult) {
1690 if (pendingActionResult && !isErrorResult(pendingActionResult[1])) {
1691 return {
1692 [pendingActionResult[0]]: pendingActionResult[1].data
1693 };
1694 } else if (state.actionData) {
1695 if (Object.keys(state.actionData).length === 0) {
1696 return null;
1697 } else {
1698 return state.actionData;
1699 }
1700 }
1701 }
1702 function getUpdatedRevalidatingFetchers(revalidatingFetchers) {
1703 revalidatingFetchers.forEach((rf) => {
1704 let fetcher = state.fetchers.get(rf.key);
1705 let revalidatingFetcher = getLoadingFetcher(
1706 void 0,
1707 fetcher ? fetcher.data : void 0
1708 );
1709 state.fetchers.set(rf.key, revalidatingFetcher);
1710 });
1711 return new Map(state.fetchers);
1712 }
1713 async function fetch2(key, routeId, href, opts) {
1714 abortFetcher(key);
1715 let flushSync = (opts && opts.flushSync) === true;
1716 let routesToUse = inFlightDataRoutes || dataRoutes;
1717 let normalizedPath = normalizeTo(
1718 state.location,
1719 state.matches,
1720 basename,
1721 href,
1722 routeId,
1723 opts?.relative
1724 );
1725 let matches = matchRoutes(routesToUse, normalizedPath, basename);
1726 let fogOfWar = checkFogOfWar(matches, routesToUse, normalizedPath);
1727 if (fogOfWar.active && fogOfWar.matches) {
1728 matches = fogOfWar.matches;
1729 }
1730 if (!matches) {
1731 setFetcherError(
1732 key,
1733 routeId,
1734 getInternalRouterError(404, { pathname: normalizedPath }),
1735 { flushSync }
1736 );
1737 return;
1738 }
1739 let { path, submission, error } = normalizeNavigateOptions(
1740 true,
1741 normalizedPath,
1742 opts
1743 );
1744 if (error) {
1745 setFetcherError(key, routeId, error, { flushSync });
1746 return;
1747 }
1748 let match = getTargetMatch(matches, path);
1749 let preventScrollReset = (opts && opts.preventScrollReset) === true;
1750 if (submission && isMutationMethod(submission.formMethod)) {
1751 await handleFetcherAction(
1752 key,
1753 routeId,
1754 path,
1755 match,
1756 matches,
1757 fogOfWar.active,
1758 flushSync,
1759 preventScrollReset,
1760 submission
1761 );
1762 return;
1763 }
1764 fetchLoadMatches.set(key, { routeId, path });
1765 await handleFetcherLoader(
1766 key,
1767 routeId,
1768 path,
1769 match,
1770 matches,
1771 fogOfWar.active,
1772 flushSync,
1773 preventScrollReset,
1774 submission
1775 );
1776 }
1777 async function handleFetcherAction(key, routeId, path, match, requestMatches, isFogOfWar, flushSync, preventScrollReset, submission) {
1778 interruptActiveLoads();
1779 fetchLoadMatches.delete(key);
1780 function detectAndHandle405Error(m) {
1781 if (!m.route.action && !m.route.lazy) {
1782 let error = getInternalRouterError(405, {
1783 method: submission.formMethod,
1784 pathname: path,
1785 routeId
1786 });
1787 setFetcherError(key, routeId, error, { flushSync });
1788 return true;
1789 }
1790 return false;
1791 }
1792 if (!isFogOfWar && detectAndHandle405Error(match)) {
1793 return;
1794 }
1795 let existingFetcher = state.fetchers.get(key);
1796 updateFetcherState(key, getSubmittingFetcher(submission, existingFetcher), {
1797 flushSync
1798 });
1799 let abortController = new AbortController();
1800 let fetchRequest = createClientSideRequest(
1801 init.history,
1802 path,
1803 abortController.signal,
1804 submission
1805 );
1806 if (isFogOfWar) {
1807 let discoverResult = await discoverRoutes(
1808 requestMatches,
1809 path,
1810 fetchRequest.signal
1811 );
1812 if (discoverResult.type === "aborted") {
1813 return;
1814 } else if (discoverResult.type === "error") {
1815 setFetcherError(key, routeId, discoverResult.error, { flushSync });
1816 return;
1817 } else if (!discoverResult.matches) {
1818 setFetcherError(
1819 key,
1820 routeId,
1821 getInternalRouterError(404, { pathname: path }),
1822 { flushSync }
1823 );
1824 return;
1825 } else {
1826 requestMatches = discoverResult.matches;
1827 match = getTargetMatch(requestMatches, path);
1828 if (detectAndHandle405Error(match)) {
1829 return;
1830 }
1831 }
1832 }
1833 fetchControllers.set(key, abortController);
1834 let originatingLoadId = incrementingLoadId;
1835 let actionResults = await callDataStrategy(
1836 "action",
1837 state,
1838 fetchRequest,
1839 [match],
1840 requestMatches,
1841 key
1842 );
1843 let actionResult = actionResults[match.route.id];
1844 if (fetchRequest.signal.aborted) {
1845 if (fetchControllers.get(key) === abortController) {
1846 fetchControllers.delete(key);
1847 }
1848 return;
1849 }
1850 if (fetchersQueuedForDeletion.has(key)) {
1851 if (isRedirectResult(actionResult) || isErrorResult(actionResult)) {
1852 updateFetcherState(key, getDoneFetcher(void 0));
1853 return;
1854 }
1855 } else {
1856 if (isRedirectResult(actionResult)) {
1857 fetchControllers.delete(key);
1858 if (pendingNavigationLoadId > originatingLoadId) {
1859 updateFetcherState(key, getDoneFetcher(void 0));
1860 return;
1861 } else {
1862 fetchRedirectIds.add(key);
1863 updateFetcherState(key, getLoadingFetcher(submission));
1864 return startRedirectNavigation(fetchRequest, actionResult, false, {
1865 fetcherSubmission: submission,
1866 preventScrollReset
1867 });
1868 }
1869 }
1870 if (isErrorResult(actionResult)) {
1871 setFetcherError(key, routeId, actionResult.error);
1872 return;
1873 }
1874 }
1875 let nextLocation = state.navigation.location || state.location;
1876 let revalidationRequest = createClientSideRequest(
1877 init.history,
1878 nextLocation,
1879 abortController.signal
1880 );
1881 let routesToUse = inFlightDataRoutes || dataRoutes;
1882 let matches = state.navigation.state !== "idle" ? matchRoutes(routesToUse, state.navigation.location, basename) : state.matches;
1883 invariant(matches, "Didn't find any matches after fetcher action");
1884 let loadId = ++incrementingLoadId;
1885 fetchReloadIds.set(key, loadId);
1886 let loadFetcher = getLoadingFetcher(submission, actionResult.data);
1887 state.fetchers.set(key, loadFetcher);
1888 let [matchesToLoad, revalidatingFetchers] = getMatchesToLoad(
1889 init.history,
1890 state,
1891 matches,
1892 submission,
1893 nextLocation,
1894 false,
1895 isRevalidationRequired,
1896 cancelledFetcherLoads,
1897 fetchersQueuedForDeletion,
1898 fetchLoadMatches,
1899 fetchRedirectIds,
1900 routesToUse,
1901 basename,
1902 [match.route.id, actionResult]
1903 );
1904 revalidatingFetchers.filter((rf) => rf.key !== key).forEach((rf) => {
1905 let staleKey = rf.key;
1906 let existingFetcher2 = state.fetchers.get(staleKey);
1907 let revalidatingFetcher = getLoadingFetcher(
1908 void 0,
1909 existingFetcher2 ? existingFetcher2.data : void 0
1910 );
1911 state.fetchers.set(staleKey, revalidatingFetcher);
1912 abortFetcher(staleKey);
1913 if (rf.controller) {
1914 fetchControllers.set(staleKey, rf.controller);
1915 }
1916 });
1917 updateState({ fetchers: new Map(state.fetchers) });
1918 let abortPendingFetchRevalidations = () => revalidatingFetchers.forEach((rf) => abortFetcher(rf.key));
1919 abortController.signal.addEventListener(
1920 "abort",
1921 abortPendingFetchRevalidations
1922 );
1923 let { loaderResults, fetcherResults } = await callLoadersAndMaybeResolveData(
1924 state,
1925 matches,
1926 matchesToLoad,
1927 revalidatingFetchers,
1928 revalidationRequest
1929 );
1930 if (abortController.signal.aborted) {
1931 return;
1932 }
1933 abortController.signal.removeEventListener(
1934 "abort",
1935 abortPendingFetchRevalidations
1936 );
1937 fetchReloadIds.delete(key);
1938 fetchControllers.delete(key);
1939 revalidatingFetchers.forEach((r) => fetchControllers.delete(r.key));
1940 let redirect2 = findRedirect(loaderResults);
1941 if (redirect2) {
1942 return startRedirectNavigation(
1943 revalidationRequest,
1944 redirect2.result,
1945 false,
1946 { preventScrollReset }
1947 );
1948 }
1949 redirect2 = findRedirect(fetcherResults);
1950 if (redirect2) {
1951 fetchRedirectIds.add(redirect2.key);
1952 return startRedirectNavigation(
1953 revalidationRequest,
1954 redirect2.result,
1955 false,
1956 { preventScrollReset }
1957 );
1958 }
1959 let { loaderData, errors } = processLoaderData(
1960 state,
1961 matches,
1962 loaderResults,
1963 void 0,
1964 revalidatingFetchers,
1965 fetcherResults
1966 );
1967 if (state.fetchers.has(key)) {
1968 let doneFetcher = getDoneFetcher(actionResult.data);
1969 state.fetchers.set(key, doneFetcher);
1970 }
1971 abortStaleFetchLoads(loadId);
1972 if (state.navigation.state === "loading" && loadId > pendingNavigationLoadId) {
1973 invariant(pendingAction, "Expected pending action");
1974 pendingNavigationController && pendingNavigationController.abort();
1975 completeNavigation(state.navigation.location, {
1976 matches,
1977 loaderData,
1978 errors,
1979 fetchers: new Map(state.fetchers)
1980 });
1981 } else {
1982 updateState({
1983 errors,
1984 loaderData: mergeLoaderData(
1985 state.loaderData,
1986 loaderData,
1987 matches,
1988 errors
1989 ),
1990 fetchers: new Map(state.fetchers)
1991 });
1992 isRevalidationRequired = false;
1993 }
1994 }
1995 async function handleFetcherLoader(key, routeId, path, match, matches, isFogOfWar, flushSync, preventScrollReset, submission) {
1996 let existingFetcher = state.fetchers.get(key);
1997 updateFetcherState(
1998 key,
1999 getLoadingFetcher(
2000 submission,
2001 existingFetcher ? existingFetcher.data : void 0
2002 ),
2003 { flushSync }
2004 );
2005 let abortController = new AbortController();
2006 let fetchRequest = createClientSideRequest(
2007 init.history,
2008 path,
2009 abortController.signal
2010 );
2011 if (isFogOfWar) {
2012 let discoverResult = await discoverRoutes(
2013 matches,
2014 path,
2015 fetchRequest.signal
2016 );
2017 if (discoverResult.type === "aborted") {
2018 return;
2019 } else if (discoverResult.type === "error") {
2020 setFetcherError(key, routeId, discoverResult.error, { flushSync });
2021 return;
2022 } else if (!discoverResult.matches) {
2023 setFetcherError(
2024 key,
2025 routeId,
2026 getInternalRouterError(404, { pathname: path }),
2027 { flushSync }
2028 );
2029 return;
2030 } else {
2031 matches = discoverResult.matches;
2032 match = getTargetMatch(matches, path);
2033 }
2034 }
2035 fetchControllers.set(key, abortController);
2036 let originatingLoadId = incrementingLoadId;
2037 let results = await callDataStrategy(
2038 "loader",
2039 state,
2040 fetchRequest,
2041 [match],
2042 matches,
2043 key
2044 );
2045 let result = results[match.route.id];
2046 if (fetchControllers.get(key) === abortController) {
2047 fetchControllers.delete(key);
2048 }
2049 if (fetchRequest.signal.aborted) {
2050 return;
2051 }
2052 if (fetchersQueuedForDeletion.has(key)) {
2053 updateFetcherState(key, getDoneFetcher(void 0));
2054 return;
2055 }
2056 if (isRedirectResult(result)) {
2057 if (pendingNavigationLoadId > originatingLoadId) {
2058 updateFetcherState(key, getDoneFetcher(void 0));
2059 return;
2060 } else {
2061 fetchRedirectIds.add(key);
2062 await startRedirectNavigation(fetchRequest, result, false, {
2063 preventScrollReset
2064 });
2065 return;
2066 }
2067 }
2068 if (isErrorResult(result)) {
2069 setFetcherError(key, routeId, result.error);
2070 return;
2071 }
2072 updateFetcherState(key, getDoneFetcher(result.data));
2073 }
2074 async function startRedirectNavigation(request, redirect2, isNavigation, {
2075 submission,
2076 fetcherSubmission,
2077 preventScrollReset,
2078 replace: replace2
2079 } = {}) {
2080 if (redirect2.response.headers.has("X-Remix-Revalidate")) {
2081 isRevalidationRequired = true;
2082 }
2083 let location = redirect2.response.headers.get("Location");
2084 invariant(location, "Expected a Location header on the redirect Response");
2085 location = normalizeRedirectLocation(
2086 location,
2087 new URL(request.url),
2088 basename
2089 );
2090 let redirectLocation = createLocation(state.location, location, {
2091 _isRedirect: true
2092 });
2093 if (isBrowser2) {
2094 let isDocumentReload = false;
2095 if (redirect2.response.headers.has("X-Remix-Reload-Document")) {
2096 isDocumentReload = true;
2097 } else if (ABSOLUTE_URL_REGEX.test(location)) {
2098 const url = init.history.createURL(location);
2099 isDocumentReload = // Hard reload if it's an absolute URL to a new origin
2100 url.origin !== routerWindow.location.origin || // Hard reload if it's an absolute URL that does not match our basename
2101 stripBasename(url.pathname, basename) == null;
2102 }
2103 if (isDocumentReload) {
2104 if (replace2) {
2105 routerWindow.location.replace(location);
2106 } else {
2107 routerWindow.location.assign(location);
2108 }
2109 return;
2110 }
2111 }
2112 pendingNavigationController = null;
2113 let redirectNavigationType = replace2 === true || redirect2.response.headers.has("X-Remix-Replace") ? "REPLACE" /* Replace */ : "PUSH" /* Push */;
2114 let { formMethod, formAction, formEncType } = state.navigation;
2115 if (!submission && !fetcherSubmission && formMethod && formAction && formEncType) {
2116 submission = getSubmissionFromNavigation(state.navigation);
2117 }
2118 let activeSubmission = submission || fetcherSubmission;
2119 if (redirectPreserveMethodStatusCodes.has(redirect2.response.status) && activeSubmission && isMutationMethod(activeSubmission.formMethod)) {
2120 await startNavigation(redirectNavigationType, redirectLocation, {
2121 submission: {
2122 ...activeSubmission,
2123 formAction: location
2124 },
2125 // Preserve these flags across redirects
2126 preventScrollReset: preventScrollReset || pendingPreventScrollReset,
2127 enableViewTransition: isNavigation ? pendingViewTransitionEnabled : void 0
2128 });
2129 } else {
2130 let overrideNavigation = getLoadingNavigation(
2131 redirectLocation,
2132 submission
2133 );
2134 await startNavigation(redirectNavigationType, redirectLocation, {
2135 overrideNavigation,
2136 // Send fetcher submissions through for shouldRevalidate
2137 fetcherSubmission,
2138 // Preserve these flags across redirects
2139 preventScrollReset: preventScrollReset || pendingPreventScrollReset,
2140 enableViewTransition: isNavigation ? pendingViewTransitionEnabled : void 0
2141 });
2142 }
2143 }
2144 async function callDataStrategy(type, state2, request, matchesToLoad, matches, fetcherKey) {
2145 let results;
2146 let dataResults = {};
2147 try {
2148 results = await callDataStrategyImpl(
2149 dataStrategyImpl,
2150 type,
2151 state2,
2152 request,
2153 matchesToLoad,
2154 matches,
2155 fetcherKey,
2156 manifest,
2157 mapRouteProperties2
2158 );
2159 } catch (e) {
2160 matchesToLoad.forEach((m) => {
2161 dataResults[m.route.id] = {
2162 type: "error" /* error */,
2163 error: e
2164 };
2165 });
2166 return dataResults;
2167 }
2168 for (let [routeId, result] of Object.entries(results)) {
2169 if (isRedirectDataStrategyResult(result)) {
2170 let response = result.result;
2171 dataResults[routeId] = {
2172 type: "redirect" /* redirect */,
2173 response: normalizeRelativeRoutingRedirectResponse(
2174 response,
2175 request,
2176 routeId,
2177 matches,
2178 basename
2179 )
2180 };
2181 } else {
2182 dataResults[routeId] = await convertDataStrategyResultToDataResult(
2183 result
2184 );
2185 }
2186 }
2187 return dataResults;
2188 }
2189 async function callLoadersAndMaybeResolveData(state2, matches, matchesToLoad, fetchersToLoad, request) {
2190 let loaderResultsPromise = callDataStrategy(
2191 "loader",
2192 state2,
2193 request,
2194 matchesToLoad,
2195 matches,
2196 null
2197 );
2198 let fetcherResultsPromise = Promise.all(
2199 fetchersToLoad.map(async (f) => {
2200 if (f.matches && f.match && f.controller) {
2201 let results = await callDataStrategy(
2202 "loader",
2203 state2,
2204 createClientSideRequest(init.history, f.path, f.controller.signal),
2205 [f.match],
2206 f.matches,
2207 f.key
2208 );
2209 let result = results[f.match.route.id];
2210 return { [f.key]: result };
2211 } else {
2212 return Promise.resolve({
2213 [f.key]: {
2214 type: "error" /* error */,
2215 error: getInternalRouterError(404, {
2216 pathname: f.path
2217 })
2218 }
2219 });
2220 }
2221 })
2222 );
2223 let loaderResults = await loaderResultsPromise;
2224 let fetcherResults = (await fetcherResultsPromise).reduce(
2225 (acc, r) => Object.assign(acc, r),
2226 {}
2227 );
2228 return {
2229 loaderResults,
2230 fetcherResults
2231 };
2232 }
2233 function interruptActiveLoads() {
2234 isRevalidationRequired = true;
2235 fetchLoadMatches.forEach((_, key) => {
2236 if (fetchControllers.has(key)) {
2237 cancelledFetcherLoads.add(key);
2238 }
2239 abortFetcher(key);
2240 });
2241 }
2242 function updateFetcherState(key, fetcher, opts = {}) {
2243 state.fetchers.set(key, fetcher);
2244 updateState(
2245 { fetchers: new Map(state.fetchers) },
2246 { flushSync: (opts && opts.flushSync) === true }
2247 );
2248 }
2249 function setFetcherError(key, routeId, error, opts = {}) {
2250 let boundaryMatch = findNearestBoundary(state.matches, routeId);
2251 deleteFetcher(key);
2252 updateState(
2253 {
2254 errors: {
2255 [boundaryMatch.route.id]: error
2256 },
2257 fetchers: new Map(state.fetchers)
2258 },
2259 { flushSync: (opts && opts.flushSync) === true }
2260 );
2261 }
2262 function getFetcher(key) {
2263 activeFetchers.set(key, (activeFetchers.get(key) || 0) + 1);
2264 if (fetchersQueuedForDeletion.has(key)) {
2265 fetchersQueuedForDeletion.delete(key);
2266 }
2267 return state.fetchers.get(key) || IDLE_FETCHER;
2268 }
2269 function deleteFetcher(key) {
2270 let fetcher = state.fetchers.get(key);
2271 if (fetchControllers.has(key) && !(fetcher && fetcher.state === "loading" && fetchReloadIds.has(key))) {
2272 abortFetcher(key);
2273 }
2274 fetchLoadMatches.delete(key);
2275 fetchReloadIds.delete(key);
2276 fetchRedirectIds.delete(key);
2277 fetchersQueuedForDeletion.delete(key);
2278 cancelledFetcherLoads.delete(key);
2279 state.fetchers.delete(key);
2280 }
2281 function queueFetcherForDeletion(key) {
2282 let count = (activeFetchers.get(key) || 0) - 1;
2283 if (count <= 0) {
2284 activeFetchers.delete(key);
2285 fetchersQueuedForDeletion.add(key);
2286 } else {
2287 activeFetchers.set(key, count);
2288 }
2289 updateState({ fetchers: new Map(state.fetchers) });
2290 }
2291 function abortFetcher(key) {
2292 let controller = fetchControllers.get(key);
2293 if (controller) {
2294 controller.abort();
2295 fetchControllers.delete(key);
2296 }
2297 }
2298 function markFetchersDone(keys) {
2299 for (let key of keys) {
2300 let fetcher = getFetcher(key);
2301 let doneFetcher = getDoneFetcher(fetcher.data);
2302 state.fetchers.set(key, doneFetcher);
2303 }
2304 }
2305 function markFetchRedirectsDone() {
2306 let doneKeys = [];
2307 let updatedFetchers = false;
2308 for (let key of fetchRedirectIds) {
2309 let fetcher = state.fetchers.get(key);
2310 invariant(fetcher, `Expected fetcher: ${key}`);
2311 if (fetcher.state === "loading") {
2312 fetchRedirectIds.delete(key);
2313 doneKeys.push(key);
2314 updatedFetchers = true;
2315 }
2316 }
2317 markFetchersDone(doneKeys);
2318 return updatedFetchers;
2319 }
2320 function abortStaleFetchLoads(landedId) {
2321 let yeetedKeys = [];
2322 for (let [key, id] of fetchReloadIds) {
2323 if (id < landedId) {
2324 let fetcher = state.fetchers.get(key);
2325 invariant(fetcher, `Expected fetcher: ${key}`);
2326 if (fetcher.state === "loading") {
2327 abortFetcher(key);
2328 fetchReloadIds.delete(key);
2329 yeetedKeys.push(key);
2330 }
2331 }
2332 }
2333 markFetchersDone(yeetedKeys);
2334 return yeetedKeys.length > 0;
2335 }
2336 function getBlocker(key, fn) {
2337 let blocker = state.blockers.get(key) || IDLE_BLOCKER;
2338 if (blockerFunctions.get(key) !== fn) {
2339 blockerFunctions.set(key, fn);
2340 }
2341 return blocker;
2342 }
2343 function deleteBlocker(key) {
2344 state.blockers.delete(key);
2345 blockerFunctions.delete(key);
2346 }
2347 function updateBlocker(key, newBlocker) {
2348 let blocker = state.blockers.get(key) || IDLE_BLOCKER;
2349 invariant(
2350 blocker.state === "unblocked" && newBlocker.state === "blocked" || blocker.state === "blocked" && newBlocker.state === "blocked" || blocker.state === "blocked" && newBlocker.state === "proceeding" || blocker.state === "blocked" && newBlocker.state === "unblocked" || blocker.state === "proceeding" && newBlocker.state === "unblocked",
2351 `Invalid blocker state transition: ${blocker.state} -> ${newBlocker.state}`
2352 );
2353 let blockers = new Map(state.blockers);
2354 blockers.set(key, newBlocker);
2355 updateState({ blockers });
2356 }
2357 function shouldBlockNavigation({
2358 currentLocation,
2359 nextLocation,
2360 historyAction
2361 }) {
2362 if (blockerFunctions.size === 0) {
2363 return;
2364 }
2365 if (blockerFunctions.size > 1) {
2366 warning(false, "A router only supports one blocker at a time");
2367 }
2368 let entries = Array.from(blockerFunctions.entries());
2369 let [blockerKey, blockerFunction] = entries[entries.length - 1];
2370 let blocker = state.blockers.get(blockerKey);
2371 if (blocker && blocker.state === "proceeding") {
2372 return;
2373 }
2374 if (blockerFunction({ currentLocation, nextLocation, historyAction })) {
2375 return blockerKey;
2376 }
2377 }
2378 function handleNavigational404(pathname) {
2379 let error = getInternalRouterError(404, { pathname });
2380 let routesToUse = inFlightDataRoutes || dataRoutes;
2381 let { matches, route } = getShortCircuitMatches(routesToUse);
2382 return { notFoundMatches: matches, route, error };
2383 }
2384 function enableScrollRestoration(positions, getPosition, getKey) {
2385 savedScrollPositions2 = positions;
2386 getScrollPosition = getPosition;
2387 getScrollRestorationKey2 = getKey || null;
2388 if (!initialScrollRestored && state.navigation === IDLE_NAVIGATION) {
2389 initialScrollRestored = true;
2390 let y = getSavedScrollPosition(state.location, state.matches);
2391 if (y != null) {
2392 updateState({ restoreScrollPosition: y });
2393 }
2394 }
2395 return () => {
2396 savedScrollPositions2 = null;
2397 getScrollPosition = null;
2398 getScrollRestorationKey2 = null;
2399 };
2400 }
2401 function getScrollKey(location, matches) {
2402 if (getScrollRestorationKey2) {
2403 let key = getScrollRestorationKey2(
2404 location,
2405 matches.map((m) => convertRouteMatchToUiMatch(m, state.loaderData))
2406 );
2407 return key || location.key;
2408 }
2409 return location.key;
2410 }
2411 function saveScrollPosition(location, matches) {
2412 if (savedScrollPositions2 && getScrollPosition) {
2413 let key = getScrollKey(location, matches);
2414 savedScrollPositions2[key] = getScrollPosition();
2415 }
2416 }
2417 function getSavedScrollPosition(location, matches) {
2418 if (savedScrollPositions2) {
2419 let key = getScrollKey(location, matches);
2420 let y = savedScrollPositions2[key];
2421 if (typeof y === "number") {
2422 return y;
2423 }
2424 }
2425 return null;
2426 }
2427 function checkFogOfWar(matches, routesToUse, pathname) {
2428 if (patchRoutesOnNavigationImpl) {
2429 if (!matches) {
2430 let fogMatches = matchRoutesImpl(
2431 routesToUse,
2432 pathname,
2433 basename,
2434 true
2435 );
2436 return { active: true, matches: fogMatches || [] };
2437 } else {
2438 if (Object.keys(matches[0].params).length > 0) {
2439 let partialMatches = matchRoutesImpl(
2440 routesToUse,
2441 pathname,
2442 basename,
2443 true
2444 );
2445 return { active: true, matches: partialMatches };
2446 }
2447 }
2448 }
2449 return { active: false, matches: null };
2450 }
2451 async function discoverRoutes(matches, pathname, signal) {
2452 if (!patchRoutesOnNavigationImpl) {
2453 return { type: "success", matches };
2454 }
2455 let partialMatches = matches;
2456 while (true) {
2457 let isNonHMR = inFlightDataRoutes == null;
2458 let routesToUse = inFlightDataRoutes || dataRoutes;
2459 let localManifest = manifest;
2460 try {
2461 await patchRoutesOnNavigationImpl({
2462 path: pathname,
2463 matches: partialMatches,
2464 patch: (routeId, children) => {
2465 if (signal.aborted) return;
2466 patchRoutesImpl(
2467 routeId,
2468 children,
2469 routesToUse,
2470 localManifest,
2471 mapRouteProperties2
2472 );
2473 }
2474 });
2475 } catch (e) {
2476 return { type: "error", error: e, partialMatches };
2477 } finally {
2478 if (isNonHMR && !signal.aborted) {
2479 dataRoutes = [...dataRoutes];
2480 }
2481 }
2482 if (signal.aborted) {
2483 return { type: "aborted" };
2484 }
2485 let newMatches = matchRoutes(routesToUse, pathname, basename);
2486 if (newMatches) {
2487 return { type: "success", matches: newMatches };
2488 }
2489 let newPartialMatches = matchRoutesImpl(
2490 routesToUse,
2491 pathname,
2492 basename,
2493 true
2494 );
2495 if (!newPartialMatches || partialMatches.length === newPartialMatches.length && partialMatches.every(
2496 (m, i) => m.route.id === newPartialMatches[i].route.id
2497 )) {
2498 return { type: "success", matches: null };
2499 }
2500 partialMatches = newPartialMatches;
2501 }
2502 }
2503 function _internalSetRoutes(newRoutes) {
2504 manifest = {};
2505 inFlightDataRoutes = convertRoutesToDataRoutes(
2506 newRoutes,
2507 mapRouteProperties2,
2508 void 0,
2509 manifest
2510 );
2511 }
2512 function patchRoutes(routeId, children) {
2513 let isNonHMR = inFlightDataRoutes == null;
2514 let routesToUse = inFlightDataRoutes || dataRoutes;
2515 patchRoutesImpl(
2516 routeId,
2517 children,
2518 routesToUse,
2519 manifest,
2520 mapRouteProperties2
2521 );
2522 if (isNonHMR) {
2523 dataRoutes = [...dataRoutes];
2524 updateState({});
2525 }
2526 }
2527 router = {
2528 get basename() {
2529 return basename;
2530 },
2531 get future() {
2532 return future;
2533 },
2534 get state() {
2535 return state;
2536 },
2537 get routes() {
2538 return dataRoutes;
2539 },
2540 get window() {
2541 return routerWindow;
2542 },
2543 initialize,
2544 subscribe,
2545 enableScrollRestoration,
2546 navigate,
2547 fetch: fetch2,
2548 revalidate,
2549 // Passthrough to history-aware createHref used by useHref so we get proper
2550 // hash-aware URLs in DOM paths
2551 createHref: (to) => init.history.createHref(to),
2552 encodeLocation: (to) => init.history.encodeLocation(to),
2553 getFetcher,
2554 deleteFetcher: queueFetcherForDeletion,
2555 dispose,
2556 getBlocker,
2557 deleteBlocker,
2558 patchRoutes,
2559 _internalFetchControllers: fetchControllers,
2560 // TODO: Remove setRoutes, it's temporary to avoid dealing with
2561 // updating the tree while validating the update algorithm.
2562 _internalSetRoutes
2563 };
2564 return router;
2565}
2566function createStaticHandler(routes, opts) {
2567 invariant(
2568 routes.length > 0,
2569 "You must provide a non-empty routes array to createStaticHandler"
2570 );
2571 let manifest = {};
2572 let basename = (opts ? opts.basename : null) || "/";
2573 let mapRouteProperties2 = opts?.mapRouteProperties || defaultMapRouteProperties;
2574 let dataRoutes = convertRoutesToDataRoutes(
2575 routes,
2576 mapRouteProperties2,
2577 void 0,
2578 manifest
2579 );
2580 async function query(request, {
2581 requestContext,
2582 skipLoaderErrorBubbling,
2583 dataStrategy
2584 } = {}) {
2585 let url = new URL(request.url);
2586 let method = request.method;
2587 let location = createLocation("", createPath(url), null, "default");
2588 let matches = matchRoutes(dataRoutes, location, basename);
2589 if (!isValidMethod(method) && method !== "HEAD") {
2590 let error = getInternalRouterError(405, { method });
2591 let { matches: methodNotAllowedMatches, route } = getShortCircuitMatches(dataRoutes);
2592 return {
2593 basename,
2594 location,
2595 matches: methodNotAllowedMatches,
2596 loaderData: {},
2597 actionData: null,
2598 errors: {
2599 [route.id]: error
2600 },
2601 statusCode: error.status,
2602 loaderHeaders: {},
2603 actionHeaders: {}
2604 };
2605 } else if (!matches) {
2606 let error = getInternalRouterError(404, { pathname: location.pathname });
2607 let { matches: notFoundMatches, route } = getShortCircuitMatches(dataRoutes);
2608 return {
2609 basename,
2610 location,
2611 matches: notFoundMatches,
2612 loaderData: {},
2613 actionData: null,
2614 errors: {
2615 [route.id]: error
2616 },
2617 statusCode: error.status,
2618 loaderHeaders: {},
2619 actionHeaders: {}
2620 };
2621 }
2622 let result = await queryImpl(
2623 request,
2624 location,
2625 matches,
2626 requestContext,
2627 dataStrategy || null,
2628 skipLoaderErrorBubbling === true,
2629 null
2630 );
2631 if (isResponse(result)) {
2632 return result;
2633 }
2634 return { location, basename, ...result };
2635 }
2636 async function queryRoute(request, {
2637 routeId,
2638 requestContext,
2639 dataStrategy
2640 } = {}) {
2641 let url = new URL(request.url);
2642 let method = request.method;
2643 let location = createLocation("", createPath(url), null, "default");
2644 let matches = matchRoutes(dataRoutes, location, basename);
2645 if (!isValidMethod(method) && method !== "HEAD" && method !== "OPTIONS") {
2646 throw getInternalRouterError(405, { method });
2647 } else if (!matches) {
2648 throw getInternalRouterError(404, { pathname: location.pathname });
2649 }
2650 let match = routeId ? matches.find((m) => m.route.id === routeId) : getTargetMatch(matches, location);
2651 if (routeId && !match) {
2652 throw getInternalRouterError(403, {
2653 pathname: location.pathname,
2654 routeId
2655 });
2656 } else if (!match) {
2657 throw getInternalRouterError(404, { pathname: location.pathname });
2658 }
2659 let result = await queryImpl(
2660 request,
2661 location,
2662 matches,
2663 requestContext,
2664 dataStrategy || null,
2665 false,
2666 match
2667 );
2668 if (isResponse(result)) {
2669 return result;
2670 }
2671 let error = result.errors ? Object.values(result.errors)[0] : void 0;
2672 if (error !== void 0) {
2673 throw error;
2674 }
2675 if (result.actionData) {
2676 return Object.values(result.actionData)[0];
2677 }
2678 if (result.loaderData) {
2679 return Object.values(result.loaderData)[0];
2680 }
2681 return void 0;
2682 }
2683 async function queryImpl(request, location, matches, requestContext, dataStrategy, skipLoaderErrorBubbling, routeMatch) {
2684 invariant(
2685 request.signal,
2686 "query()/queryRoute() requests must contain an AbortController signal"
2687 );
2688 try {
2689 if (isMutationMethod(request.method)) {
2690 let result2 = await submit(
2691 request,
2692 matches,
2693 routeMatch || getTargetMatch(matches, location),
2694 requestContext,
2695 dataStrategy,
2696 skipLoaderErrorBubbling,
2697 routeMatch != null
2698 );
2699 return result2;
2700 }
2701 let result = await loadRouteData(
2702 request,
2703 matches,
2704 requestContext,
2705 dataStrategy,
2706 skipLoaderErrorBubbling,
2707 routeMatch
2708 );
2709 return isResponse(result) ? result : {
2710 ...result,
2711 actionData: null,
2712 actionHeaders: {}
2713 };
2714 } catch (e) {
2715 if (isDataStrategyResult(e) && isResponse(e.result)) {
2716 if (e.type === "error" /* error */) {
2717 throw e.result;
2718 }
2719 return e.result;
2720 }
2721 if (isRedirectResponse(e)) {
2722 return e;
2723 }
2724 throw e;
2725 }
2726 }
2727 async function submit(request, matches, actionMatch, requestContext, dataStrategy, skipLoaderErrorBubbling, isRouteRequest) {
2728 let result;
2729 if (!actionMatch.route.action && !actionMatch.route.lazy) {
2730 let error = getInternalRouterError(405, {
2731 method: request.method,
2732 pathname: new URL(request.url).pathname,
2733 routeId: actionMatch.route.id
2734 });
2735 if (isRouteRequest) {
2736 throw error;
2737 }
2738 result = {
2739 type: "error" /* error */,
2740 error
2741 };
2742 } else {
2743 let results = await callDataStrategy(
2744 "action",
2745 request,
2746 [actionMatch],
2747 matches,
2748 isRouteRequest,
2749 requestContext,
2750 dataStrategy
2751 );
2752 result = results[actionMatch.route.id];
2753 if (request.signal.aborted) {
2754 throwStaticHandlerAbortedError(request, isRouteRequest);
2755 }
2756 }
2757 if (isRedirectResult(result)) {
2758 throw new Response(null, {
2759 status: result.response.status,
2760 headers: {
2761 Location: result.response.headers.get("Location")
2762 }
2763 });
2764 }
2765 if (isRouteRequest) {
2766 if (isErrorResult(result)) {
2767 throw result.error;
2768 }
2769 return {
2770 matches: [actionMatch],
2771 loaderData: {},
2772 actionData: { [actionMatch.route.id]: result.data },
2773 errors: null,
2774 // Note: statusCode + headers are unused here since queryRoute will
2775 // return the raw Response or value
2776 statusCode: 200,
2777 loaderHeaders: {},
2778 actionHeaders: {}
2779 };
2780 }
2781 let loaderRequest = new Request(request.url, {
2782 headers: request.headers,
2783 redirect: request.redirect,
2784 signal: request.signal
2785 });
2786 if (isErrorResult(result)) {
2787 let boundaryMatch = skipLoaderErrorBubbling ? actionMatch : findNearestBoundary(matches, actionMatch.route.id);
2788 let context2 = await loadRouteData(
2789 loaderRequest,
2790 matches,
2791 requestContext,
2792 dataStrategy,
2793 skipLoaderErrorBubbling,
2794 null,
2795 [boundaryMatch.route.id, result]
2796 );
2797 return {
2798 ...context2,
2799 statusCode: isRouteErrorResponse(result.error) ? result.error.status : result.statusCode != null ? result.statusCode : 500,
2800 actionData: null,
2801 actionHeaders: {
2802 ...result.headers ? { [actionMatch.route.id]: result.headers } : {}
2803 }
2804 };
2805 }
2806 let context = await loadRouteData(
2807 loaderRequest,
2808 matches,
2809 requestContext,
2810 dataStrategy,
2811 skipLoaderErrorBubbling,
2812 null
2813 );
2814 return {
2815 ...context,
2816 actionData: {
2817 [actionMatch.route.id]: result.data
2818 },
2819 // action status codes take precedence over loader status codes
2820 ...result.statusCode ? { statusCode: result.statusCode } : {},
2821 actionHeaders: result.headers ? { [actionMatch.route.id]: result.headers } : {}
2822 };
2823 }
2824 async function loadRouteData(request, matches, requestContext, dataStrategy, skipLoaderErrorBubbling, routeMatch, pendingActionResult) {
2825 let isRouteRequest = routeMatch != null;
2826 if (isRouteRequest && !routeMatch?.route.loader && !routeMatch?.route.lazy) {
2827 throw getInternalRouterError(400, {
2828 method: request.method,
2829 pathname: new URL(request.url).pathname,
2830 routeId: routeMatch?.route.id
2831 });
2832 }
2833 let requestMatches = routeMatch ? [routeMatch] : pendingActionResult && isErrorResult(pendingActionResult[1]) ? getLoaderMatchesUntilBoundary(matches, pendingActionResult[0]) : matches;
2834 let matchesToLoad = requestMatches.filter(
2835 (m) => m.route.loader || m.route.lazy
2836 );
2837 if (matchesToLoad.length === 0) {
2838 return {
2839 matches,
2840 // Add a null for all matched routes for proper revalidation on the client
2841 loaderData: matches.reduce(
2842 (acc, m) => Object.assign(acc, { [m.route.id]: null }),
2843 {}
2844 ),
2845 errors: pendingActionResult && isErrorResult(pendingActionResult[1]) ? {
2846 [pendingActionResult[0]]: pendingActionResult[1].error
2847 } : null,
2848 statusCode: 200,
2849 loaderHeaders: {}
2850 };
2851 }
2852 let results = await callDataStrategy(
2853 "loader",
2854 request,
2855 matchesToLoad,
2856 matches,
2857 isRouteRequest,
2858 requestContext,
2859 dataStrategy
2860 );
2861 if (request.signal.aborted) {
2862 throwStaticHandlerAbortedError(request, isRouteRequest);
2863 }
2864 let context = processRouteLoaderData(
2865 matches,
2866 results,
2867 pendingActionResult,
2868 true,
2869 skipLoaderErrorBubbling
2870 );
2871 let executedLoaders = new Set(
2872 matchesToLoad.map((match) => match.route.id)
2873 );
2874 matches.forEach((match) => {
2875 if (!executedLoaders.has(match.route.id)) {
2876 context.loaderData[match.route.id] = null;
2877 }
2878 });
2879 return {
2880 ...context,
2881 matches
2882 };
2883 }
2884 async function callDataStrategy(type, request, matchesToLoad, matches, isRouteRequest, requestContext, dataStrategy) {
2885 let results = await callDataStrategyImpl(
2886 dataStrategy || defaultDataStrategy,
2887 type,
2888 null,
2889 request,
2890 matchesToLoad,
2891 matches,
2892 null,
2893 manifest,
2894 mapRouteProperties2,
2895 requestContext
2896 );
2897 let dataResults = {};
2898 await Promise.all(
2899 matches.map(async (match) => {
2900 if (!(match.route.id in results)) {
2901 return;
2902 }
2903 let result = results[match.route.id];
2904 if (isRedirectDataStrategyResult(result)) {
2905 let response = result.result;
2906 throw normalizeRelativeRoutingRedirectResponse(
2907 response,
2908 request,
2909 match.route.id,
2910 matches,
2911 basename
2912 );
2913 }
2914 if (isResponse(result.result) && isRouteRequest) {
2915 throw result;
2916 }
2917 dataResults[match.route.id] = await convertDataStrategyResultToDataResult(result);
2918 })
2919 );
2920 return dataResults;
2921 }
2922 return {
2923 dataRoutes,
2924 query,
2925 queryRoute
2926 };
2927}
2928function getStaticContextFromError(routes, context, error) {
2929 let newContext = {
2930 ...context,
2931 statusCode: isRouteErrorResponse(error) ? error.status : 500,
2932 errors: {
2933 [context._deepestRenderedBoundaryId || routes[0].id]: error
2934 }
2935 };
2936 return newContext;
2937}
2938function throwStaticHandlerAbortedError(request, isRouteRequest) {
2939 if (request.signal.reason !== void 0) {
2940 throw request.signal.reason;
2941 }
2942 let method = isRouteRequest ? "queryRoute" : "query";
2943 throw new Error(
2944 `${method}() call aborted without an \`AbortSignal.reason\`: ${request.method} ${request.url}`
2945 );
2946}
2947function isSubmissionNavigation(opts) {
2948 return opts != null && ("formData" in opts && opts.formData != null || "body" in opts && opts.body !== void 0);
2949}
2950function normalizeTo(location, matches, basename, to, fromRouteId, relative) {
2951 let contextualMatches;
2952 let activeRouteMatch;
2953 if (fromRouteId) {
2954 contextualMatches = [];
2955 for (let match of matches) {
2956 contextualMatches.push(match);
2957 if (match.route.id === fromRouteId) {
2958 activeRouteMatch = match;
2959 break;
2960 }
2961 }
2962 } else {
2963 contextualMatches = matches;
2964 activeRouteMatch = matches[matches.length - 1];
2965 }
2966 let path = resolveTo(
2967 to ? to : ".",
2968 getResolveToMatches(contextualMatches),
2969 stripBasename(location.pathname, basename) || location.pathname,
2970 relative === "path"
2971 );
2972 if (to == null) {
2973 path.search = location.search;
2974 path.hash = location.hash;
2975 }
2976 if ((to == null || to === "" || to === ".") && activeRouteMatch) {
2977 let nakedIndex = hasNakedIndexQuery(path.search);
2978 if (activeRouteMatch.route.index && !nakedIndex) {
2979 path.search = path.search ? path.search.replace(/^\?/, "?index&") : "?index";
2980 } else if (!activeRouteMatch.route.index && nakedIndex) {
2981 let params = new URLSearchParams(path.search);
2982 let indexValues = params.getAll("index");
2983 params.delete("index");
2984 indexValues.filter((v) => v).forEach((v) => params.append("index", v));
2985 let qs = params.toString();
2986 path.search = qs ? `?${qs}` : "";
2987 }
2988 }
2989 if (basename !== "/") {
2990 path.pathname = path.pathname === "/" ? basename : joinPaths([basename, path.pathname]);
2991 }
2992 return createPath(path);
2993}
2994function normalizeNavigateOptions(isFetcher, path, opts) {
2995 if (!opts || !isSubmissionNavigation(opts)) {
2996 return { path };
2997 }
2998 if (opts.formMethod && !isValidMethod(opts.formMethod)) {
2999 return {
3000 path,
3001 error: getInternalRouterError(405, { method: opts.formMethod })
3002 };
3003 }
3004 let getInvalidBodyError = () => ({
3005 path,
3006 error: getInternalRouterError(400, { type: "invalid-body" })
3007 });
3008 let rawFormMethod = opts.formMethod || "get";
3009 let formMethod = rawFormMethod.toUpperCase();
3010 let formAction = stripHashFromPath(path);
3011 if (opts.body !== void 0) {
3012 if (opts.formEncType === "text/plain") {
3013 if (!isMutationMethod(formMethod)) {
3014 return getInvalidBodyError();
3015 }
3016 let text = typeof opts.body === "string" ? opts.body : opts.body instanceof FormData || opts.body instanceof URLSearchParams ? (
3017 // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#plain-text-form-data
3018 Array.from(opts.body.entries()).reduce(
3019 (acc, [name, value]) => `${acc}${name}=${value}
3020`,
3021 ""
3022 )
3023 ) : String(opts.body);
3024 return {
3025 path,
3026 submission: {
3027 formMethod,
3028 formAction,
3029 formEncType: opts.formEncType,
3030 formData: void 0,
3031 json: void 0,
3032 text
3033 }
3034 };
3035 } else if (opts.formEncType === "application/json") {
3036 if (!isMutationMethod(formMethod)) {
3037 return getInvalidBodyError();
3038 }
3039 try {
3040 let json = typeof opts.body === "string" ? JSON.parse(opts.body) : opts.body;
3041 return {
3042 path,
3043 submission: {
3044 formMethod,
3045 formAction,
3046 formEncType: opts.formEncType,
3047 formData: void 0,
3048 json,
3049 text: void 0
3050 }
3051 };
3052 } catch (e) {
3053 return getInvalidBodyError();
3054 }
3055 }
3056 }
3057 invariant(
3058 typeof FormData === "function",
3059 "FormData is not available in this environment"
3060 );
3061 let searchParams;
3062 let formData;
3063 if (opts.formData) {
3064 searchParams = convertFormDataToSearchParams(opts.formData);
3065 formData = opts.formData;
3066 } else if (opts.body instanceof FormData) {
3067 searchParams = convertFormDataToSearchParams(opts.body);
3068 formData = opts.body;
3069 } else if (opts.body instanceof URLSearchParams) {
3070 searchParams = opts.body;
3071 formData = convertSearchParamsToFormData(searchParams);
3072 } else if (opts.body == null) {
3073 searchParams = new URLSearchParams();
3074 formData = new FormData();
3075 } else {
3076 try {
3077 searchParams = new URLSearchParams(opts.body);
3078 formData = convertSearchParamsToFormData(searchParams);
3079 } catch (e) {
3080 return getInvalidBodyError();
3081 }
3082 }
3083 let submission = {
3084 formMethod,
3085 formAction,
3086 formEncType: opts && opts.formEncType || "application/x-www-form-urlencoded",
3087 formData,
3088 json: void 0,
3089 text: void 0
3090 };
3091 if (isMutationMethod(submission.formMethod)) {
3092 return { path, submission };
3093 }
3094 let parsedPath = parsePath(path);
3095 if (isFetcher && parsedPath.search && hasNakedIndexQuery(parsedPath.search)) {
3096 searchParams.append("index", "");
3097 }
3098 parsedPath.search = `?${searchParams}`;
3099 return { path: createPath(parsedPath), submission };
3100}
3101function getLoaderMatchesUntilBoundary(matches, boundaryId, includeBoundary = false) {
3102 let index = matches.findIndex((m) => m.route.id === boundaryId);
3103 if (index >= 0) {
3104 return matches.slice(0, includeBoundary ? index + 1 : index);
3105 }
3106 return matches;
3107}
3108function getMatchesToLoad(history, state, matches, submission, location, initialHydration, isRevalidationRequired, cancelledFetcherLoads, fetchersQueuedForDeletion, fetchLoadMatches, fetchRedirectIds, routesToUse, basename, pendingActionResult) {
3109 let actionResult = pendingActionResult ? isErrorResult(pendingActionResult[1]) ? pendingActionResult[1].error : pendingActionResult[1].data : void 0;
3110 let currentUrl = history.createURL(state.location);
3111 let nextUrl = history.createURL(location);
3112 let boundaryMatches = matches;
3113 if (initialHydration && state.errors) {
3114 boundaryMatches = getLoaderMatchesUntilBoundary(
3115 matches,
3116 Object.keys(state.errors)[0],
3117 true
3118 );
3119 } else if (pendingActionResult && isErrorResult(pendingActionResult[1])) {
3120 boundaryMatches = getLoaderMatchesUntilBoundary(
3121 matches,
3122 pendingActionResult[0]
3123 );
3124 }
3125 let actionStatus = pendingActionResult ? pendingActionResult[1].statusCode : void 0;
3126 let shouldSkipRevalidation = actionStatus && actionStatus >= 400;
3127 let navigationMatches = boundaryMatches.filter((match, index) => {
3128 let { route } = match;
3129 if (route.lazy) {
3130 return true;
3131 }
3132 if (route.loader == null) {
3133 return false;
3134 }
3135 if (initialHydration) {
3136 return shouldLoadRouteOnHydration(route, state.loaderData, state.errors);
3137 }
3138 if (isNewLoader(state.loaderData, state.matches[index], match)) {
3139 return true;
3140 }
3141 let currentRouteMatch = state.matches[index];
3142 let nextRouteMatch = match;
3143 return shouldRevalidateLoader(match, {
3144 currentUrl,
3145 currentParams: currentRouteMatch.params,
3146 nextUrl,
3147 nextParams: nextRouteMatch.params,
3148 ...submission,
3149 actionResult,
3150 actionStatus,
3151 defaultShouldRevalidate: shouldSkipRevalidation ? false : (
3152 // Forced revalidation due to submission, useRevalidator, or X-Remix-Revalidate
3153 isRevalidationRequired || currentUrl.pathname + currentUrl.search === nextUrl.pathname + nextUrl.search || // Search params affect all loaders
3154 currentUrl.search !== nextUrl.search || isNewRouteInstance(currentRouteMatch, nextRouteMatch)
3155 )
3156 });
3157 });
3158 let revalidatingFetchers = [];
3159 fetchLoadMatches.forEach((f, key) => {
3160 if (initialHydration || !matches.some((m) => m.route.id === f.routeId) || fetchersQueuedForDeletion.has(key)) {
3161 return;
3162 }
3163 let fetcherMatches = matchRoutes(routesToUse, f.path, basename);
3164 if (!fetcherMatches) {
3165 revalidatingFetchers.push({
3166 key,
3167 routeId: f.routeId,
3168 path: f.path,
3169 matches: null,
3170 match: null,
3171 controller: null
3172 });
3173 return;
3174 }
3175 let fetcher = state.fetchers.get(key);
3176 let fetcherMatch = getTargetMatch(fetcherMatches, f.path);
3177 let shouldRevalidate = false;
3178 if (fetchRedirectIds.has(key)) {
3179 shouldRevalidate = false;
3180 } else if (cancelledFetcherLoads.has(key)) {
3181 cancelledFetcherLoads.delete(key);
3182 shouldRevalidate = true;
3183 } else if (fetcher && fetcher.state !== "idle" && fetcher.data === void 0) {
3184 shouldRevalidate = isRevalidationRequired;
3185 } else {
3186 shouldRevalidate = shouldRevalidateLoader(fetcherMatch, {
3187 currentUrl,
3188 currentParams: state.matches[state.matches.length - 1].params,
3189 nextUrl,
3190 nextParams: matches[matches.length - 1].params,
3191 ...submission,
3192 actionResult,
3193 actionStatus,
3194 defaultShouldRevalidate: shouldSkipRevalidation ? false : isRevalidationRequired
3195 });
3196 }
3197 if (shouldRevalidate) {
3198 revalidatingFetchers.push({
3199 key,
3200 routeId: f.routeId,
3201 path: f.path,
3202 matches: fetcherMatches,
3203 match: fetcherMatch,
3204 controller: new AbortController()
3205 });
3206 }
3207 });
3208 return [navigationMatches, revalidatingFetchers];
3209}
3210function shouldLoadRouteOnHydration(route, loaderData, errors) {
3211 if (route.lazy) {
3212 return true;
3213 }
3214 if (!route.loader) {
3215 return false;
3216 }
3217 let hasData = loaderData != null && loaderData[route.id] !== void 0;
3218 let hasError = errors != null && errors[route.id] !== void 0;
3219 if (!hasData && hasError) {
3220 return false;
3221 }
3222 if (typeof route.loader === "function" && route.loader.hydrate === true) {
3223 return true;
3224 }
3225 return !hasData && !hasError;
3226}
3227function isNewLoader(currentLoaderData, currentMatch, match) {
3228 let isNew = (
3229 // [a] -> [a, b]
3230 !currentMatch || // [a, b] -> [a, c]
3231 match.route.id !== currentMatch.route.id
3232 );
3233 let isMissingData = !currentLoaderData.hasOwnProperty(match.route.id);
3234 return isNew || isMissingData;
3235}
3236function isNewRouteInstance(currentMatch, match) {
3237 let currentPath = currentMatch.route.path;
3238 return (
3239 // param change for this match, /users/123 -> /users/456
3240 currentMatch.pathname !== match.pathname || // splat param changed, which is not present in match.path
3241 // e.g. /files/images/avatar.jpg -> files/finances.xls
3242 currentPath != null && currentPath.endsWith("*") && currentMatch.params["*"] !== match.params["*"]
3243 );
3244}
3245function shouldRevalidateLoader(loaderMatch, arg) {
3246 if (loaderMatch.route.shouldRevalidate) {
3247 let routeChoice = loaderMatch.route.shouldRevalidate(arg);
3248 if (typeof routeChoice === "boolean") {
3249 return routeChoice;
3250 }
3251 }
3252 return arg.defaultShouldRevalidate;
3253}
3254function patchRoutesImpl(routeId, children, routesToUse, manifest, mapRouteProperties2) {
3255 let childrenToPatch;
3256 if (routeId) {
3257 let route = manifest[routeId];
3258 invariant(
3259 route,
3260 `No route found to patch children into: routeId = ${routeId}`
3261 );
3262 if (!route.children) {
3263 route.children = [];
3264 }
3265 childrenToPatch = route.children;
3266 } else {
3267 childrenToPatch = routesToUse;
3268 }
3269 let uniqueChildren = children.filter(
3270 (newRoute) => !childrenToPatch.some(
3271 (existingRoute) => isSameRoute(newRoute, existingRoute)
3272 )
3273 );
3274 let newRoutes = convertRoutesToDataRoutes(
3275 uniqueChildren,
3276 mapRouteProperties2,
3277 [routeId || "_", "patch", String(childrenToPatch?.length || "0")],
3278 manifest
3279 );
3280 childrenToPatch.push(...newRoutes);
3281}
3282function isSameRoute(newRoute, existingRoute) {
3283 if ("id" in newRoute && "id" in existingRoute && newRoute.id === existingRoute.id) {
3284 return true;
3285 }
3286 if (!(newRoute.index === existingRoute.index && newRoute.path === existingRoute.path && newRoute.caseSensitive === existingRoute.caseSensitive)) {
3287 return false;
3288 }
3289 if ((!newRoute.children || newRoute.children.length === 0) && (!existingRoute.children || existingRoute.children.length === 0)) {
3290 return true;
3291 }
3292 return newRoute.children.every(
3293 (aChild, i) => existingRoute.children?.some((bChild) => isSameRoute(aChild, bChild))
3294 );
3295}
3296async function loadLazyRouteModule(route, mapRouteProperties2, manifest) {
3297 if (!route.lazy) {
3298 return;
3299 }
3300 let lazyRoute = await route.lazy();
3301 if (!route.lazy) {
3302 return;
3303 }
3304 let routeToUpdate = manifest[route.id];
3305 invariant(routeToUpdate, "No route found in manifest");
3306 let routeUpdates = {};
3307 for (let lazyRouteProperty in lazyRoute) {
3308 let staticRouteValue = routeToUpdate[lazyRouteProperty];
3309 let isPropertyStaticallyDefined = staticRouteValue !== void 0 && // This property isn't static since it should always be updated based
3310 // on the route updates
3311 lazyRouteProperty !== "hasErrorBoundary";
3312 warning(
3313 !isPropertyStaticallyDefined,
3314 `Route "${routeToUpdate.id}" has a static property "${lazyRouteProperty}" defined but its lazy function is also returning a value for this property. The lazy route property "${lazyRouteProperty}" will be ignored.`
3315 );
3316 if (!isPropertyStaticallyDefined && !immutableRouteKeys.has(lazyRouteProperty)) {
3317 routeUpdates[lazyRouteProperty] = lazyRoute[lazyRouteProperty];
3318 }
3319 }
3320 Object.assign(routeToUpdate, routeUpdates);
3321 Object.assign(routeToUpdate, {
3322 // To keep things framework agnostic, we use the provided `mapRouteProperties`
3323 // function to set the framework-aware properties (`element`/`hasErrorBoundary`)
3324 // since the logic will differ between frameworks.
3325 ...mapRouteProperties2(routeToUpdate),
3326 lazy: void 0
3327 });
3328}
3329async function defaultDataStrategy({
3330 matches
3331}) {
3332 let matchesToLoad = matches.filter((m) => m.shouldLoad);
3333 let results = await Promise.all(matchesToLoad.map((m) => m.resolve()));
3334 return results.reduce(
3335 (acc, result, i) => Object.assign(acc, { [matchesToLoad[i].route.id]: result }),
3336 {}
3337 );
3338}
3339async function callDataStrategyImpl(dataStrategyImpl, type, state, request, matchesToLoad, matches, fetcherKey, manifest, mapRouteProperties2, requestContext) {
3340 let loadRouteDefinitionsPromises = matches.map(
3341 (m) => m.route.lazy ? loadLazyRouteModule(m.route, mapRouteProperties2, manifest) : void 0
3342 );
3343 let dsMatches = matches.map((match, i) => {
3344 let loadRoutePromise = loadRouteDefinitionsPromises[i];
3345 let shouldLoad = matchesToLoad.some((m) => m.route.id === match.route.id);
3346 let resolve = async (handlerOverride) => {
3347 if (handlerOverride && request.method === "GET" && (match.route.lazy || match.route.loader)) {
3348 shouldLoad = true;
3349 }
3350 return shouldLoad ? callLoaderOrAction(
3351 type,
3352 request,
3353 match,
3354 loadRoutePromise,
3355 handlerOverride,
3356 requestContext
3357 ) : Promise.resolve({ type: "data" /* data */, result: void 0 });
3358 };
3359 return {
3360 ...match,
3361 shouldLoad,
3362 resolve
3363 };
3364 });
3365 let results = await dataStrategyImpl({
3366 matches: dsMatches,
3367 request,
3368 params: matches[0].params,
3369 fetcherKey,
3370 context: requestContext
3371 });
3372 try {
3373 await Promise.all(loadRouteDefinitionsPromises);
3374 } catch (e) {
3375 }
3376 return results;
3377}
3378async function callLoaderOrAction(type, request, match, loadRoutePromise, handlerOverride, staticContext) {
3379 let result;
3380 let onReject;
3381 let runHandler = (handler) => {
3382 let reject;
3383 let abortPromise = new Promise((_, r) => reject = r);
3384 onReject = () => reject();
3385 request.signal.addEventListener("abort", onReject);
3386 let actualHandler = (ctx) => {
3387 if (typeof handler !== "function") {
3388 return Promise.reject(
3389 new Error(
3390 `You cannot call the handler for a route which defines a boolean "${type}" [routeId: ${match.route.id}]`
3391 )
3392 );
3393 }
3394 return handler(
3395 {
3396 request,
3397 params: match.params,
3398 context: staticContext
3399 },
3400 ...ctx !== void 0 ? [ctx] : []
3401 );
3402 };
3403 let handlerPromise = (async () => {
3404 try {
3405 let val = await (handlerOverride ? handlerOverride((ctx) => actualHandler(ctx)) : actualHandler());
3406 return { type: "data", result: val };
3407 } catch (e) {
3408 return { type: "error", result: e };
3409 }
3410 })();
3411 return Promise.race([handlerPromise, abortPromise]);
3412 };
3413 try {
3414 let handler = match.route[type];
3415 if (loadRoutePromise) {
3416 if (handler) {
3417 let handlerError;
3418 let [value] = await Promise.all([
3419 // If the handler throws, don't let it immediately bubble out,
3420 // since we need to let the lazy() execution finish so we know if this
3421 // route has a boundary that can handle the error
3422 runHandler(handler).catch((e) => {
3423 handlerError = e;
3424 }),
3425 loadRoutePromise
3426 ]);
3427 if (handlerError !== void 0) {
3428 throw handlerError;
3429 }
3430 result = value;
3431 } else {
3432 await loadRoutePromise;
3433 handler = match.route[type];
3434 if (handler) {
3435 result = await runHandler(handler);
3436 } else if (type === "action") {
3437 let url = new URL(request.url);
3438 let pathname = url.pathname + url.search;
3439 throw getInternalRouterError(405, {
3440 method: request.method,
3441 pathname,
3442 routeId: match.route.id
3443 });
3444 } else {
3445 return { type: "data" /* data */, result: void 0 };
3446 }
3447 }
3448 } else if (!handler) {
3449 let url = new URL(request.url);
3450 let pathname = url.pathname + url.search;
3451 throw getInternalRouterError(404, {
3452 pathname
3453 });
3454 } else {
3455 result = await runHandler(handler);
3456 }
3457 } catch (e) {
3458 return { type: "error" /* error */, result: e };
3459 } finally {
3460 if (onReject) {
3461 request.signal.removeEventListener("abort", onReject);
3462 }
3463 }
3464 return result;
3465}
3466async function convertDataStrategyResultToDataResult(dataStrategyResult) {
3467 let { result, type } = dataStrategyResult;
3468 if (isResponse(result)) {
3469 let data2;
3470 try {
3471 let contentType = result.headers.get("Content-Type");
3472 if (contentType && /\bapplication\/json\b/.test(contentType)) {
3473 if (result.body == null) {
3474 data2 = null;
3475 } else {
3476 data2 = await result.json();
3477 }
3478 } else {
3479 data2 = await result.text();
3480 }
3481 } catch (e) {
3482 return { type: "error" /* error */, error: e };
3483 }
3484 if (type === "error" /* error */) {
3485 return {
3486 type: "error" /* error */,
3487 error: new ErrorResponseImpl(result.status, result.statusText, data2),
3488 statusCode: result.status,
3489 headers: result.headers
3490 };
3491 }
3492 return {
3493 type: "data" /* data */,
3494 data: data2,
3495 statusCode: result.status,
3496 headers: result.headers
3497 };
3498 }
3499 if (type === "error" /* error */) {
3500 if (isDataWithResponseInit(result)) {
3501 if (result.data instanceof Error) {
3502 return {
3503 type: "error" /* error */,
3504 error: result.data,
3505 statusCode: result.init?.status,
3506 headers: result.init?.headers ? new Headers(result.init.headers) : void 0
3507 };
3508 }
3509 return {
3510 type: "error" /* error */,
3511 error: new ErrorResponseImpl(
3512 result.init?.status || 500,
3513 void 0,
3514 result.data
3515 ),
3516 statusCode: isRouteErrorResponse(result) ? result.status : void 0,
3517 headers: result.init?.headers ? new Headers(result.init.headers) : void 0
3518 };
3519 }
3520 return {
3521 type: "error" /* error */,
3522 error: result,
3523 statusCode: isRouteErrorResponse(result) ? result.status : void 0
3524 };
3525 }
3526 if (isDataWithResponseInit(result)) {
3527 return {
3528 type: "data" /* data */,
3529 data: result.data,
3530 statusCode: result.init?.status,
3531 headers: result.init?.headers ? new Headers(result.init.headers) : void 0
3532 };
3533 }
3534 return { type: "data" /* data */, data: result };
3535}
3536function normalizeRelativeRoutingRedirectResponse(response, request, routeId, matches, basename) {
3537 let location = response.headers.get("Location");
3538 invariant(
3539 location,
3540 "Redirects returned/thrown from loaders/actions must have a Location header"
3541 );
3542 if (!ABSOLUTE_URL_REGEX.test(location)) {
3543 let trimmedMatches = matches.slice(
3544 0,
3545 matches.findIndex((m) => m.route.id === routeId) + 1
3546 );
3547 location = normalizeTo(
3548 new URL(request.url),
3549 trimmedMatches,
3550 basename,
3551 location
3552 );
3553 response.headers.set("Location", location);
3554 }
3555 return response;
3556}
3557function normalizeRedirectLocation(location, currentUrl, basename) {
3558 if (ABSOLUTE_URL_REGEX.test(location)) {
3559 let normalizedLocation = location;
3560 let url = normalizedLocation.startsWith("//") ? new URL(currentUrl.protocol + normalizedLocation) : new URL(normalizedLocation);
3561 let isSameBasename = stripBasename(url.pathname, basename) != null;
3562 if (url.origin === currentUrl.origin && isSameBasename) {
3563 return url.pathname + url.search + url.hash;
3564 }
3565 }
3566 return location;
3567}
3568function createClientSideRequest(history, location, signal, submission) {
3569 let url = history.createURL(stripHashFromPath(location)).toString();
3570 let init = { signal };
3571 if (submission && isMutationMethod(submission.formMethod)) {
3572 let { formMethod, formEncType } = submission;
3573 init.method = formMethod.toUpperCase();
3574 if (formEncType === "application/json") {
3575 init.headers = new Headers({ "Content-Type": formEncType });
3576 init.body = JSON.stringify(submission.json);
3577 } else if (formEncType === "text/plain") {
3578 init.body = submission.text;
3579 } else if (formEncType === "application/x-www-form-urlencoded" && submission.formData) {
3580 init.body = convertFormDataToSearchParams(submission.formData);
3581 } else {
3582 init.body = submission.formData;
3583 }
3584 }
3585 return new Request(url, init);
3586}
3587function convertFormDataToSearchParams(formData) {
3588 let searchParams = new URLSearchParams();
3589 for (let [key, value] of formData.entries()) {
3590 searchParams.append(key, typeof value === "string" ? value : value.name);
3591 }
3592 return searchParams;
3593}
3594function convertSearchParamsToFormData(searchParams) {
3595 let formData = new FormData();
3596 for (let [key, value] of searchParams.entries()) {
3597 formData.append(key, value);
3598 }
3599 return formData;
3600}
3601function processRouteLoaderData(matches, results, pendingActionResult, isStaticHandler = false, skipLoaderErrorBubbling = false) {
3602 let loaderData = {};
3603 let errors = null;
3604 let statusCode;
3605 let foundError = false;
3606 let loaderHeaders = {};
3607 let pendingError = pendingActionResult && isErrorResult(pendingActionResult[1]) ? pendingActionResult[1].error : void 0;
3608 matches.forEach((match) => {
3609 if (!(match.route.id in results)) {
3610 return;
3611 }
3612 let id = match.route.id;
3613 let result = results[id];
3614 invariant(
3615 !isRedirectResult(result),
3616 "Cannot handle redirect results in processLoaderData"
3617 );
3618 if (isErrorResult(result)) {
3619 let error = result.error;
3620 if (pendingError !== void 0) {
3621 error = pendingError;
3622 pendingError = void 0;
3623 }
3624 errors = errors || {};
3625 if (skipLoaderErrorBubbling) {
3626 errors[id] = error;
3627 } else {
3628 let boundaryMatch = findNearestBoundary(matches, id);
3629 if (errors[boundaryMatch.route.id] == null) {
3630 errors[boundaryMatch.route.id] = error;
3631 }
3632 }
3633 if (!isStaticHandler) {
3634 loaderData[id] = ResetLoaderDataSymbol;
3635 }
3636 if (!foundError) {
3637 foundError = true;
3638 statusCode = isRouteErrorResponse(result.error) ? result.error.status : 500;
3639 }
3640 if (result.headers) {
3641 loaderHeaders[id] = result.headers;
3642 }
3643 } else {
3644 loaderData[id] = result.data;
3645 if (result.statusCode && result.statusCode !== 200 && !foundError) {
3646 statusCode = result.statusCode;
3647 }
3648 if (result.headers) {
3649 loaderHeaders[id] = result.headers;
3650 }
3651 }
3652 });
3653 if (pendingError !== void 0 && pendingActionResult) {
3654 errors = { [pendingActionResult[0]]: pendingError };
3655 loaderData[pendingActionResult[0]] = void 0;
3656 }
3657 return {
3658 loaderData,
3659 errors,
3660 statusCode: statusCode || 200,
3661 loaderHeaders
3662 };
3663}
3664function processLoaderData(state, matches, results, pendingActionResult, revalidatingFetchers, fetcherResults) {
3665 let { loaderData, errors } = processRouteLoaderData(
3666 matches,
3667 results,
3668 pendingActionResult
3669 );
3670 revalidatingFetchers.forEach((rf) => {
3671 let { key, match, controller } = rf;
3672 let result = fetcherResults[key];
3673 invariant(result, "Did not find corresponding fetcher result");
3674 if (controller && controller.signal.aborted) {
3675 return;
3676 } else if (isErrorResult(result)) {
3677 let boundaryMatch = findNearestBoundary(state.matches, match?.route.id);
3678 if (!(errors && errors[boundaryMatch.route.id])) {
3679 errors = {
3680 ...errors,
3681 [boundaryMatch.route.id]: result.error
3682 };
3683 }
3684 state.fetchers.delete(key);
3685 } else if (isRedirectResult(result)) {
3686 invariant(false, "Unhandled fetcher revalidation redirect");
3687 } else {
3688 let doneFetcher = getDoneFetcher(result.data);
3689 state.fetchers.set(key, doneFetcher);
3690 }
3691 });
3692 return { loaderData, errors };
3693}
3694function mergeLoaderData(loaderData, newLoaderData, matches, errors) {
3695 let mergedLoaderData = Object.entries(newLoaderData).filter(([, v]) => v !== ResetLoaderDataSymbol).reduce((merged, [k, v]) => {
3696 merged[k] = v;
3697 return merged;
3698 }, {});
3699 for (let match of matches) {
3700 let id = match.route.id;
3701 if (!newLoaderData.hasOwnProperty(id) && loaderData.hasOwnProperty(id) && match.route.loader) {
3702 mergedLoaderData[id] = loaderData[id];
3703 }
3704 if (errors && errors.hasOwnProperty(id)) {
3705 break;
3706 }
3707 }
3708 return mergedLoaderData;
3709}
3710function getActionDataForCommit(pendingActionResult) {
3711 if (!pendingActionResult) {
3712 return {};
3713 }
3714 return isErrorResult(pendingActionResult[1]) ? {
3715 // Clear out prior actionData on errors
3716 actionData: {}
3717 } : {
3718 actionData: {
3719 [pendingActionResult[0]]: pendingActionResult[1].data
3720 }
3721 };
3722}
3723function findNearestBoundary(matches, routeId) {
3724 let eligibleMatches = routeId ? matches.slice(0, matches.findIndex((m) => m.route.id === routeId) + 1) : [...matches];
3725 return eligibleMatches.reverse().find((m) => m.route.hasErrorBoundary === true) || matches[0];
3726}
3727function getShortCircuitMatches(routes) {
3728 let route = routes.length === 1 ? routes[0] : routes.find((r) => r.index || !r.path || r.path === "/") || {
3729 id: `__shim-error-route__`
3730 };
3731 return {
3732 matches: [
3733 {
3734 params: {},
3735 pathname: "",
3736 pathnameBase: "",
3737 route
3738 }
3739 ],
3740 route
3741 };
3742}
3743function getInternalRouterError(status, {
3744 pathname,
3745 routeId,
3746 method,
3747 type,
3748 message
3749} = {}) {
3750 let statusText = "Unknown Server Error";
3751 let errorMessage = "Unknown @remix-run/router error";
3752 if (status === 400) {
3753 statusText = "Bad Request";
3754 if (method && pathname && routeId) {
3755 errorMessage = `You made a ${method} request to "${pathname}" but did not provide a \`loader\` for route "${routeId}", so there is no way to handle the request.`;
3756 } else if (type === "invalid-body") {
3757 errorMessage = "Unable to encode submission body";
3758 }
3759 } else if (status === 403) {
3760 statusText = "Forbidden";
3761 errorMessage = `Route "${routeId}" does not match URL "${pathname}"`;
3762 } else if (status === 404) {
3763 statusText = "Not Found";
3764 errorMessage = `No route matches URL "${pathname}"`;
3765 } else if (status === 405) {
3766 statusText = "Method Not Allowed";
3767 if (method && pathname && routeId) {
3768 errorMessage = `You made a ${method.toUpperCase()} request to "${pathname}" but did not provide an \`action\` for route "${routeId}", so there is no way to handle the request.`;
3769 } else if (method) {
3770 errorMessage = `Invalid request method "${method.toUpperCase()}"`;
3771 }
3772 }
3773 return new ErrorResponseImpl(
3774 status || 500,
3775 statusText,
3776 new Error(errorMessage),
3777 true
3778 );
3779}
3780function findRedirect(results) {
3781 let entries = Object.entries(results);
3782 for (let i = entries.length - 1; i >= 0; i--) {
3783 let [key, result] = entries[i];
3784 if (isRedirectResult(result)) {
3785 return { key, result };
3786 }
3787 }
3788}
3789function stripHashFromPath(path) {
3790 let parsedPath = typeof path === "string" ? parsePath(path) : path;
3791 return createPath({ ...parsedPath, hash: "" });
3792}
3793function isHashChangeOnly(a, b) {
3794 if (a.pathname !== b.pathname || a.search !== b.search) {
3795 return false;
3796 }
3797 if (a.hash === "") {
3798 return b.hash !== "";
3799 } else if (a.hash === b.hash) {
3800 return true;
3801 } else if (b.hash !== "") {
3802 return true;
3803 }
3804 return false;
3805}
3806function isDataStrategyResult(result) {
3807 return result != null && typeof result === "object" && "type" in result && "result" in result && (result.type === "data" /* data */ || result.type === "error" /* error */);
3808}
3809function isRedirectDataStrategyResult(result) {
3810 return isResponse(result.result) && redirectStatusCodes.has(result.result.status);
3811}
3812function isErrorResult(result) {
3813 return result.type === "error" /* error */;
3814}
3815function isRedirectResult(result) {
3816 return (result && result.type) === "redirect" /* redirect */;
3817}
3818function isDataWithResponseInit(value) {
3819 return typeof value === "object" && value != null && "type" in value && "data" in value && "init" in value && value.type === "DataWithResponseInit";
3820}
3821function isResponse(value) {
3822 return value != null && typeof value.status === "number" && typeof value.statusText === "string" && typeof value.headers === "object" && typeof value.body !== "undefined";
3823}
3824function isRedirectStatusCode(statusCode) {
3825 return redirectStatusCodes.has(statusCode);
3826}
3827function isRedirectResponse(result) {
3828 return isResponse(result) && isRedirectStatusCode(result.status) && result.headers.has("Location");
3829}
3830function isValidMethod(method) {
3831 return validRequestMethods.has(method.toUpperCase());
3832}
3833function isMutationMethod(method) {
3834 return validMutationMethods.has(method.toUpperCase());
3835}
3836function hasNakedIndexQuery(search) {
3837 return new URLSearchParams(search).getAll("index").some((v) => v === "");
3838}
3839function getTargetMatch(matches, location) {
3840 let search = typeof location === "string" ? parsePath(location).search : location.search;
3841 if (matches[matches.length - 1].route.index && hasNakedIndexQuery(search || "")) {
3842 return matches[matches.length - 1];
3843 }
3844 let pathMatches = getPathContributingMatches(matches);
3845 return pathMatches[pathMatches.length - 1];
3846}
3847function getSubmissionFromNavigation(navigation) {
3848 let { formMethod, formAction, formEncType, text, formData, json } = navigation;
3849 if (!formMethod || !formAction || !formEncType) {
3850 return;
3851 }
3852 if (text != null) {
3853 return {
3854 formMethod,
3855 formAction,
3856 formEncType,
3857 formData: void 0,
3858 json: void 0,
3859 text
3860 };
3861 } else if (formData != null) {
3862 return {
3863 formMethod,
3864 formAction,
3865 formEncType,
3866 formData,
3867 json: void 0,
3868 text: void 0
3869 };
3870 } else if (json !== void 0) {
3871 return {
3872 formMethod,
3873 formAction,
3874 formEncType,
3875 formData: void 0,
3876 json,
3877 text: void 0
3878 };
3879 }
3880}
3881function getLoadingNavigation(location, submission) {
3882 if (submission) {
3883 let navigation = {
3884 state: "loading",
3885 location,
3886 formMethod: submission.formMethod,
3887 formAction: submission.formAction,
3888 formEncType: submission.formEncType,
3889 formData: submission.formData,
3890 json: submission.json,
3891 text: submission.text
3892 };
3893 return navigation;
3894 } else {
3895 let navigation = {
3896 state: "loading",
3897 location,
3898 formMethod: void 0,
3899 formAction: void 0,
3900 formEncType: void 0,
3901 formData: void 0,
3902 json: void 0,
3903 text: void 0
3904 };
3905 return navigation;
3906 }
3907}
3908function getSubmittingNavigation(location, submission) {
3909 let navigation = {
3910 state: "submitting",
3911 location,
3912 formMethod: submission.formMethod,
3913 formAction: submission.formAction,
3914 formEncType: submission.formEncType,
3915 formData: submission.formData,
3916 json: submission.json,
3917 text: submission.text
3918 };
3919 return navigation;
3920}
3921function getLoadingFetcher(submission, data2) {
3922 if (submission) {
3923 let fetcher = {
3924 state: "loading",
3925 formMethod: submission.formMethod,
3926 formAction: submission.formAction,
3927 formEncType: submission.formEncType,
3928 formData: submission.formData,
3929 json: submission.json,
3930 text: submission.text,
3931 data: data2
3932 };
3933 return fetcher;
3934 } else {
3935 let fetcher = {
3936 state: "loading",
3937 formMethod: void 0,
3938 formAction: void 0,
3939 formEncType: void 0,
3940 formData: void 0,
3941 json: void 0,
3942 text: void 0,
3943 data: data2
3944 };
3945 return fetcher;
3946 }
3947}
3948function getSubmittingFetcher(submission, existingFetcher) {
3949 let fetcher = {
3950 state: "submitting",
3951 formMethod: submission.formMethod,
3952 formAction: submission.formAction,
3953 formEncType: submission.formEncType,
3954 formData: submission.formData,
3955 json: submission.json,
3956 text: submission.text,
3957 data: existingFetcher ? existingFetcher.data : void 0
3958 };
3959 return fetcher;
3960}
3961function getDoneFetcher(data2) {
3962 let fetcher = {
3963 state: "idle",
3964 formMethod: void 0,
3965 formAction: void 0,
3966 formEncType: void 0,
3967 formData: void 0,
3968 json: void 0,
3969 text: void 0,
3970 data: data2
3971 };
3972 return fetcher;
3973}
3974function restoreAppliedTransitions(_window, transitions) {
3975 try {
3976 let sessionPositions = _window.sessionStorage.getItem(
3977 TRANSITIONS_STORAGE_KEY
3978 );
3979 if (sessionPositions) {
3980 let json = JSON.parse(sessionPositions);
3981 for (let [k, v] of Object.entries(json || {})) {
3982 if (v && Array.isArray(v)) {
3983 transitions.set(k, new Set(v || []));
3984 }
3985 }
3986 }
3987 } catch (e) {
3988 }
3989}
3990function persistAppliedTransitions(_window, transitions) {
3991 if (transitions.size > 0) {
3992 let json = {};
3993 for (let [k, v] of transitions) {
3994 json[k] = [...v];
3995 }
3996 try {
3997 _window.sessionStorage.setItem(
3998 TRANSITIONS_STORAGE_KEY,
3999 JSON.stringify(json)
4000 );
4001 } catch (error) {
4002 warning(
4003 false,
4004 `Failed to save applied view transitions in sessionStorage (${error}).`
4005 );
4006 }
4007 }
4008}
4009function createDeferred() {
4010 let resolve;
4011 let reject;
4012 let promise = new Promise((res, rej) => {
4013 resolve = async (val) => {
4014 res(val);
4015 try {
4016 await promise;
4017 } catch (e) {
4018 }
4019 };
4020 reject = async (error) => {
4021 rej(error);
4022 try {
4023 await promise;
4024 } catch (e) {
4025 }
4026 };
4027 });
4028 return {
4029 promise,
4030 //@ts-ignore
4031 resolve,
4032 //@ts-ignore
4033 reject
4034 };
4035}
4036
4037// lib/components.tsx
4038import * as React3 from "react";
4039
4040// lib/context.ts
4041import * as React from "react";
4042var DataRouterContext = React.createContext(null);
4043DataRouterContext.displayName = "DataRouter";
4044var DataRouterStateContext = React.createContext(null);
4045DataRouterStateContext.displayName = "DataRouterState";
4046var ViewTransitionContext = React.createContext({
4047 isTransitioning: false
4048});
4049ViewTransitionContext.displayName = "ViewTransition";
4050var FetchersContext = React.createContext(
4051 /* @__PURE__ */ new Map()
4052);
4053FetchersContext.displayName = "Fetchers";
4054var AwaitContext = React.createContext(null);
4055AwaitContext.displayName = "Await";
4056var NavigationContext = React.createContext(
4057 null
4058);
4059NavigationContext.displayName = "Navigation";
4060var LocationContext = React.createContext(
4061 null
4062);
4063LocationContext.displayName = "Location";
4064var RouteContext = React.createContext({
4065 outlet: null,
4066 matches: [],
4067 isDataRoute: false
4068});
4069RouteContext.displayName = "Route";
4070var RouteErrorContext = React.createContext(null);
4071RouteErrorContext.displayName = "RouteError";
4072
4073// lib/hooks.tsx
4074import * as React2 from "react";
4075var ENABLE_DEV_WARNINGS = false;
4076function useHref(to, { relative } = {}) {
4077 invariant(
4078 useInRouterContext(),
4079 // TODO: This error is probably because they somehow have 2 versions of the
4080 // router loaded. We can help them understand how to avoid that.
4081 `useHref() may be used only in the context of a <Router> component.`
4082 );
4083 let { basename, navigator: navigator2 } = React2.useContext(NavigationContext);
4084 let { hash, pathname, search } = useResolvedPath(to, { relative });
4085 let joinedPathname = pathname;
4086 if (basename !== "/") {
4087 joinedPathname = pathname === "/" ? basename : joinPaths([basename, pathname]);
4088 }
4089 return navigator2.createHref({ pathname: joinedPathname, search, hash });
4090}
4091function useInRouterContext() {
4092 return React2.useContext(LocationContext) != null;
4093}
4094function useLocation() {
4095 invariant(
4096 useInRouterContext(),
4097 // TODO: This error is probably because they somehow have 2 versions of the
4098 // router loaded. We can help them understand how to avoid that.
4099 `useLocation() may be used only in the context of a <Router> component.`
4100 );
4101 return React2.useContext(LocationContext).location;
4102}
4103function useNavigationType() {
4104 return React2.useContext(LocationContext).navigationType;
4105}
4106function useMatch(pattern) {
4107 invariant(
4108 useInRouterContext(),
4109 // TODO: This error is probably because they somehow have 2 versions of the
4110 // router loaded. We can help them understand how to avoid that.
4111 `useMatch() may be used only in the context of a <Router> component.`
4112 );
4113 let { pathname } = useLocation();
4114 return React2.useMemo(
4115 () => matchPath(pattern, decodePath(pathname)),
4116 [pathname, pattern]
4117 );
4118}
4119var navigateEffectWarning = `You should call navigate() in a React.useEffect(), not when your component is first rendered.`;
4120function useIsomorphicLayoutEffect(cb) {
4121 let isStatic = React2.useContext(NavigationContext).static;
4122 if (!isStatic) {
4123 React2.useLayoutEffect(cb);
4124 }
4125}
4126function useNavigate() {
4127 let { isDataRoute } = React2.useContext(RouteContext);
4128 return isDataRoute ? useNavigateStable() : useNavigateUnstable();
4129}
4130function useNavigateUnstable() {
4131 invariant(
4132 useInRouterContext(),
4133 // TODO: This error is probably because they somehow have 2 versions of the
4134 // router loaded. We can help them understand how to avoid that.
4135 `useNavigate() may be used only in the context of a <Router> component.`
4136 );
4137 let dataRouterContext = React2.useContext(DataRouterContext);
4138 let { basename, navigator: navigator2 } = React2.useContext(NavigationContext);
4139 let { matches } = React2.useContext(RouteContext);
4140 let { pathname: locationPathname } = useLocation();
4141 let routePathnamesJson = JSON.stringify(getResolveToMatches(matches));
4142 let activeRef = React2.useRef(false);
4143 useIsomorphicLayoutEffect(() => {
4144 activeRef.current = true;
4145 });
4146 let navigate = React2.useCallback(
4147 (to, options = {}) => {
4148 warning(activeRef.current, navigateEffectWarning);
4149 if (!activeRef.current) return;
4150 if (typeof to === "number") {
4151 navigator2.go(to);
4152 return;
4153 }
4154 let path = resolveTo(
4155 to,
4156 JSON.parse(routePathnamesJson),
4157 locationPathname,
4158 options.relative === "path"
4159 );
4160 if (dataRouterContext == null && basename !== "/") {
4161 path.pathname = path.pathname === "/" ? basename : joinPaths([basename, path.pathname]);
4162 }
4163 (!!options.replace ? navigator2.replace : navigator2.push)(
4164 path,
4165 options.state,
4166 options
4167 );
4168 },
4169 [
4170 basename,
4171 navigator2,
4172 routePathnamesJson,
4173 locationPathname,
4174 dataRouterContext
4175 ]
4176 );
4177 return navigate;
4178}
4179var OutletContext = React2.createContext(null);
4180function useOutletContext() {
4181 return React2.useContext(OutletContext);
4182}
4183function useOutlet(context) {
4184 let outlet = React2.useContext(RouteContext).outlet;
4185 if (outlet) {
4186 return /* @__PURE__ */ React2.createElement(OutletContext.Provider, { value: context }, outlet);
4187 }
4188 return outlet;
4189}
4190function useParams() {
4191 let { matches } = React2.useContext(RouteContext);
4192 let routeMatch = matches[matches.length - 1];
4193 return routeMatch ? routeMatch.params : {};
4194}
4195function useResolvedPath(to, { relative } = {}) {
4196 let { matches } = React2.useContext(RouteContext);
4197 let { pathname: locationPathname } = useLocation();
4198 let routePathnamesJson = JSON.stringify(getResolveToMatches(matches));
4199 return React2.useMemo(
4200 () => resolveTo(
4201 to,
4202 JSON.parse(routePathnamesJson),
4203 locationPathname,
4204 relative === "path"
4205 ),
4206 [to, routePathnamesJson, locationPathname, relative]
4207 );
4208}
4209function useRoutes(routes, locationArg) {
4210 return useRoutesImpl(routes, locationArg);
4211}
4212function useRoutesImpl(routes, locationArg, dataRouterState, future) {
4213 invariant(
4214 useInRouterContext(),
4215 // TODO: This error is probably because they somehow have 2 versions of the
4216 // router loaded. We can help them understand how to avoid that.
4217 `useRoutes() may be used only in the context of a <Router> component.`
4218 );
4219 let { navigator: navigator2, static: isStatic } = React2.useContext(NavigationContext);
4220 let { matches: parentMatches } = React2.useContext(RouteContext);
4221 let routeMatch = parentMatches[parentMatches.length - 1];
4222 let parentParams = routeMatch ? routeMatch.params : {};
4223 let parentPathname = routeMatch ? routeMatch.pathname : "/";
4224 let parentPathnameBase = routeMatch ? routeMatch.pathnameBase : "/";
4225 let parentRoute = routeMatch && routeMatch.route;
4226 if (ENABLE_DEV_WARNINGS) {
4227 let parentPath = parentRoute && parentRoute.path || "";
4228 warningOnce(
4229 parentPathname,
4230 !parentRoute || parentPath.endsWith("*") || parentPath.endsWith("*?"),
4231 `You rendered descendant <Routes> (or called \`useRoutes()\`) at "${parentPathname}" (under <Route path="${parentPath}">) but the parent route path has no trailing "*". This means if you navigate deeper, the parent won't match anymore and therefore the child routes will never render.
4232
4233Please change the parent <Route path="${parentPath}"> to <Route path="${parentPath === "/" ? "*" : `${parentPath}/*`}">.`
4234 );
4235 }
4236 let locationFromContext = useLocation();
4237 let location;
4238 if (locationArg) {
4239 let parsedLocationArg = typeof locationArg === "string" ? parsePath(locationArg) : locationArg;
4240 invariant(
4241 parentPathnameBase === "/" || parsedLocationArg.pathname?.startsWith(parentPathnameBase),
4242 `When overriding the location using \`<Routes location>\` or \`useRoutes(routes, location)\`, the location pathname must begin with the portion of the URL pathname that was matched by all parent routes. The current pathname base is "${parentPathnameBase}" but pathname "${parsedLocationArg.pathname}" was given in the \`location\` prop.`
4243 );
4244 location = parsedLocationArg;
4245 } else {
4246 location = locationFromContext;
4247 }
4248 let pathname = location.pathname || "/";
4249 let remainingPathname = pathname;
4250 if (parentPathnameBase !== "/") {
4251 let parentSegments = parentPathnameBase.replace(/^\//, "").split("/");
4252 let segments = pathname.replace(/^\//, "").split("/");
4253 remainingPathname = "/" + segments.slice(parentSegments.length).join("/");
4254 }
4255 let matches = !isStatic && dataRouterState && dataRouterState.matches && dataRouterState.matches.length > 0 ? dataRouterState.matches : matchRoutes(routes, { pathname: remainingPathname });
4256 if (ENABLE_DEV_WARNINGS) {
4257 warning(
4258 parentRoute || matches != null,
4259 `No routes matched location "${location.pathname}${location.search}${location.hash}" `
4260 );
4261 warning(
4262 matches == null || matches[matches.length - 1].route.element !== void 0 || matches[matches.length - 1].route.Component !== void 0 || matches[matches.length - 1].route.lazy !== void 0,
4263 `Matched leaf route at location "${location.pathname}${location.search}${location.hash}" does not have an element or Component. This means it will render an <Outlet /> with a null value by default resulting in an "empty" page.`
4264 );
4265 }
4266 let renderedMatches = _renderMatches(
4267 matches && matches.map(
4268 (match) => Object.assign({}, match, {
4269 params: Object.assign({}, parentParams, match.params),
4270 pathname: joinPaths([
4271 parentPathnameBase,
4272 // Re-encode pathnames that were decoded inside matchRoutes
4273 navigator2.encodeLocation ? navigator2.encodeLocation(match.pathname).pathname : match.pathname
4274 ]),
4275 pathnameBase: match.pathnameBase === "/" ? parentPathnameBase : joinPaths([
4276 parentPathnameBase,
4277 // Re-encode pathnames that were decoded inside matchRoutes
4278 navigator2.encodeLocation ? navigator2.encodeLocation(match.pathnameBase).pathname : match.pathnameBase
4279 ])
4280 })
4281 ),
4282 parentMatches,
4283 dataRouterState,
4284 future
4285 );
4286 if (locationArg && renderedMatches) {
4287 return /* @__PURE__ */ React2.createElement(
4288 LocationContext.Provider,
4289 {
4290 value: {
4291 location: {
4292 pathname: "/",
4293 search: "",
4294 hash: "",
4295 state: null,
4296 key: "default",
4297 ...location
4298 },
4299 navigationType: "POP" /* Pop */
4300 }
4301 },
4302 renderedMatches
4303 );
4304 }
4305 return renderedMatches;
4306}
4307function DefaultErrorComponent() {
4308 let error = useRouteError();
4309 let message = isRouteErrorResponse(error) ? `${error.status} ${error.statusText}` : error instanceof Error ? error.message : JSON.stringify(error);
4310 let stack = error instanceof Error ? error.stack : null;
4311 let lightgrey = "rgba(200,200,200, 0.5)";
4312 let preStyles = { padding: "0.5rem", backgroundColor: lightgrey };
4313 let codeStyles = { padding: "2px 4px", backgroundColor: lightgrey };
4314 let devInfo = null;
4315 if (ENABLE_DEV_WARNINGS) {
4316 console.error(
4317 "Error handled by React Router default ErrorBoundary:",
4318 error
4319 );
4320 devInfo = /* @__PURE__ */ React2.createElement(React2.Fragment, null, /* @__PURE__ */ React2.createElement("p", null, "\u{1F4BF} Hey developer \u{1F44B}"), /* @__PURE__ */ React2.createElement("p", null, "You can provide a way better UX than this when your app throws errors by providing your own ", /* @__PURE__ */ React2.createElement("code", { style: codeStyles }, "ErrorBoundary"), " or", " ", /* @__PURE__ */ React2.createElement("code", { style: codeStyles }, "errorElement"), " prop on your route."));
4321 }
4322 return /* @__PURE__ */ React2.createElement(React2.Fragment, null, /* @__PURE__ */ React2.createElement("h2", null, "Unexpected Application Error!"), /* @__PURE__ */ React2.createElement("h3", { style: { fontStyle: "italic" } }, message), stack ? /* @__PURE__ */ React2.createElement("pre", { style: preStyles }, stack) : null, devInfo);
4323}
4324var defaultErrorElement = /* @__PURE__ */ React2.createElement(DefaultErrorComponent, null);
4325var RenderErrorBoundary = class extends React2.Component {
4326 constructor(props) {
4327 super(props);
4328 this.state = {
4329 location: props.location,
4330 revalidation: props.revalidation,
4331 error: props.error
4332 };
4333 }
4334 static getDerivedStateFromError(error) {
4335 return { error };
4336 }
4337 static getDerivedStateFromProps(props, state) {
4338 if (state.location !== props.location || state.revalidation !== "idle" && props.revalidation === "idle") {
4339 return {
4340 error: props.error,
4341 location: props.location,
4342 revalidation: props.revalidation
4343 };
4344 }
4345 return {
4346 error: props.error !== void 0 ? props.error : state.error,
4347 location: state.location,
4348 revalidation: props.revalidation || state.revalidation
4349 };
4350 }
4351 componentDidCatch(error, errorInfo) {
4352 console.error(
4353 "React Router caught the following error during render",
4354 error,
4355 errorInfo
4356 );
4357 }
4358 render() {
4359 return this.state.error !== void 0 ? /* @__PURE__ */ React2.createElement(RouteContext.Provider, { value: this.props.routeContext }, /* @__PURE__ */ React2.createElement(
4360 RouteErrorContext.Provider,
4361 {
4362 value: this.state.error,
4363 children: this.props.component
4364 }
4365 )) : this.props.children;
4366 }
4367};
4368function RenderedRoute({ routeContext, match, children }) {
4369 let dataRouterContext = React2.useContext(DataRouterContext);
4370 if (dataRouterContext && dataRouterContext.static && dataRouterContext.staticContext && (match.route.errorElement || match.route.ErrorBoundary)) {
4371 dataRouterContext.staticContext._deepestRenderedBoundaryId = match.route.id;
4372 }
4373 return /* @__PURE__ */ React2.createElement(RouteContext.Provider, { value: routeContext }, children);
4374}
4375function _renderMatches(matches, parentMatches = [], dataRouterState = null, future = null) {
4376 if (matches == null) {
4377 if (!dataRouterState) {
4378 return null;
4379 }
4380 if (dataRouterState.errors) {
4381 matches = dataRouterState.matches;
4382 } else if (parentMatches.length === 0 && !dataRouterState.initialized && dataRouterState.matches.length > 0) {
4383 matches = dataRouterState.matches;
4384 } else {
4385 return null;
4386 }
4387 }
4388 let renderedMatches = matches;
4389 let errors = dataRouterState?.errors;
4390 if (errors != null) {
4391 let errorIndex = renderedMatches.findIndex(
4392 (m) => m.route.id && errors?.[m.route.id] !== void 0
4393 );
4394 invariant(
4395 errorIndex >= 0,
4396 `Could not find a matching route for errors on route IDs: ${Object.keys(
4397 errors
4398 ).join(",")}`
4399 );
4400 renderedMatches = renderedMatches.slice(
4401 0,
4402 Math.min(renderedMatches.length, errorIndex + 1)
4403 );
4404 }
4405 let renderFallback = false;
4406 let fallbackIndex = -1;
4407 if (dataRouterState) {
4408 for (let i = 0; i < renderedMatches.length; i++) {
4409 let match = renderedMatches[i];
4410 if (match.route.HydrateFallback || match.route.hydrateFallbackElement) {
4411 fallbackIndex = i;
4412 }
4413 if (match.route.id) {
4414 let { loaderData, errors: errors2 } = dataRouterState;
4415 let needsToRunLoader = match.route.loader && !loaderData.hasOwnProperty(match.route.id) && (!errors2 || errors2[match.route.id] === void 0);
4416 if (match.route.lazy || needsToRunLoader) {
4417 renderFallback = true;
4418 if (fallbackIndex >= 0) {
4419 renderedMatches = renderedMatches.slice(0, fallbackIndex + 1);
4420 } else {
4421 renderedMatches = [renderedMatches[0]];
4422 }
4423 break;
4424 }
4425 }
4426 }
4427 }
4428 return renderedMatches.reduceRight((outlet, match, index) => {
4429 let error;
4430 let shouldRenderHydrateFallback = false;
4431 let errorElement = null;
4432 let hydrateFallbackElement = null;
4433 if (dataRouterState) {
4434 error = errors && match.route.id ? errors[match.route.id] : void 0;
4435 errorElement = match.route.errorElement || defaultErrorElement;
4436 if (renderFallback) {
4437 if (fallbackIndex < 0 && index === 0) {
4438 warningOnce(
4439 "route-fallback",
4440 false,
4441 "No `HydrateFallback` element provided to render during initial hydration"
4442 );
4443 shouldRenderHydrateFallback = true;
4444 hydrateFallbackElement = null;
4445 } else if (fallbackIndex === index) {
4446 shouldRenderHydrateFallback = true;
4447 hydrateFallbackElement = match.route.hydrateFallbackElement || null;
4448 }
4449 }
4450 }
4451 let matches2 = parentMatches.concat(renderedMatches.slice(0, index + 1));
4452 let getChildren = () => {
4453 let children;
4454 if (error) {
4455 children = errorElement;
4456 } else if (shouldRenderHydrateFallback) {
4457 children = hydrateFallbackElement;
4458 } else if (match.route.Component) {
4459 children = /* @__PURE__ */ React2.createElement(match.route.Component, null);
4460 } else if (match.route.element) {
4461 children = match.route.element;
4462 } else {
4463 children = outlet;
4464 }
4465 return /* @__PURE__ */ React2.createElement(
4466 RenderedRoute,
4467 {
4468 match,
4469 routeContext: {
4470 outlet,
4471 matches: matches2,
4472 isDataRoute: dataRouterState != null
4473 },
4474 children
4475 }
4476 );
4477 };
4478 return dataRouterState && (match.route.ErrorBoundary || match.route.errorElement || index === 0) ? /* @__PURE__ */ React2.createElement(
4479 RenderErrorBoundary,
4480 {
4481 location: dataRouterState.location,
4482 revalidation: dataRouterState.revalidation,
4483 component: errorElement,
4484 error,
4485 children: getChildren(),
4486 routeContext: { outlet: null, matches: matches2, isDataRoute: true }
4487 }
4488 ) : getChildren();
4489 }, null);
4490}
4491function getDataRouterConsoleError(hookName) {
4492 return `${hookName} must be used within a data router. See https://reactrouter.com/en/main/routers/picking-a-router.`;
4493}
4494function useDataRouterContext(hookName) {
4495 let ctx = React2.useContext(DataRouterContext);
4496 invariant(ctx, getDataRouterConsoleError(hookName));
4497 return ctx;
4498}
4499function useDataRouterState(hookName) {
4500 let state = React2.useContext(DataRouterStateContext);
4501 invariant(state, getDataRouterConsoleError(hookName));
4502 return state;
4503}
4504function useRouteContext(hookName) {
4505 let route = React2.useContext(RouteContext);
4506 invariant(route, getDataRouterConsoleError(hookName));
4507 return route;
4508}
4509function useCurrentRouteId(hookName) {
4510 let route = useRouteContext(hookName);
4511 let thisRoute = route.matches[route.matches.length - 1];
4512 invariant(
4513 thisRoute.route.id,
4514 `${hookName} can only be used on routes that contain a unique "id"`
4515 );
4516 return thisRoute.route.id;
4517}
4518function useRouteId() {
4519 return useCurrentRouteId("useRouteId" /* UseRouteId */);
4520}
4521function useNavigation() {
4522 let state = useDataRouterState("useNavigation" /* UseNavigation */);
4523 return state.navigation;
4524}
4525function useRevalidator() {
4526 let dataRouterContext = useDataRouterContext("useRevalidator" /* UseRevalidator */);
4527 let state = useDataRouterState("useRevalidator" /* UseRevalidator */);
4528 return React2.useMemo(
4529 () => ({
4530 async revalidate() {
4531 await dataRouterContext.router.revalidate();
4532 },
4533 state: state.revalidation
4534 }),
4535 [dataRouterContext.router, state.revalidation]
4536 );
4537}
4538function useMatches() {
4539 let { matches, loaderData } = useDataRouterState(
4540 "useMatches" /* UseMatches */
4541 );
4542 return React2.useMemo(
4543 () => matches.map((m) => convertRouteMatchToUiMatch(m, loaderData)),
4544 [matches, loaderData]
4545 );
4546}
4547function useLoaderData() {
4548 let state = useDataRouterState("useLoaderData" /* UseLoaderData */);
4549 let routeId = useCurrentRouteId("useLoaderData" /* UseLoaderData */);
4550 return state.loaderData[routeId];
4551}
4552function useRouteLoaderData(routeId) {
4553 let state = useDataRouterState("useRouteLoaderData" /* UseRouteLoaderData */);
4554 return state.loaderData[routeId];
4555}
4556function useActionData() {
4557 let state = useDataRouterState("useActionData" /* UseActionData */);
4558 let routeId = useCurrentRouteId("useLoaderData" /* UseLoaderData */);
4559 return state.actionData ? state.actionData[routeId] : void 0;
4560}
4561function useRouteError() {
4562 let error = React2.useContext(RouteErrorContext);
4563 let state = useDataRouterState("useRouteError" /* UseRouteError */);
4564 let routeId = useCurrentRouteId("useRouteError" /* UseRouteError */);
4565 if (error !== void 0) {
4566 return error;
4567 }
4568 return state.errors?.[routeId];
4569}
4570function useAsyncValue() {
4571 let value = React2.useContext(AwaitContext);
4572 return value?._data;
4573}
4574function useAsyncError() {
4575 let value = React2.useContext(AwaitContext);
4576 return value?._error;
4577}
4578var blockerId = 0;
4579function useBlocker(shouldBlock) {
4580 let { router, basename } = useDataRouterContext("useBlocker" /* UseBlocker */);
4581 let state = useDataRouterState("useBlocker" /* UseBlocker */);
4582 let [blockerKey, setBlockerKey] = React2.useState("");
4583 let blockerFunction = React2.useCallback(
4584 (arg) => {
4585 if (typeof shouldBlock !== "function") {
4586 return !!shouldBlock;
4587 }
4588 if (basename === "/") {
4589 return shouldBlock(arg);
4590 }
4591 let { currentLocation, nextLocation, historyAction } = arg;
4592 return shouldBlock({
4593 currentLocation: {
4594 ...currentLocation,
4595 pathname: stripBasename(currentLocation.pathname, basename) || currentLocation.pathname
4596 },
4597 nextLocation: {
4598 ...nextLocation,
4599 pathname: stripBasename(nextLocation.pathname, basename) || nextLocation.pathname
4600 },
4601 historyAction
4602 });
4603 },
4604 [basename, shouldBlock]
4605 );
4606 React2.useEffect(() => {
4607 let key = String(++blockerId);
4608 setBlockerKey(key);
4609 return () => router.deleteBlocker(key);
4610 }, [router]);
4611 React2.useEffect(() => {
4612 if (blockerKey !== "") {
4613 router.getBlocker(blockerKey, blockerFunction);
4614 }
4615 }, [router, blockerKey, blockerFunction]);
4616 return blockerKey && state.blockers.has(blockerKey) ? state.blockers.get(blockerKey) : IDLE_BLOCKER;
4617}
4618function useNavigateStable() {
4619 let { router } = useDataRouterContext("useNavigate" /* UseNavigateStable */);
4620 let id = useCurrentRouteId("useNavigate" /* UseNavigateStable */);
4621 let activeRef = React2.useRef(false);
4622 useIsomorphicLayoutEffect(() => {
4623 activeRef.current = true;
4624 });
4625 let navigate = React2.useCallback(
4626 async (to, options = {}) => {
4627 warning(activeRef.current, navigateEffectWarning);
4628 if (!activeRef.current) return;
4629 if (typeof to === "number") {
4630 router.navigate(to);
4631 } else {
4632 await router.navigate(to, { fromRouteId: id, ...options });
4633 }
4634 },
4635 [router, id]
4636 );
4637 return navigate;
4638}
4639var alreadyWarned = {};
4640function warningOnce(key, cond, message) {
4641 if (!cond && !alreadyWarned[key]) {
4642 alreadyWarned[key] = true;
4643 warning(false, message);
4644 }
4645}
4646
4647// lib/server-runtime/warnings.ts
4648var alreadyWarned2 = {};
4649function warnOnce(condition, message) {
4650 if (!condition && !alreadyWarned2[message]) {
4651 alreadyWarned2[message] = true;
4652 console.warn(message);
4653 }
4654}
4655
4656// lib/components.tsx
4657var ENABLE_DEV_WARNINGS2 = false;
4658function mapRouteProperties(route) {
4659 let updates = {
4660 // Note: this check also occurs in createRoutesFromChildren so update
4661 // there if you change this -- please and thank you!
4662 hasErrorBoundary: route.hasErrorBoundary || route.ErrorBoundary != null || route.errorElement != null
4663 };
4664 if (route.Component) {
4665 if (ENABLE_DEV_WARNINGS2) {
4666 if (route.element) {
4667 warning(
4668 false,
4669 "You should not include both `Component` and `element` on your route - `Component` will be used."
4670 );
4671 }
4672 }
4673 Object.assign(updates, {
4674 element: React3.createElement(route.Component),
4675 Component: void 0
4676 });
4677 }
4678 if (route.HydrateFallback) {
4679 if (ENABLE_DEV_WARNINGS2) {
4680 if (route.hydrateFallbackElement) {
4681 warning(
4682 false,
4683 "You should not include both `HydrateFallback` and `hydrateFallbackElement` on your route - `HydrateFallback` will be used."
4684 );
4685 }
4686 }
4687 Object.assign(updates, {
4688 hydrateFallbackElement: React3.createElement(route.HydrateFallback),
4689 HydrateFallback: void 0
4690 });
4691 }
4692 if (route.ErrorBoundary) {
4693 if (ENABLE_DEV_WARNINGS2) {
4694 if (route.errorElement) {
4695 warning(
4696 false,
4697 "You should not include both `ErrorBoundary` and `errorElement` on your route - `ErrorBoundary` will be used."
4698 );
4699 }
4700 }
4701 Object.assign(updates, {
4702 errorElement: React3.createElement(route.ErrorBoundary),
4703 ErrorBoundary: void 0
4704 });
4705 }
4706 return updates;
4707}
4708function createMemoryRouter(routes, opts) {
4709 return createRouter({
4710 basename: opts?.basename,
4711 future: opts?.future,
4712 history: createMemoryHistory({
4713 initialEntries: opts?.initialEntries,
4714 initialIndex: opts?.initialIndex
4715 }),
4716 hydrationData: opts?.hydrationData,
4717 routes,
4718 mapRouteProperties,
4719 dataStrategy: opts?.dataStrategy,
4720 patchRoutesOnNavigation: opts?.patchRoutesOnNavigation
4721 }).initialize();
4722}
4723var Deferred = class {
4724 constructor() {
4725 this.status = "pending";
4726 this.promise = new Promise((resolve, reject) => {
4727 this.resolve = (value) => {
4728 if (this.status === "pending") {
4729 this.status = "resolved";
4730 resolve(value);
4731 }
4732 };
4733 this.reject = (reason) => {
4734 if (this.status === "pending") {
4735 this.status = "rejected";
4736 reject(reason);
4737 }
4738 };
4739 });
4740 }
4741};
4742function RouterProvider({
4743 router,
4744 flushSync: reactDomFlushSyncImpl
4745}) {
4746 let [state, setStateImpl] = React3.useState(router.state);
4747 let [pendingState, setPendingState] = React3.useState();
4748 let [vtContext, setVtContext] = React3.useState({
4749 isTransitioning: false
4750 });
4751 let [renderDfd, setRenderDfd] = React3.useState();
4752 let [transition, setTransition] = React3.useState();
4753 let [interruption, setInterruption] = React3.useState();
4754 let fetcherData = React3.useRef(/* @__PURE__ */ new Map());
4755 let setState = React3.useCallback(
4756 (newState, { deletedFetchers, flushSync, viewTransitionOpts }) => {
4757 newState.fetchers.forEach((fetcher, key) => {
4758 if (fetcher.data !== void 0) {
4759 fetcherData.current.set(key, fetcher.data);
4760 }
4761 });
4762 deletedFetchers.forEach((key) => fetcherData.current.delete(key));
4763 warnOnce(
4764 flushSync === false || reactDomFlushSyncImpl != null,
4765 'You provided the `flushSync` option to a router update, but you are not using the `<RouterProvider>` from `react-router/dom` so `ReactDOM.flushSync()` is unavailable. Please update your app to `import { RouterProvider } from "react-router/dom"` and ensure you have `react-dom` installed as a dependency to use the `flushSync` option.'
4766 );
4767 let isViewTransitionAvailable = router.window != null && router.window.document != null && typeof router.window.document.startViewTransition === "function";
4768 warnOnce(
4769 viewTransitionOpts == null || isViewTransitionAvailable,
4770 "You provided the `viewTransition` option to a router update, but you do not appear to be running in a DOM environment as `window.startViewTransition` is not available."
4771 );
4772 if (!viewTransitionOpts || !isViewTransitionAvailable) {
4773 if (reactDomFlushSyncImpl && flushSync) {
4774 reactDomFlushSyncImpl(() => setStateImpl(newState));
4775 } else {
4776 React3.startTransition(() => setStateImpl(newState));
4777 }
4778 return;
4779 }
4780 if (reactDomFlushSyncImpl && flushSync) {
4781 reactDomFlushSyncImpl(() => {
4782 if (transition) {
4783 renderDfd && renderDfd.resolve();
4784 transition.skipTransition();
4785 }
4786 setVtContext({
4787 isTransitioning: true,
4788 flushSync: true,
4789 currentLocation: viewTransitionOpts.currentLocation,
4790 nextLocation: viewTransitionOpts.nextLocation
4791 });
4792 });
4793 let t = router.window.document.startViewTransition(() => {
4794 reactDomFlushSyncImpl(() => setStateImpl(newState));
4795 });
4796 t.finished.finally(() => {
4797 reactDomFlushSyncImpl(() => {
4798 setRenderDfd(void 0);
4799 setTransition(void 0);
4800 setPendingState(void 0);
4801 setVtContext({ isTransitioning: false });
4802 });
4803 });
4804 reactDomFlushSyncImpl(() => setTransition(t));
4805 return;
4806 }
4807 if (transition) {
4808 renderDfd && renderDfd.resolve();
4809 transition.skipTransition();
4810 setInterruption({
4811 state: newState,
4812 currentLocation: viewTransitionOpts.currentLocation,
4813 nextLocation: viewTransitionOpts.nextLocation
4814 });
4815 } else {
4816 setPendingState(newState);
4817 setVtContext({
4818 isTransitioning: true,
4819 flushSync: false,
4820 currentLocation: viewTransitionOpts.currentLocation,
4821 nextLocation: viewTransitionOpts.nextLocation
4822 });
4823 }
4824 },
4825 [router.window, reactDomFlushSyncImpl, transition, renderDfd]
4826 );
4827 React3.useLayoutEffect(() => router.subscribe(setState), [router, setState]);
4828 React3.useEffect(() => {
4829 if (vtContext.isTransitioning && !vtContext.flushSync) {
4830 setRenderDfd(new Deferred());
4831 }
4832 }, [vtContext]);
4833 React3.useEffect(() => {
4834 if (renderDfd && pendingState && router.window) {
4835 let newState = pendingState;
4836 let renderPromise = renderDfd.promise;
4837 let transition2 = router.window.document.startViewTransition(async () => {
4838 React3.startTransition(() => setStateImpl(newState));
4839 await renderPromise;
4840 });
4841 transition2.finished.finally(() => {
4842 setRenderDfd(void 0);
4843 setTransition(void 0);
4844 setPendingState(void 0);
4845 setVtContext({ isTransitioning: false });
4846 });
4847 setTransition(transition2);
4848 }
4849 }, [pendingState, renderDfd, router.window]);
4850 React3.useEffect(() => {
4851 if (renderDfd && pendingState && state.location.key === pendingState.location.key) {
4852 renderDfd.resolve();
4853 }
4854 }, [renderDfd, transition, state.location, pendingState]);
4855 React3.useEffect(() => {
4856 if (!vtContext.isTransitioning && interruption) {
4857 setPendingState(interruption.state);
4858 setVtContext({
4859 isTransitioning: true,
4860 flushSync: false,
4861 currentLocation: interruption.currentLocation,
4862 nextLocation: interruption.nextLocation
4863 });
4864 setInterruption(void 0);
4865 }
4866 }, [vtContext.isTransitioning, interruption]);
4867 let navigator2 = React3.useMemo(() => {
4868 return {
4869 createHref: router.createHref,
4870 encodeLocation: router.encodeLocation,
4871 go: (n) => router.navigate(n),
4872 push: (to, state2, opts) => router.navigate(to, {
4873 state: state2,
4874 preventScrollReset: opts?.preventScrollReset
4875 }),
4876 replace: (to, state2, opts) => router.navigate(to, {
4877 replace: true,
4878 state: state2,
4879 preventScrollReset: opts?.preventScrollReset
4880 })
4881 };
4882 }, [router]);
4883 let basename = router.basename || "/";
4884 let dataRouterContext = React3.useMemo(
4885 () => ({
4886 router,
4887 navigator: navigator2,
4888 static: false,
4889 basename
4890 }),
4891 [router, navigator2, basename]
4892 );
4893 return /* @__PURE__ */ React3.createElement(React3.Fragment, null, /* @__PURE__ */ React3.createElement(DataRouterContext.Provider, { value: dataRouterContext }, /* @__PURE__ */ React3.createElement(DataRouterStateContext.Provider, { value: state }, /* @__PURE__ */ React3.createElement(FetchersContext.Provider, { value: fetcherData.current }, /* @__PURE__ */ React3.createElement(ViewTransitionContext.Provider, { value: vtContext }, /* @__PURE__ */ React3.createElement(
4894 Router,
4895 {
4896 basename,
4897 location: state.location,
4898 navigationType: state.historyAction,
4899 navigator: navigator2
4900 },
4901 /* @__PURE__ */ React3.createElement(
4902 MemoizedDataRoutes,
4903 {
4904 routes: router.routes,
4905 future: router.future,
4906 state
4907 }
4908 )
4909 ))))), null);
4910}
4911var MemoizedDataRoutes = React3.memo(DataRoutes);
4912function DataRoutes({
4913 routes,
4914 future,
4915 state
4916}) {
4917 return useRoutesImpl(routes, void 0, state, future);
4918}
4919function MemoryRouter({
4920 basename,
4921 children,
4922 initialEntries,
4923 initialIndex
4924}) {
4925 let historyRef = React3.useRef();
4926 if (historyRef.current == null) {
4927 historyRef.current = createMemoryHistory({
4928 initialEntries,
4929 initialIndex,
4930 v5Compat: true
4931 });
4932 }
4933 let history = historyRef.current;
4934 let [state, setStateImpl] = React3.useState({
4935 action: history.action,
4936 location: history.location
4937 });
4938 let setState = React3.useCallback(
4939 (newState) => {
4940 React3.startTransition(() => setStateImpl(newState));
4941 },
4942 [setStateImpl]
4943 );
4944 React3.useLayoutEffect(() => history.listen(setState), [history, setState]);
4945 return /* @__PURE__ */ React3.createElement(
4946 Router,
4947 {
4948 basename,
4949 children,
4950 location: state.location,
4951 navigationType: state.action,
4952 navigator: history
4953 }
4954 );
4955}
4956function Navigate({
4957 to,
4958 replace: replace2,
4959 state,
4960 relative
4961}) {
4962 invariant(
4963 useInRouterContext(),
4964 // TODO: This error is probably because they somehow have 2 versions of
4965 // the router loaded. We can help them understand how to avoid that.
4966 `<Navigate> may be used only in the context of a <Router> component.`
4967 );
4968 let { static: isStatic } = React3.useContext(NavigationContext);
4969 warning(
4970 !isStatic,
4971 `<Navigate> must not be used on the initial render in a <StaticRouter>. This is a no-op, but you should modify your code so the <Navigate> is only ever rendered in response to some user interaction or state change.`
4972 );
4973 let { matches } = React3.useContext(RouteContext);
4974 let { pathname: locationPathname } = useLocation();
4975 let navigate = useNavigate();
4976 let path = resolveTo(
4977 to,
4978 getResolveToMatches(matches),
4979 locationPathname,
4980 relative === "path"
4981 );
4982 let jsonPath = JSON.stringify(path);
4983 React3.useEffect(() => {
4984 navigate(JSON.parse(jsonPath), { replace: replace2, state, relative });
4985 }, [navigate, jsonPath, relative, replace2, state]);
4986 return null;
4987}
4988function Outlet(props) {
4989 return useOutlet(props.context);
4990}
4991function Route(_props) {
4992 invariant(
4993 false,
4994 `A <Route> is only ever to be used as the child of <Routes> element, never rendered directly. Please wrap your <Route> in a <Routes>.`
4995 );
4996}
4997function Router({
4998 basename: basenameProp = "/",
4999 children = null,
5000 location: locationProp,
5001 navigationType = "POP" /* Pop */,
5002 navigator: navigator2,
5003 static: staticProp = false
5004}) {
5005 invariant(
5006 !useInRouterContext(),
5007 `You cannot render a <Router> inside another <Router>. You should never have more than one in your app.`
5008 );
5009 let basename = basenameProp.replace(/^\/*/, "/");
5010 let navigationContext = React3.useMemo(
5011 () => ({
5012 basename,
5013 navigator: navigator2,
5014 static: staticProp,
5015 future: {}
5016 }),
5017 [basename, navigator2, staticProp]
5018 );
5019 if (typeof locationProp === "string") {
5020 locationProp = parsePath(locationProp);
5021 }
5022 let {
5023 pathname = "/",
5024 search = "",
5025 hash = "",
5026 state = null,
5027 key = "default"
5028 } = locationProp;
5029 let locationContext = React3.useMemo(() => {
5030 let trailingPathname = stripBasename(pathname, basename);
5031 if (trailingPathname == null) {
5032 return null;
5033 }
5034 return {
5035 location: {
5036 pathname: trailingPathname,
5037 search,
5038 hash,
5039 state,
5040 key
5041 },
5042 navigationType
5043 };
5044 }, [basename, pathname, search, hash, state, key, navigationType]);
5045 warning(
5046 locationContext != null,
5047 `<Router basename="${basename}"> is not able to match the URL "${pathname}${search}${hash}" because it does not start with the basename, so the <Router> won't render anything.`
5048 );
5049 if (locationContext == null) {
5050 return null;
5051 }
5052 return /* @__PURE__ */ React3.createElement(NavigationContext.Provider, { value: navigationContext }, /* @__PURE__ */ React3.createElement(LocationContext.Provider, { children, value: locationContext }));
5053}
5054function Routes({
5055 children,
5056 location
5057}) {
5058 return useRoutes(createRoutesFromChildren(children), location);
5059}
5060function Await({
5061 children,
5062 errorElement,
5063 resolve
5064}) {
5065 return /* @__PURE__ */ React3.createElement(AwaitErrorBoundary, { resolve, errorElement }, /* @__PURE__ */ React3.createElement(ResolveAwait, null, children));
5066}
5067var AwaitErrorBoundary = class extends React3.Component {
5068 constructor(props) {
5069 super(props);
5070 this.state = { error: null };
5071 }
5072 static getDerivedStateFromError(error) {
5073 return { error };
5074 }
5075 componentDidCatch(error, errorInfo) {
5076 console.error(
5077 "<Await> caught the following error during render",
5078 error,
5079 errorInfo
5080 );
5081 }
5082 render() {
5083 let { children, errorElement, resolve } = this.props;
5084 let promise = null;
5085 let status = 0 /* pending */;
5086 if (!(resolve instanceof Promise)) {
5087 status = 1 /* success */;
5088 promise = Promise.resolve();
5089 Object.defineProperty(promise, "_tracked", { get: () => true });
5090 Object.defineProperty(promise, "_data", { get: () => resolve });
5091 } else if (this.state.error) {
5092 status = 2 /* error */;
5093 let renderError = this.state.error;
5094 promise = Promise.reject().catch(() => {
5095 });
5096 Object.defineProperty(promise, "_tracked", { get: () => true });
5097 Object.defineProperty(promise, "_error", { get: () => renderError });
5098 } else if (resolve._tracked) {
5099 promise = resolve;
5100 status = "_error" in promise ? 2 /* error */ : "_data" in promise ? 1 /* success */ : 0 /* pending */;
5101 } else {
5102 status = 0 /* pending */;
5103 Object.defineProperty(resolve, "_tracked", { get: () => true });
5104 promise = resolve.then(
5105 (data2) => Object.defineProperty(resolve, "_data", { get: () => data2 }),
5106 (error) => Object.defineProperty(resolve, "_error", { get: () => error })
5107 );
5108 }
5109 if (status === 2 /* error */ && !errorElement) {
5110 throw promise._error;
5111 }
5112 if (status === 2 /* error */) {
5113 return /* @__PURE__ */ React3.createElement(AwaitContext.Provider, { value: promise, children: errorElement });
5114 }
5115 if (status === 1 /* success */) {
5116 return /* @__PURE__ */ React3.createElement(AwaitContext.Provider, { value: promise, children });
5117 }
5118 throw promise;
5119 }
5120};
5121function ResolveAwait({
5122 children
5123}) {
5124 let data2 = useAsyncValue();
5125 let toRender = typeof children === "function" ? children(data2) : children;
5126 return /* @__PURE__ */ React3.createElement(React3.Fragment, null, toRender);
5127}
5128function createRoutesFromChildren(children, parentPath = []) {
5129 let routes = [];
5130 React3.Children.forEach(children, (element, index) => {
5131 if (!React3.isValidElement(element)) {
5132 return;
5133 }
5134 let treePath = [...parentPath, index];
5135 if (element.type === React3.Fragment) {
5136 routes.push.apply(
5137 routes,
5138 createRoutesFromChildren(element.props.children, treePath)
5139 );
5140 return;
5141 }
5142 invariant(
5143 element.type === Route,
5144 `[${typeof element.type === "string" ? element.type : element.type.name}] is not a <Route> component. All component children of <Routes> must be a <Route> or <React.Fragment>`
5145 );
5146 invariant(
5147 !element.props.index || !element.props.children,
5148 "An index route cannot have child routes."
5149 );
5150 let route = {
5151 id: element.props.id || treePath.join("-"),
5152 caseSensitive: element.props.caseSensitive,
5153 element: element.props.element,
5154 Component: element.props.Component,
5155 index: element.props.index,
5156 path: element.props.path,
5157 loader: element.props.loader,
5158 action: element.props.action,
5159 hydrateFallbackElement: element.props.hydrateFallbackElement,
5160 HydrateFallback: element.props.HydrateFallback,
5161 errorElement: element.props.errorElement,
5162 ErrorBoundary: element.props.ErrorBoundary,
5163 hasErrorBoundary: element.props.hasErrorBoundary === true || element.props.ErrorBoundary != null || element.props.errorElement != null,
5164 shouldRevalidate: element.props.shouldRevalidate,
5165 handle: element.props.handle,
5166 lazy: element.props.lazy
5167 };
5168 if (element.props.children) {
5169 route.children = createRoutesFromChildren(
5170 element.props.children,
5171 treePath
5172 );
5173 }
5174 routes.push(route);
5175 });
5176 return routes;
5177}
5178var createRoutesFromElements = createRoutesFromChildren;
5179function renderMatches(matches) {
5180 return _renderMatches(matches);
5181}
5182
5183// lib/dom/lib.tsx
5184import * as React10 from "react";
5185
5186// lib/dom/dom.ts
5187var defaultMethod = "get";
5188var defaultEncType = "application/x-www-form-urlencoded";
5189function isHtmlElement(object) {
5190 return object != null && typeof object.tagName === "string";
5191}
5192function isButtonElement(object) {
5193 return isHtmlElement(object) && object.tagName.toLowerCase() === "button";
5194}
5195function isFormElement(object) {
5196 return isHtmlElement(object) && object.tagName.toLowerCase() === "form";
5197}
5198function isInputElement(object) {
5199 return isHtmlElement(object) && object.tagName.toLowerCase() === "input";
5200}
5201function isModifiedEvent(event) {
5202 return !!(event.metaKey || event.altKey || event.ctrlKey || event.shiftKey);
5203}
5204function shouldProcessLinkClick(event, target) {
5205 return event.button === 0 && // Ignore everything but left clicks
5206 (!target || target === "_self") && // Let browser handle "target=_blank" etc.
5207 !isModifiedEvent(event);
5208}
5209function createSearchParams(init = "") {
5210 return new URLSearchParams(
5211 typeof init === "string" || Array.isArray(init) || init instanceof URLSearchParams ? init : Object.keys(init).reduce((memo2, key) => {
5212 let value = init[key];
5213 return memo2.concat(
5214 Array.isArray(value) ? value.map((v) => [key, v]) : [[key, value]]
5215 );
5216 }, [])
5217 );
5218}
5219function getSearchParamsForLocation(locationSearch, defaultSearchParams) {
5220 let searchParams = createSearchParams(locationSearch);
5221 if (defaultSearchParams) {
5222 defaultSearchParams.forEach((_, key) => {
5223 if (!searchParams.has(key)) {
5224 defaultSearchParams.getAll(key).forEach((value) => {
5225 searchParams.append(key, value);
5226 });
5227 }
5228 });
5229 }
5230 return searchParams;
5231}
5232var _formDataSupportsSubmitter = null;
5233function isFormDataSubmitterSupported() {
5234 if (_formDataSupportsSubmitter === null) {
5235 try {
5236 new FormData(
5237 document.createElement("form"),
5238 // @ts-expect-error if FormData supports the submitter parameter, this will throw
5239 0
5240 );
5241 _formDataSupportsSubmitter = false;
5242 } catch (e) {
5243 _formDataSupportsSubmitter = true;
5244 }
5245 }
5246 return _formDataSupportsSubmitter;
5247}
5248var supportedFormEncTypes = /* @__PURE__ */ new Set([
5249 "application/x-www-form-urlencoded",
5250 "multipart/form-data",
5251 "text/plain"
5252]);
5253function getFormEncType(encType) {
5254 if (encType != null && !supportedFormEncTypes.has(encType)) {
5255 warning(
5256 false,
5257 `"${encType}" is not a valid \`encType\` for \`<Form>\`/\`<fetcher.Form>\` and will default to "${defaultEncType}"`
5258 );
5259 return null;
5260 }
5261 return encType;
5262}
5263function getFormSubmissionInfo(target, basename) {
5264 let method;
5265 let action;
5266 let encType;
5267 let formData;
5268 let body;
5269 if (isFormElement(target)) {
5270 let attr = target.getAttribute("action");
5271 action = attr ? stripBasename(attr, basename) : null;
5272 method = target.getAttribute("method") || defaultMethod;
5273 encType = getFormEncType(target.getAttribute("enctype")) || defaultEncType;
5274 formData = new FormData(target);
5275 } else if (isButtonElement(target) || isInputElement(target) && (target.type === "submit" || target.type === "image")) {
5276 let form = target.form;
5277 if (form == null) {
5278 throw new Error(
5279 `Cannot submit a <button> or <input type="submit"> without a <form>`
5280 );
5281 }
5282 let attr = target.getAttribute("formaction") || form.getAttribute("action");
5283 action = attr ? stripBasename(attr, basename) : null;
5284 method = target.getAttribute("formmethod") || form.getAttribute("method") || defaultMethod;
5285 encType = getFormEncType(target.getAttribute("formenctype")) || getFormEncType(form.getAttribute("enctype")) || defaultEncType;
5286 formData = new FormData(form, target);
5287 if (!isFormDataSubmitterSupported()) {
5288 let { name, type, value } = target;
5289 if (type === "image") {
5290 let prefix = name ? `${name}.` : "";
5291 formData.append(`${prefix}x`, "0");
5292 formData.append(`${prefix}y`, "0");
5293 } else if (name) {
5294 formData.append(name, value);
5295 }
5296 }
5297 } else if (isHtmlElement(target)) {
5298 throw new Error(
5299 `Cannot submit element that is not <form>, <button>, or <input type="submit|image">`
5300 );
5301 } else {
5302 method = defaultMethod;
5303 action = null;
5304 encType = defaultEncType;
5305 body = target;
5306 }
5307 if (formData && encType === "text/plain") {
5308 body = formData;
5309 formData = void 0;
5310 }
5311 return { action, method: method.toLowerCase(), encType, formData, body };
5312}
5313
5314// lib/dom/ssr/components.tsx
5315import * as React9 from "react";
5316
5317// lib/dom/ssr/invariant.ts
5318function invariant2(value, message) {
5319 if (value === false || value === null || typeof value === "undefined") {
5320 throw new Error(message);
5321 }
5322}
5323
5324// lib/dom/ssr/routeModules.ts
5325async function loadRouteModule(route, routeModulesCache) {
5326 if (route.id in routeModulesCache) {
5327 return routeModulesCache[route.id];
5328 }
5329 try {
5330 let routeModule = await import(
5331 /* @vite-ignore */
5332 /* webpackIgnore: true */
5333 route.module
5334 );
5335 routeModulesCache[route.id] = routeModule;
5336 return routeModule;
5337 } catch (error) {
5338 console.error(
5339 `Error loading route module \`${route.module}\`, reloading page...`
5340 );
5341 console.error(error);
5342 if (window.__reactRouterContext && window.__reactRouterContext.isSpaMode && // @ts-expect-error
5343 import.meta.hot) {
5344 throw error;
5345 }
5346 window.location.reload();
5347 return new Promise(() => {
5348 });
5349 }
5350}
5351
5352// lib/dom/ssr/links.ts
5353function getKeyedLinksForMatches(matches, routeModules, manifest) {
5354 let descriptors = matches.map((match) => {
5355 let module = routeModules[match.route.id];
5356 let route = manifest.routes[match.route.id];
5357 return [
5358 route && route.css ? route.css.map((href) => ({ rel: "stylesheet", href })) : [],
5359 module?.links?.() || []
5360 ];
5361 }).flat(2);
5362 let preloads = getCurrentPageModulePreloadHrefs(matches, manifest);
5363 return dedupeLinkDescriptors(descriptors, preloads);
5364}
5365async function prefetchStyleLinks(route, routeModule) {
5366 if (!route.css && !routeModule.links || !isPreloadSupported()) return;
5367 let descriptors = [];
5368 if (route.css) {
5369 descriptors.push(...route.css.map((href) => ({ rel: "stylesheet", href })));
5370 }
5371 if (routeModule.links) {
5372 descriptors.push(...routeModule.links());
5373 }
5374 if (descriptors.length === 0) return;
5375 let styleLinks = [];
5376 for (let descriptor of descriptors) {
5377 if (!isPageLinkDescriptor(descriptor) && descriptor.rel === "stylesheet") {
5378 styleLinks.push({
5379 ...descriptor,
5380 rel: "preload",
5381 as: "style"
5382 });
5383 }
5384 }
5385 let matchingLinks = styleLinks.filter(
5386 (link) => (!link.media || window.matchMedia(link.media).matches) && !document.querySelector(`link[rel="stylesheet"][href="${link.href}"]`)
5387 );
5388 await Promise.all(matchingLinks.map(prefetchStyleLink));
5389}
5390async function prefetchStyleLink(descriptor) {
5391 return new Promise((resolve) => {
5392 let link = document.createElement("link");
5393 Object.assign(link, descriptor);
5394 function removeLink() {
5395 if (document.head.contains(link)) {
5396 document.head.removeChild(link);
5397 }
5398 }
5399 link.onload = () => {
5400 removeLink();
5401 resolve();
5402 };
5403 link.onerror = () => {
5404 removeLink();
5405 resolve();
5406 };
5407 document.head.appendChild(link);
5408 });
5409}
5410function isPageLinkDescriptor(object) {
5411 return object != null && typeof object.page === "string";
5412}
5413function isHtmlLinkDescriptor(object) {
5414 if (object == null) {
5415 return false;
5416 }
5417 if (object.href == null) {
5418 return object.rel === "preload" && typeof object.imageSrcSet === "string" && typeof object.imageSizes === "string";
5419 }
5420 return typeof object.rel === "string" && typeof object.href === "string";
5421}
5422async function getKeyedPrefetchLinks(matches, manifest, routeModules) {
5423 let links = await Promise.all(
5424 matches.map(async (match) => {
5425 let route = manifest.routes[match.route.id];
5426 if (route) {
5427 let mod = await loadRouteModule(route, routeModules);
5428 return mod.links ? mod.links() : [];
5429 }
5430 return [];
5431 })
5432 );
5433 return dedupeLinkDescriptors(
5434 links.flat(1).filter(isHtmlLinkDescriptor).filter((link) => link.rel === "stylesheet" || link.rel === "preload").map(
5435 (link) => link.rel === "stylesheet" ? { ...link, rel: "prefetch", as: "style" } : { ...link, rel: "prefetch" }
5436 )
5437 );
5438}
5439function getNewMatchesForLinks(page, nextMatches, currentMatches, manifest, location, mode) {
5440 let isNew = (match, index) => {
5441 if (!currentMatches[index]) return true;
5442 return match.route.id !== currentMatches[index].route.id;
5443 };
5444 let matchPathChanged = (match, index) => {
5445 return (
5446 // param change, /users/123 -> /users/456
5447 currentMatches[index].pathname !== match.pathname || // splat param changed, which is not present in match.path
5448 // e.g. /files/images/avatar.jpg -> files/finances.xls
5449 currentMatches[index].route.path?.endsWith("*") && currentMatches[index].params["*"] !== match.params["*"]
5450 );
5451 };
5452 if (mode === "assets") {
5453 return nextMatches.filter(
5454 (match, index) => isNew(match, index) || matchPathChanged(match, index)
5455 );
5456 }
5457 if (mode === "data") {
5458 return nextMatches.filter((match, index) => {
5459 let manifestRoute = manifest.routes[match.route.id];
5460 if (!manifestRoute || !manifestRoute.hasLoader) {
5461 return false;
5462 }
5463 if (isNew(match, index) || matchPathChanged(match, index)) {
5464 return true;
5465 }
5466 if (match.route.shouldRevalidate) {
5467 let routeChoice = match.route.shouldRevalidate({
5468 currentUrl: new URL(
5469 location.pathname + location.search + location.hash,
5470 window.origin
5471 ),
5472 currentParams: currentMatches[0]?.params || {},
5473 nextUrl: new URL(page, window.origin),
5474 nextParams: match.params,
5475 defaultShouldRevalidate: true
5476 });
5477 if (typeof routeChoice === "boolean") {
5478 return routeChoice;
5479 }
5480 }
5481 return true;
5482 });
5483 }
5484 return [];
5485}
5486function getModuleLinkHrefs(matches, manifestPatch) {
5487 return dedupeHrefs(
5488 matches.map((match) => {
5489 let route = manifestPatch.routes[match.route.id];
5490 if (!route) return [];
5491 let hrefs = [route.module];
5492 if (route.imports) {
5493 hrefs = hrefs.concat(route.imports);
5494 }
5495 return hrefs;
5496 }).flat(1)
5497 );
5498}
5499function getCurrentPageModulePreloadHrefs(matches, manifest) {
5500 return dedupeHrefs(
5501 matches.map((match) => {
5502 let route = manifest.routes[match.route.id];
5503 if (!route) return [];
5504 let hrefs = [route.module];
5505 if (route.imports) {
5506 hrefs = hrefs.concat(route.imports);
5507 }
5508 return hrefs;
5509 }).flat(1)
5510 );
5511}
5512function dedupeHrefs(hrefs) {
5513 return [...new Set(hrefs)];
5514}
5515function sortKeys(obj) {
5516 let sorted = {};
5517 let keys = Object.keys(obj).sort();
5518 for (let key of keys) {
5519 sorted[key] = obj[key];
5520 }
5521 return sorted;
5522}
5523function dedupeLinkDescriptors(descriptors, preloads) {
5524 let set = /* @__PURE__ */ new Set();
5525 let preloadsSet = new Set(preloads);
5526 return descriptors.reduce((deduped, descriptor) => {
5527 let alreadyModulePreload = preloads && !isPageLinkDescriptor(descriptor) && descriptor.as === "script" && descriptor.href && preloadsSet.has(descriptor.href);
5528 if (alreadyModulePreload) {
5529 return deduped;
5530 }
5531 let key = JSON.stringify(sortKeys(descriptor));
5532 if (!set.has(key)) {
5533 set.add(key);
5534 deduped.push({ key, link: descriptor });
5535 }
5536 return deduped;
5537 }, []);
5538}
5539var _isPreloadSupported;
5540function isPreloadSupported() {
5541 if (_isPreloadSupported !== void 0) {
5542 return _isPreloadSupported;
5543 }
5544 let el = document.createElement("link");
5545 _isPreloadSupported = el.relList.supports("preload");
5546 el = null;
5547 return _isPreloadSupported;
5548}
5549
5550// lib/dom/ssr/markup.ts
5551var ESCAPE_LOOKUP = {
5552 "&": "\\u0026",
5553 ">": "\\u003e",
5554 "<": "\\u003c",
5555 "\u2028": "\\u2028",
5556 "\u2029": "\\u2029"
5557};
5558var ESCAPE_REGEX = /[&><\u2028\u2029]/g;
5559function escapeHtml(html) {
5560 return html.replace(ESCAPE_REGEX, (match) => ESCAPE_LOOKUP[match]);
5561}
5562function createHtml(html) {
5563 return { __html: html };
5564}
5565
5566// lib/dom/ssr/single-fetch.tsx
5567import * as React4 from "react";
5568import { decode } from "turbo-stream";
5569
5570// lib/dom/ssr/data.ts
5571async function createRequestInit(request) {
5572 let init = { signal: request.signal };
5573 if (request.method !== "GET") {
5574 init.method = request.method;
5575 let contentType = request.headers.get("Content-Type");
5576 if (contentType && /\bapplication\/json\b/.test(contentType)) {
5577 init.headers = { "Content-Type": contentType };
5578 init.body = JSON.stringify(await request.json());
5579 } else if (contentType && /\btext\/plain\b/.test(contentType)) {
5580 init.headers = { "Content-Type": contentType };
5581 init.body = await request.text();
5582 } else if (contentType && /\bapplication\/x-www-form-urlencoded\b/.test(contentType)) {
5583 init.body = new URLSearchParams(await request.text());
5584 } else {
5585 init.body = await request.formData();
5586 }
5587 }
5588 return init;
5589}
5590
5591// lib/dom/ssr/single-fetch.tsx
5592var SingleFetchRedirectSymbol = Symbol("SingleFetchRedirect");
5593function StreamTransfer({
5594 context,
5595 identifier,
5596 reader,
5597 textDecoder,
5598 nonce
5599}) {
5600 if (!context.renderMeta || !context.renderMeta.didRenderScripts) {
5601 return null;
5602 }
5603 if (!context.renderMeta.streamCache) {
5604 context.renderMeta.streamCache = {};
5605 }
5606 let { streamCache } = context.renderMeta;
5607 let promise = streamCache[identifier];
5608 if (!promise) {
5609 promise = streamCache[identifier] = reader.read().then((result) => {
5610 streamCache[identifier].result = {
5611 done: result.done,
5612 value: textDecoder.decode(result.value, { stream: true })
5613 };
5614 }).catch((e) => {
5615 streamCache[identifier].error = e;
5616 });
5617 }
5618 if (promise.error) {
5619 throw promise.error;
5620 }
5621 if (promise.result === void 0) {
5622 throw promise;
5623 }
5624 let { done, value } = promise.result;
5625 let scriptTag = value ? /* @__PURE__ */ React4.createElement(
5626 "script",
5627 {
5628 nonce,
5629 dangerouslySetInnerHTML: {
5630 __html: `window.__reactRouterContext.streamController.enqueue(${escapeHtml(
5631 JSON.stringify(value)
5632 )});`
5633 }
5634 }
5635 ) : null;
5636 if (done) {
5637 return /* @__PURE__ */ React4.createElement(React4.Fragment, null, scriptTag, /* @__PURE__ */ React4.createElement(
5638 "script",
5639 {
5640 nonce,
5641 dangerouslySetInnerHTML: {
5642 __html: `window.__reactRouterContext.streamController.close();`
5643 }
5644 }
5645 ));
5646 } else {
5647 return /* @__PURE__ */ React4.createElement(React4.Fragment, null, scriptTag, /* @__PURE__ */ React4.createElement(React4.Suspense, null, /* @__PURE__ */ React4.createElement(
5648 StreamTransfer,
5649 {
5650 context,
5651 identifier: identifier + 1,
5652 reader,
5653 textDecoder,
5654 nonce
5655 }
5656 )));
5657 }
5658}
5659function getSingleFetchDataStrategy(manifest, routeModules, getRouter) {
5660 return async ({ request, matches, fetcherKey }) => {
5661 if (request.method !== "GET") {
5662 return singleFetchActionStrategy(request, matches);
5663 }
5664 if (fetcherKey) {
5665 return singleFetchLoaderFetcherStrategy(request, matches);
5666 }
5667 return singleFetchLoaderNavigationStrategy(
5668 manifest,
5669 routeModules,
5670 getRouter(),
5671 request,
5672 matches
5673 );
5674 };
5675}
5676async function singleFetchActionStrategy(request, matches) {
5677 let actionMatch = matches.find((m) => m.shouldLoad);
5678 invariant2(actionMatch, "No action match found");
5679 let actionStatus = void 0;
5680 let result = await actionMatch.resolve(async (handler) => {
5681 let result2 = await handler(async () => {
5682 let url = singleFetchUrl(request.url);
5683 let init = await createRequestInit(request);
5684 let { data: data2, status } = await fetchAndDecode(url, init);
5685 actionStatus = status;
5686 return unwrapSingleFetchResult(
5687 data2,
5688 actionMatch.route.id
5689 );
5690 });
5691 return result2;
5692 });
5693 if (isResponse(result.result) || isRouteErrorResponse(result.result)) {
5694 return { [actionMatch.route.id]: result };
5695 }
5696 return {
5697 [actionMatch.route.id]: {
5698 type: result.type,
5699 result: data(result.result, actionStatus)
5700 }
5701 };
5702}
5703async function singleFetchLoaderNavigationStrategy(manifest, routeModules, router, request, matches) {
5704 let routesParams = /* @__PURE__ */ new Set();
5705 let foundOptOutRoute = false;
5706 let routeDfds = matches.map(() => createDeferred2());
5707 let routesLoadedPromise = Promise.all(routeDfds.map((d) => d.promise));
5708 let singleFetchDfd = createDeferred2();
5709 let url = stripIndexParam(singleFetchUrl(request.url));
5710 let init = await createRequestInit(request);
5711 let results = {};
5712 let resolvePromise = Promise.all(
5713 matches.map(
5714 async (m, i) => m.resolve(async (handler) => {
5715 routeDfds[i].resolve();
5716 let manifestRoute = manifest.routes[m.route.id];
5717 if (!m.shouldLoad) {
5718 if (!router.state.initialized) {
5719 return;
5720 }
5721 if (m.route.id in router.state.loaderData && manifestRoute && manifestRoute.hasLoader && routeModules[m.route.id]?.shouldRevalidate) {
5722 foundOptOutRoute = true;
5723 return;
5724 }
5725 }
5726 if (manifestRoute && manifestRoute.hasClientLoader) {
5727 if (manifestRoute.hasLoader) {
5728 foundOptOutRoute = true;
5729 }
5730 try {
5731 let result = await fetchSingleLoader(
5732 handler,
5733 url,
5734 init,
5735 m.route.id
5736 );
5737 results[m.route.id] = { type: "data", result };
5738 } catch (e) {
5739 results[m.route.id] = { type: "error", result: e };
5740 }
5741 return;
5742 }
5743 if (manifestRoute && manifestRoute.hasLoader) {
5744 routesParams.add(m.route.id);
5745 }
5746 try {
5747 let result = await handler(async () => {
5748 let data2 = await singleFetchDfd.promise;
5749 return unwrapSingleFetchResults(data2, m.route.id);
5750 });
5751 results[m.route.id] = {
5752 type: "data",
5753 result
5754 };
5755 } catch (e) {
5756 results[m.route.id] = {
5757 type: "error",
5758 result: e
5759 };
5760 }
5761 })
5762 )
5763 );
5764 await routesLoadedPromise;
5765 if ((!router.state.initialized || routesParams.size === 0) && !window.__reactRouterHdrActive) {
5766 singleFetchDfd.resolve({});
5767 } else {
5768 try {
5769 if (foundOptOutRoute && routesParams.size > 0) {
5770 url.searchParams.set(
5771 "_routes",
5772 matches.filter((m) => routesParams.has(m.route.id)).map((m) => m.route.id).join(",")
5773 );
5774 }
5775 let data2 = await fetchAndDecode(url, init);
5776 singleFetchDfd.resolve(data2.data);
5777 } catch (e) {
5778 singleFetchDfd.reject(e);
5779 }
5780 }
5781 await resolvePromise;
5782 return results;
5783}
5784async function singleFetchLoaderFetcherStrategy(request, matches) {
5785 let fetcherMatch = matches.find((m) => m.shouldLoad);
5786 invariant2(fetcherMatch, "No fetcher match found");
5787 let result = await fetcherMatch.resolve(async (handler) => {
5788 let url = stripIndexParam(singleFetchUrl(request.url));
5789 let init = await createRequestInit(request);
5790 return fetchSingleLoader(handler, url, init, fetcherMatch.route.id);
5791 });
5792 return { [fetcherMatch.route.id]: result };
5793}
5794function fetchSingleLoader(handler, url, init, routeId) {
5795 return handler(async () => {
5796 let singleLoaderUrl = new URL(url);
5797 singleLoaderUrl.searchParams.set("_routes", routeId);
5798 let { data: data2 } = await fetchAndDecode(singleLoaderUrl, init);
5799 return unwrapSingleFetchResults(data2, routeId);
5800 });
5801}
5802function stripIndexParam(url) {
5803 let indexValues = url.searchParams.getAll("index");
5804 url.searchParams.delete("index");
5805 let indexValuesToKeep = [];
5806 for (let indexValue of indexValues) {
5807 if (indexValue) {
5808 indexValuesToKeep.push(indexValue);
5809 }
5810 }
5811 for (let toKeep of indexValuesToKeep) {
5812 url.searchParams.append("index", toKeep);
5813 }
5814 return url;
5815}
5816function singleFetchUrl(reqUrl) {
5817 let url = typeof reqUrl === "string" ? new URL(
5818 reqUrl,
5819 // This can be called during the SSR flow via PrefetchPageLinksImpl so
5820 // don't assume window is available
5821 typeof window === "undefined" ? "server://singlefetch/" : window.location.origin
5822 ) : reqUrl;
5823 if (url.pathname === "/") {
5824 url.pathname = "_root.data";
5825 } else {
5826 url.pathname = `${url.pathname.replace(/\/$/, "")}.data`;
5827 }
5828 return url;
5829}
5830async function fetchAndDecode(url, init) {
5831 let res = await fetch(url, init);
5832 if (res.status === 404 && !res.headers.has("X-Remix-Response")) {
5833 throw new ErrorResponseImpl(404, "Not Found", true);
5834 }
5835 const NO_BODY_STATUS_CODES2 = /* @__PURE__ */ new Set([100, 101, 204, 205]);
5836 if (NO_BODY_STATUS_CODES2.has(res.status)) {
5837 if (!init.method || init.method === "GET") {
5838 return { status: res.status, data: {} };
5839 } else {
5840 return { status: res.status, data: { data: void 0 } };
5841 }
5842 }
5843 invariant2(res.body, "No response body to decode");
5844 try {
5845 let decoded = await decodeViaTurboStream(res.body, window);
5846 return { status: res.status, data: decoded.value };
5847 } catch (e) {
5848 throw new Error("Unable to decode turbo-stream response");
5849 }
5850}
5851function decodeViaTurboStream(body, global2) {
5852 return decode(body, {
5853 plugins: [
5854 (type, ...rest) => {
5855 if (type === "SanitizedError") {
5856 let [name, message, stack] = rest;
5857 let Constructor = Error;
5858 if (name && name in global2 && typeof global2[name] === "function") {
5859 Constructor = global2[name];
5860 }
5861 let error = new Constructor(message);
5862 error.stack = stack;
5863 return { value: error };
5864 }
5865 if (type === "ErrorResponse") {
5866 let [data2, status, statusText] = rest;
5867 return {
5868 value: new ErrorResponseImpl(status, statusText, data2)
5869 };
5870 }
5871 if (type === "SingleFetchRedirect") {
5872 return { value: { [SingleFetchRedirectSymbol]: rest[0] } };
5873 }
5874 if (type === "SingleFetchClassInstance") {
5875 return { value: rest[0] };
5876 }
5877 if (type === "SingleFetchFallback") {
5878 return { value: void 0 };
5879 }
5880 }
5881 ]
5882 });
5883}
5884function unwrapSingleFetchResults(results, routeId) {
5885 let redirect2 = results[SingleFetchRedirectSymbol];
5886 if (redirect2) {
5887 return unwrapSingleFetchResult(redirect2, routeId);
5888 }
5889 return results[routeId] !== void 0 ? unwrapSingleFetchResult(results[routeId], routeId) : null;
5890}
5891function unwrapSingleFetchResult(result, routeId) {
5892 if ("error" in result) {
5893 throw result.error;
5894 } else if ("redirect" in result) {
5895 let headers = {};
5896 if (result.revalidate) {
5897 headers["X-Remix-Revalidate"] = "yes";
5898 }
5899 if (result.reload) {
5900 headers["X-Remix-Reload-Document"] = "yes";
5901 }
5902 if (result.replace) {
5903 headers["X-Remix-Replace"] = "yes";
5904 }
5905 throw redirect(result.redirect, { status: result.status, headers });
5906 } else if ("data" in result) {
5907 return result.data;
5908 } else {
5909 throw new Error(`No response found for routeId "${routeId}"`);
5910 }
5911}
5912function createDeferred2() {
5913 let resolve;
5914 let reject;
5915 let promise = new Promise((res, rej) => {
5916 resolve = async (val) => {
5917 res(val);
5918 try {
5919 await promise;
5920 } catch (e) {
5921 }
5922 };
5923 reject = async (error) => {
5924 rej(error);
5925 try {
5926 await promise;
5927 } catch (e) {
5928 }
5929 };
5930 });
5931 return {
5932 promise,
5933 //@ts-ignore
5934 resolve,
5935 //@ts-ignore
5936 reject
5937 };
5938}
5939
5940// lib/dom/ssr/fog-of-war.ts
5941import * as React8 from "react";
5942
5943// lib/dom/ssr/routes.tsx
5944import * as React7 from "react";
5945
5946// lib/dom/ssr/errorBoundaries.tsx
5947import * as React5 from "react";
5948var RemixErrorBoundary = class extends React5.Component {
5949 constructor(props) {
5950 super(props);
5951 this.state = { error: props.error || null, location: props.location };
5952 }
5953 static getDerivedStateFromError(error) {
5954 return { error };
5955 }
5956 static getDerivedStateFromProps(props, state) {
5957 if (state.location !== props.location) {
5958 return { error: props.error || null, location: props.location };
5959 }
5960 return { error: props.error || state.error, location: state.location };
5961 }
5962 render() {
5963 if (this.state.error) {
5964 return /* @__PURE__ */ React5.createElement(
5965 RemixRootDefaultErrorBoundary,
5966 {
5967 error: this.state.error,
5968 isOutsideRemixApp: true
5969 }
5970 );
5971 } else {
5972 return this.props.children;
5973 }
5974 }
5975};
5976function RemixRootDefaultErrorBoundary({
5977 error,
5978 isOutsideRemixApp
5979}) {
5980 console.error(error);
5981 let heyDeveloper = /* @__PURE__ */ React5.createElement(
5982 "script",
5983 {
5984 dangerouslySetInnerHTML: {
5985 __html: `
5986 console.log(
5987 "\u{1F4BF} Hey developer \u{1F44B}. You can provide a way better UX than this when your app throws errors. Check out https://remix.run/guides/errors for more information."
5988 );
5989 `
5990 }
5991 }
5992 );
5993 if (isRouteErrorResponse(error)) {
5994 return /* @__PURE__ */ React5.createElement(BoundaryShell, { title: "Unhandled Thrown Response!" }, /* @__PURE__ */ React5.createElement("h1", { style: { fontSize: "24px" } }, error.status, " ", error.statusText), heyDeveloper);
5995 }
5996 let errorInstance;
5997 if (error instanceof Error) {
5998 errorInstance = error;
5999 } else {
6000 let errorString = error == null ? "Unknown Error" : typeof error === "object" && "toString" in error ? error.toString() : JSON.stringify(error);
6001 errorInstance = new Error(errorString);
6002 }
6003 return /* @__PURE__ */ React5.createElement(
6004 BoundaryShell,
6005 {
6006 title: "Application Error!",
6007 isOutsideRemixApp
6008 },
6009 /* @__PURE__ */ React5.createElement("h1", { style: { fontSize: "24px" } }, "Application Error"),
6010 /* @__PURE__ */ React5.createElement(
6011 "pre",
6012 {
6013 style: {
6014 padding: "2rem",
6015 background: "hsla(10, 50%, 50%, 0.1)",
6016 color: "red",
6017 overflow: "auto"
6018 }
6019 },
6020 errorInstance.stack
6021 ),
6022 heyDeveloper
6023 );
6024}
6025function BoundaryShell({
6026 title,
6027 renderScripts,
6028 isOutsideRemixApp,
6029 children
6030}) {
6031 let { routeModules } = useFrameworkContext();
6032 if (routeModules.root?.Layout && !isOutsideRemixApp) {
6033 return children;
6034 }
6035 return /* @__PURE__ */ React5.createElement("html", { lang: "en" }, /* @__PURE__ */ React5.createElement("head", null, /* @__PURE__ */ React5.createElement("meta", { charSet: "utf-8" }), /* @__PURE__ */ React5.createElement(
6036 "meta",
6037 {
6038 name: "viewport",
6039 content: "width=device-width,initial-scale=1,viewport-fit=cover"
6040 }
6041 ), /* @__PURE__ */ React5.createElement("title", null, title)), /* @__PURE__ */ React5.createElement("body", null, /* @__PURE__ */ React5.createElement("main", { style: { fontFamily: "system-ui, sans-serif", padding: "2rem" } }, children, renderScripts ? /* @__PURE__ */ React5.createElement(Scripts, null) : null)));
6042}
6043
6044// lib/dom/ssr/fallback.tsx
6045import * as React6 from "react";
6046function RemixRootDefaultHydrateFallback() {
6047 return /* @__PURE__ */ React6.createElement(BoundaryShell, { title: "Loading...", renderScripts: true }, /* @__PURE__ */ React6.createElement(
6048 "script",
6049 {
6050 dangerouslySetInnerHTML: {
6051 __html: `
6052 console.log(
6053 "\u{1F4BF} Hey developer \u{1F44B}. You can provide a way better UX than this " +
6054 "when your app is loading JS modules and/or running \`clientLoader\` " +
6055 "functions. Check out https://remix.run/route/hydrate-fallback " +
6056 "for more information."
6057 );
6058 `
6059 }
6060 }
6061 ));
6062}
6063
6064// lib/dom/ssr/routes.tsx
6065function groupRoutesByParentId(manifest) {
6066 let routes = {};
6067 Object.values(manifest).forEach((route) => {
6068 if (route) {
6069 let parentId = route.parentId || "";
6070 if (!routes[parentId]) {
6071 routes[parentId] = [];
6072 }
6073 routes[parentId].push(route);
6074 }
6075 });
6076 return routes;
6077}
6078function getRouteComponents(route, routeModule, isSpaMode) {
6079 let Component4 = getRouteModuleComponent(routeModule);
6080 let HydrateFallback = routeModule.HydrateFallback && (!isSpaMode || route.id === "root") ? routeModule.HydrateFallback : route.id === "root" ? RemixRootDefaultHydrateFallback : void 0;
6081 let ErrorBoundary = routeModule.ErrorBoundary ? routeModule.ErrorBoundary : route.id === "root" ? () => /* @__PURE__ */ React7.createElement(RemixRootDefaultErrorBoundary, { error: useRouteError() }) : void 0;
6082 if (route.id === "root" && routeModule.Layout) {
6083 return {
6084 ...Component4 ? {
6085 element: /* @__PURE__ */ React7.createElement(routeModule.Layout, null, /* @__PURE__ */ React7.createElement(Component4, null))
6086 } : { Component: Component4 },
6087 ...ErrorBoundary ? {
6088 errorElement: /* @__PURE__ */ React7.createElement(routeModule.Layout, null, /* @__PURE__ */ React7.createElement(ErrorBoundary, null))
6089 } : { ErrorBoundary },
6090 ...HydrateFallback ? {
6091 hydrateFallbackElement: /* @__PURE__ */ React7.createElement(routeModule.Layout, null, /* @__PURE__ */ React7.createElement(HydrateFallback, null))
6092 } : { HydrateFallback }
6093 };
6094 }
6095 return { Component: Component4, ErrorBoundary, HydrateFallback };
6096}
6097function createServerRoutes(manifest, routeModules, future, isSpaMode, parentId = "", routesByParentId = groupRoutesByParentId(manifest), spaModeLazyPromise = Promise.resolve({ Component: () => null })) {
6098 return (routesByParentId[parentId] || []).map((route) => {
6099 let routeModule = routeModules[route.id];
6100 invariant2(
6101 routeModule,
6102 "No `routeModule` available to create server routes"
6103 );
6104 let dataRoute = {
6105 ...getRouteComponents(route, routeModule, isSpaMode),
6106 caseSensitive: route.caseSensitive,
6107 id: route.id,
6108 index: route.index,
6109 path: route.path,
6110 handle: routeModule.handle,
6111 // For SPA Mode, all routes are lazy except root. However we tell the
6112 // router root is also lazy here too since we don't need a full
6113 // implementation - we just need a `lazy` prop to tell the RR rendering
6114 // where to stop which is always at the root route in SPA mode
6115 lazy: isSpaMode ? () => spaModeLazyPromise : void 0,
6116 // For partial hydration rendering, we need to indicate when the route
6117 // has a loader/clientLoader, but it won't ever be called during the static
6118 // render, so just give it a no-op function so we can render down to the
6119 // proper fallback
6120 loader: route.hasLoader || route.hasClientLoader ? () => null : void 0
6121 // We don't need action/shouldRevalidate on these routes since they're
6122 // for a static render
6123 };
6124 let children = createServerRoutes(
6125 manifest,
6126 routeModules,
6127 future,
6128 isSpaMode,
6129 route.id,
6130 routesByParentId,
6131 spaModeLazyPromise
6132 );
6133 if (children.length > 0) dataRoute.children = children;
6134 return dataRoute;
6135 });
6136}
6137function createClientRoutesWithHMRRevalidationOptOut(needsRevalidation, manifest, routeModulesCache, initialState, future, isSpaMode) {
6138 return createClientRoutes(
6139 manifest,
6140 routeModulesCache,
6141 initialState,
6142 isSpaMode,
6143 "",
6144 groupRoutesByParentId(manifest),
6145 needsRevalidation
6146 );
6147}
6148function preventInvalidServerHandlerCall(type, route, isSpaMode) {
6149 if (isSpaMode) {
6150 let fn2 = type === "action" ? "serverAction()" : "serverLoader()";
6151 let msg2 = `You cannot call ${fn2} in SPA Mode (routeId: "${route.id}")`;
6152 console.error(msg2);
6153 throw new ErrorResponseImpl(400, "Bad Request", new Error(msg2), true);
6154 }
6155 let fn = type === "action" ? "serverAction()" : "serverLoader()";
6156 let msg = `You are trying to call ${fn} on a route that does not have a server ${type} (routeId: "${route.id}")`;
6157 if (type === "loader" && !route.hasLoader || type === "action" && !route.hasAction) {
6158 console.error(msg);
6159 throw new ErrorResponseImpl(400, "Bad Request", new Error(msg), true);
6160 }
6161}
6162function noActionDefinedError(type, routeId) {
6163 let article = type === "clientAction" ? "a" : "an";
6164 let msg = `Route "${routeId}" does not have ${article} ${type}, but you are trying to submit to it. To fix this, please add ${article} \`${type}\` function to the route`;
6165 console.error(msg);
6166 throw new ErrorResponseImpl(405, "Method Not Allowed", new Error(msg), true);
6167}
6168function createClientRoutes(manifest, routeModulesCache, initialState, isSpaMode, parentId = "", routesByParentId = groupRoutesByParentId(manifest), needsRevalidation) {
6169 return (routesByParentId[parentId] || []).map((route) => {
6170 let routeModule = routeModulesCache[route.id];
6171 function fetchServerHandler(singleFetch) {
6172 invariant2(
6173 typeof singleFetch === "function",
6174 "No single fetch function available for route handler"
6175 );
6176 return singleFetch();
6177 }
6178 function fetchServerLoader(singleFetch) {
6179 if (!route.hasLoader) return Promise.resolve(null);
6180 return fetchServerHandler(singleFetch);
6181 }
6182 function fetchServerAction(singleFetch) {
6183 if (!route.hasAction) {
6184 throw noActionDefinedError("action", route.id);
6185 }
6186 return fetchServerHandler(singleFetch);
6187 }
6188 async function prefetchStylesAndCallHandler(handler) {
6189 let cachedModule = routeModulesCache[route.id];
6190 let linkPrefetchPromise = cachedModule ? prefetchStyleLinks(route, cachedModule) : Promise.resolve();
6191 try {
6192 return handler();
6193 } finally {
6194 await linkPrefetchPromise;
6195 }
6196 }
6197 let dataRoute = {
6198 id: route.id,
6199 index: route.index,
6200 path: route.path
6201 };
6202 if (routeModule) {
6203 Object.assign(dataRoute, {
6204 ...dataRoute,
6205 ...getRouteComponents(route, routeModule, isSpaMode),
6206 handle: routeModule.handle,
6207 shouldRevalidate: getShouldRevalidateFunction(
6208 routeModule,
6209 route.id,
6210 needsRevalidation
6211 )
6212 });
6213 let hasInitialData = initialState && initialState.loaderData && route.id in initialState.loaderData;
6214 let initialData = hasInitialData ? initialState?.loaderData?.[route.id] : void 0;
6215 let hasInitialError = initialState && initialState.errors && route.id in initialState.errors;
6216 let initialError = hasInitialError ? initialState?.errors?.[route.id] : void 0;
6217 let isHydrationRequest = needsRevalidation == null && (routeModule.clientLoader?.hydrate === true || !route.hasLoader);
6218 dataRoute.loader = async ({ request, params }, singleFetch) => {
6219 try {
6220 let result = await prefetchStylesAndCallHandler(async () => {
6221 invariant2(
6222 routeModule,
6223 "No `routeModule` available for critical-route loader"
6224 );
6225 if (!routeModule.clientLoader) {
6226 if (isSpaMode) return null;
6227 return fetchServerLoader(singleFetch);
6228 }
6229 return routeModule.clientLoader({
6230 request,
6231 params,
6232 async serverLoader() {
6233 preventInvalidServerHandlerCall("loader", route, isSpaMode);
6234 if (isHydrationRequest) {
6235 if (hasInitialData) {
6236 return initialData;
6237 }
6238 if (hasInitialError) {
6239 throw initialError;
6240 }
6241 }
6242 return fetchServerLoader(singleFetch);
6243 }
6244 });
6245 });
6246 return result;
6247 } finally {
6248 isHydrationRequest = false;
6249 }
6250 };
6251 dataRoute.loader.hydrate = shouldHydrateRouteLoader(
6252 route,
6253 routeModule,
6254 isSpaMode
6255 );
6256 dataRoute.action = ({ request, params }, singleFetch) => {
6257 return prefetchStylesAndCallHandler(async () => {
6258 invariant2(
6259 routeModule,
6260 "No `routeModule` available for critical-route action"
6261 );
6262 if (!routeModule.clientAction) {
6263 if (isSpaMode) {
6264 throw noActionDefinedError("clientAction", route.id);
6265 }
6266 return fetchServerAction(singleFetch);
6267 }
6268 return routeModule.clientAction({
6269 request,
6270 params,
6271 async serverAction() {
6272 preventInvalidServerHandlerCall("action", route, isSpaMode);
6273 return fetchServerAction(singleFetch);
6274 }
6275 });
6276 });
6277 };
6278 } else {
6279 if (!route.hasClientLoader) {
6280 dataRoute.loader = ({ request }, singleFetch) => prefetchStylesAndCallHandler(() => {
6281 if (isSpaMode) return Promise.resolve(null);
6282 return fetchServerLoader(singleFetch);
6283 });
6284 }
6285 if (!route.hasClientAction) {
6286 dataRoute.action = ({ request }, singleFetch) => prefetchStylesAndCallHandler(() => {
6287 if (isSpaMode) {
6288 throw noActionDefinedError("clientAction", route.id);
6289 }
6290 return fetchServerAction(singleFetch);
6291 });
6292 }
6293 dataRoute.lazy = async () => {
6294 let mod = await loadRouteModuleWithBlockingLinks(
6295 route,
6296 routeModulesCache
6297 );
6298 let lazyRoute = { ...mod };
6299 if (mod.clientLoader) {
6300 let clientLoader = mod.clientLoader;
6301 lazyRoute.loader = (args, singleFetch) => clientLoader({
6302 ...args,
6303 async serverLoader() {
6304 preventInvalidServerHandlerCall("loader", route, isSpaMode);
6305 return fetchServerLoader(singleFetch);
6306 }
6307 });
6308 }
6309 if (mod.clientAction) {
6310 let clientAction = mod.clientAction;
6311 lazyRoute.action = (args, singleFetch) => clientAction({
6312 ...args,
6313 async serverAction() {
6314 preventInvalidServerHandlerCall("action", route, isSpaMode);
6315 return fetchServerAction(singleFetch);
6316 }
6317 });
6318 }
6319 return {
6320 ...lazyRoute.loader ? { loader: lazyRoute.loader } : {},
6321 ...lazyRoute.action ? { action: lazyRoute.action } : {},
6322 hasErrorBoundary: lazyRoute.hasErrorBoundary,
6323 shouldRevalidate: getShouldRevalidateFunction(
6324 lazyRoute,
6325 route.id,
6326 needsRevalidation
6327 ),
6328 handle: lazyRoute.handle,
6329 // No need to wrap these in layout since the root route is never
6330 // loaded via route.lazy()
6331 Component: lazyRoute.Component,
6332 ErrorBoundary: lazyRoute.ErrorBoundary
6333 };
6334 };
6335 }
6336 let children = createClientRoutes(
6337 manifest,
6338 routeModulesCache,
6339 initialState,
6340 isSpaMode,
6341 route.id,
6342 routesByParentId,
6343 needsRevalidation
6344 );
6345 if (children.length > 0) dataRoute.children = children;
6346 return dataRoute;
6347 });
6348}
6349function getShouldRevalidateFunction(route, routeId, needsRevalidation) {
6350 if (needsRevalidation) {
6351 return wrapShouldRevalidateForHdr(
6352 routeId,
6353 route.shouldRevalidate,
6354 needsRevalidation
6355 );
6356 }
6357 if (route.shouldRevalidate) {
6358 let fn = route.shouldRevalidate;
6359 return (opts) => fn({ ...opts, defaultShouldRevalidate: true });
6360 }
6361 return route.shouldRevalidate;
6362}
6363function wrapShouldRevalidateForHdr(routeId, routeShouldRevalidate, needsRevalidation) {
6364 let handledRevalidation = false;
6365 return (arg) => {
6366 if (!handledRevalidation) {
6367 handledRevalidation = true;
6368 return needsRevalidation.has(routeId);
6369 }
6370 return routeShouldRevalidate ? routeShouldRevalidate(arg) : arg.defaultShouldRevalidate;
6371 };
6372}
6373async function loadRouteModuleWithBlockingLinks(route, routeModules) {
6374 let routeModule = await loadRouteModule(route, routeModules);
6375 await prefetchStyleLinks(route, routeModule);
6376 return {
6377 Component: getRouteModuleComponent(routeModule),
6378 ErrorBoundary: routeModule.ErrorBoundary,
6379 clientAction: routeModule.clientAction,
6380 clientLoader: routeModule.clientLoader,
6381 handle: routeModule.handle,
6382 links: routeModule.links,
6383 meta: routeModule.meta,
6384 shouldRevalidate: routeModule.shouldRevalidate
6385 };
6386}
6387function getRouteModuleComponent(routeModule) {
6388 if (routeModule.default == null) return void 0;
6389 let isEmptyObject = typeof routeModule.default === "object" && Object.keys(routeModule.default).length === 0;
6390 if (!isEmptyObject) {
6391 return routeModule.default;
6392 }
6393}
6394function shouldHydrateRouteLoader(route, routeModule, isSpaMode) {
6395 return isSpaMode && route.id !== "root" || routeModule.clientLoader != null && (routeModule.clientLoader.hydrate === true || route.hasLoader !== true);
6396}
6397
6398// lib/dom/ssr/fog-of-war.ts
6399var nextPaths = /* @__PURE__ */ new Set();
6400var discoveredPathsMaxSize = 1e3;
6401var discoveredPaths = /* @__PURE__ */ new Set();
6402var URL_LIMIT = 7680;
6403function isFogOfWarEnabled(isSpaMode) {
6404 return !isSpaMode;
6405}
6406function getPartialManifest(manifest, router) {
6407 let routeIds = new Set(router.state.matches.map((m) => m.route.id));
6408 let segments = router.state.location.pathname.split("/").filter(Boolean);
6409 let paths = ["/"];
6410 segments.pop();
6411 while (segments.length > 0) {
6412 paths.push(`/${segments.join("/")}`);
6413 segments.pop();
6414 }
6415 paths.forEach((path) => {
6416 let matches = matchRoutes(router.routes, path, router.basename);
6417 if (matches) {
6418 matches.forEach((m) => routeIds.add(m.route.id));
6419 }
6420 });
6421 let initialRoutes = [...routeIds].reduce(
6422 (acc, id) => Object.assign(acc, { [id]: manifest.routes[id] }),
6423 {}
6424 );
6425 return {
6426 ...manifest,
6427 routes: initialRoutes
6428 };
6429}
6430function getPatchRoutesOnNavigationFunction(manifest, routeModules, isSpaMode, basename) {
6431 if (!isFogOfWarEnabled(isSpaMode)) {
6432 return void 0;
6433 }
6434 return async ({ path, patch }) => {
6435 if (discoveredPaths.has(path)) {
6436 return;
6437 }
6438 await fetchAndApplyManifestPatches(
6439 [path],
6440 manifest,
6441 routeModules,
6442 isSpaMode,
6443 basename,
6444 patch
6445 );
6446 };
6447}
6448function useFogOFWarDiscovery(router, manifest, routeModules, isSpaMode) {
6449 React8.useEffect(() => {
6450 if (!isFogOfWarEnabled(isSpaMode) || navigator.connection?.saveData === true) {
6451 return;
6452 }
6453 function registerElement(el) {
6454 let path = el.tagName === "FORM" ? el.getAttribute("action") : el.getAttribute("href");
6455 if (!path) {
6456 return;
6457 }
6458 let pathname = el.tagName === "A" ? el.pathname : new URL(path, window.location.origin).pathname;
6459 if (!discoveredPaths.has(pathname)) {
6460 nextPaths.add(pathname);
6461 }
6462 }
6463 async function fetchPatches() {
6464 document.querySelectorAll("a[data-discover], form[data-discover]").forEach(registerElement);
6465 let lazyPaths = Array.from(nextPaths.keys()).filter((path) => {
6466 if (discoveredPaths.has(path)) {
6467 nextPaths.delete(path);
6468 return false;
6469 }
6470 return true;
6471 });
6472 if (lazyPaths.length === 0) {
6473 return;
6474 }
6475 try {
6476 await fetchAndApplyManifestPatches(
6477 lazyPaths,
6478 manifest,
6479 routeModules,
6480 isSpaMode,
6481 router.basename,
6482 router.patchRoutes
6483 );
6484 } catch (e) {
6485 console.error("Failed to fetch manifest patches", e);
6486 }
6487 }
6488 let debouncedFetchPatches = debounce(fetchPatches, 100);
6489 fetchPatches();
6490 let observer = new MutationObserver(() => debouncedFetchPatches());
6491 observer.observe(document.documentElement, {
6492 subtree: true,
6493 childList: true,
6494 attributes: true,
6495 attributeFilter: ["data-discover", "href", "action"]
6496 });
6497 return () => observer.disconnect();
6498 }, [isSpaMode, manifest, routeModules, router]);
6499}
6500async function fetchAndApplyManifestPatches(paths, manifest, routeModules, isSpaMode, basename, patchRoutes) {
6501 let manifestPath = `${basename != null ? basename : "/"}/__manifest`.replace(
6502 /\/+/g,
6503 "/"
6504 );
6505 let url = new URL(manifestPath, window.location.origin);
6506 paths.sort().forEach((path) => url.searchParams.append("p", path));
6507 url.searchParams.set("version", manifest.version);
6508 if (url.toString().length > URL_LIMIT) {
6509 nextPaths.clear();
6510 return;
6511 }
6512 let res = await fetch(url);
6513 if (!res.ok) {
6514 throw new Error(`${res.status} ${res.statusText}`);
6515 } else if (res.status >= 400) {
6516 throw new Error(await res.text());
6517 }
6518 let serverPatches = await res.json();
6519 let knownRoutes = new Set(Object.keys(manifest.routes));
6520 let patches = Object.values(serverPatches).reduce((acc, route) => {
6521 if (route && !knownRoutes.has(route.id)) {
6522 acc[route.id] = route;
6523 }
6524 return acc;
6525 }, {});
6526 Object.assign(manifest.routes, patches);
6527 paths.forEach((p) => addToFifoQueue(p, discoveredPaths));
6528 let parentIds = /* @__PURE__ */ new Set();
6529 Object.values(patches).forEach((patch) => {
6530 if (patch && (!patch.parentId || !patches[patch.parentId])) {
6531 parentIds.add(patch.parentId);
6532 }
6533 });
6534 parentIds.forEach(
6535 (parentId) => patchRoutes(
6536 parentId || null,
6537 createClientRoutes(patches, routeModules, null, isSpaMode, parentId)
6538 )
6539 );
6540}
6541function addToFifoQueue(path, queue) {
6542 if (queue.size >= discoveredPathsMaxSize) {
6543 let first = queue.values().next().value;
6544 queue.delete(first);
6545 }
6546 queue.add(path);
6547}
6548function debounce(callback, wait) {
6549 let timeoutId;
6550 return (...args) => {
6551 window.clearTimeout(timeoutId);
6552 timeoutId = window.setTimeout(() => callback(...args), wait);
6553 };
6554}
6555
6556// lib/dom/ssr/components.tsx
6557function useDataRouterContext2() {
6558 let context = React9.useContext(DataRouterContext);
6559 invariant2(
6560 context,
6561 "You must render this element inside a <DataRouterContext.Provider> element"
6562 );
6563 return context;
6564}
6565function useDataRouterStateContext() {
6566 let context = React9.useContext(DataRouterStateContext);
6567 invariant2(
6568 context,
6569 "You must render this element inside a <DataRouterStateContext.Provider> element"
6570 );
6571 return context;
6572}
6573var FrameworkContext = React9.createContext(void 0);
6574FrameworkContext.displayName = "FrameworkContext";
6575function useFrameworkContext() {
6576 let context = React9.useContext(FrameworkContext);
6577 invariant2(
6578 context,
6579 "You must render this element inside a <HydratedRouter> element"
6580 );
6581 return context;
6582}
6583function usePrefetchBehavior(prefetch, theirElementProps) {
6584 let frameworkContext = React9.useContext(FrameworkContext);
6585 let [maybePrefetch, setMaybePrefetch] = React9.useState(false);
6586 let [shouldPrefetch, setShouldPrefetch] = React9.useState(false);
6587 let { onFocus, onBlur, onMouseEnter, onMouseLeave, onTouchStart } = theirElementProps;
6588 let ref = React9.useRef(null);
6589 React9.useEffect(() => {
6590 if (prefetch === "render") {
6591 setShouldPrefetch(true);
6592 }
6593 if (prefetch === "viewport") {
6594 let callback = (entries) => {
6595 entries.forEach((entry) => {
6596 setShouldPrefetch(entry.isIntersecting);
6597 });
6598 };
6599 let observer = new IntersectionObserver(callback, { threshold: 0.5 });
6600 if (ref.current) observer.observe(ref.current);
6601 return () => {
6602 observer.disconnect();
6603 };
6604 }
6605 }, [prefetch]);
6606 React9.useEffect(() => {
6607 if (maybePrefetch) {
6608 let id = setTimeout(() => {
6609 setShouldPrefetch(true);
6610 }, 100);
6611 return () => {
6612 clearTimeout(id);
6613 };
6614 }
6615 }, [maybePrefetch]);
6616 let setIntent = () => {
6617 setMaybePrefetch(true);
6618 };
6619 let cancelIntent = () => {
6620 setMaybePrefetch(false);
6621 setShouldPrefetch(false);
6622 };
6623 if (!frameworkContext) {
6624 return [false, ref, {}];
6625 }
6626 if (prefetch !== "intent") {
6627 return [shouldPrefetch, ref, {}];
6628 }
6629 return [
6630 shouldPrefetch,
6631 ref,
6632 {
6633 onFocus: composeEventHandlers(onFocus, setIntent),
6634 onBlur: composeEventHandlers(onBlur, cancelIntent),
6635 onMouseEnter: composeEventHandlers(onMouseEnter, setIntent),
6636 onMouseLeave: composeEventHandlers(onMouseLeave, cancelIntent),
6637 onTouchStart: composeEventHandlers(onTouchStart, setIntent)
6638 }
6639 ];
6640}
6641function composeEventHandlers(theirHandler, ourHandler) {
6642 return (event) => {
6643 theirHandler && theirHandler(event);
6644 if (!event.defaultPrevented) {
6645 ourHandler(event);
6646 }
6647 };
6648}
6649function getActiveMatches(matches, errors, isSpaMode) {
6650 if (isSpaMode && !isHydrated) {
6651 return [matches[0]];
6652 }
6653 if (errors) {
6654 let errorIdx = matches.findIndex((m) => errors[m.route.id] !== void 0);
6655 return matches.slice(0, errorIdx + 1);
6656 }
6657 return matches;
6658}
6659function Links() {
6660 let { isSpaMode, manifest, routeModules, criticalCss } = useFrameworkContext();
6661 let { errors, matches: routerMatches } = useDataRouterStateContext();
6662 let matches = getActiveMatches(routerMatches, errors, isSpaMode);
6663 let keyedLinks = React9.useMemo(
6664 () => getKeyedLinksForMatches(matches, routeModules, manifest),
6665 [matches, routeModules, manifest]
6666 );
6667 return /* @__PURE__ */ React9.createElement(React9.Fragment, null, criticalCss ? /* @__PURE__ */ React9.createElement("style", { dangerouslySetInnerHTML: { __html: criticalCss } }) : null, keyedLinks.map(
6668 ({ key, link }) => isPageLinkDescriptor(link) ? /* @__PURE__ */ React9.createElement(PrefetchPageLinks, { key, ...link }) : /* @__PURE__ */ React9.createElement("link", { key, ...link })
6669 ));
6670}
6671function PrefetchPageLinks({
6672 page,
6673 ...dataLinkProps
6674}) {
6675 let { router } = useDataRouterContext2();
6676 let matches = React9.useMemo(
6677 () => matchRoutes(router.routes, page, router.basename),
6678 [router.routes, page, router.basename]
6679 );
6680 if (!matches) {
6681 return null;
6682 }
6683 return /* @__PURE__ */ React9.createElement(PrefetchPageLinksImpl, { page, matches, ...dataLinkProps });
6684}
6685function useKeyedPrefetchLinks(matches) {
6686 let { manifest, routeModules } = useFrameworkContext();
6687 let [keyedPrefetchLinks, setKeyedPrefetchLinks] = React9.useState([]);
6688 React9.useEffect(() => {
6689 let interrupted = false;
6690 void getKeyedPrefetchLinks(matches, manifest, routeModules).then(
6691 (links) => {
6692 if (!interrupted) {
6693 setKeyedPrefetchLinks(links);
6694 }
6695 }
6696 );
6697 return () => {
6698 interrupted = true;
6699 };
6700 }, [matches, manifest, routeModules]);
6701 return keyedPrefetchLinks;
6702}
6703function PrefetchPageLinksImpl({
6704 page,
6705 matches: nextMatches,
6706 ...linkProps
6707}) {
6708 let location = useLocation();
6709 let { manifest, routeModules } = useFrameworkContext();
6710 let { loaderData, matches } = useDataRouterStateContext();
6711 let newMatchesForData = React9.useMemo(
6712 () => getNewMatchesForLinks(
6713 page,
6714 nextMatches,
6715 matches,
6716 manifest,
6717 location,
6718 "data"
6719 ),
6720 [page, nextMatches, matches, manifest, location]
6721 );
6722 let newMatchesForAssets = React9.useMemo(
6723 () => getNewMatchesForLinks(
6724 page,
6725 nextMatches,
6726 matches,
6727 manifest,
6728 location,
6729 "assets"
6730 ),
6731 [page, nextMatches, matches, manifest, location]
6732 );
6733 let dataHrefs = React9.useMemo(() => {
6734 if (page === location.pathname + location.search + location.hash) {
6735 return [];
6736 }
6737 let routesParams = /* @__PURE__ */ new Set();
6738 let foundOptOutRoute = false;
6739 nextMatches.forEach((m) => {
6740 let manifestRoute = manifest.routes[m.route.id];
6741 if (!manifestRoute || !manifestRoute.hasLoader) {
6742 return;
6743 }
6744 if (!newMatchesForData.some((m2) => m2.route.id === m.route.id) && m.route.id in loaderData && routeModules[m.route.id]?.shouldRevalidate) {
6745 foundOptOutRoute = true;
6746 } else if (manifestRoute.hasClientLoader) {
6747 foundOptOutRoute = true;
6748 } else {
6749 routesParams.add(m.route.id);
6750 }
6751 });
6752 if (routesParams.size === 0) {
6753 return [];
6754 }
6755 let url = singleFetchUrl(page);
6756 if (foundOptOutRoute && routesParams.size > 0) {
6757 url.searchParams.set(
6758 "_routes",
6759 nextMatches.filter((m) => routesParams.has(m.route.id)).map((m) => m.route.id).join(",")
6760 );
6761 }
6762 return [url.pathname + url.search];
6763 }, [
6764 loaderData,
6765 location,
6766 manifest,
6767 newMatchesForData,
6768 nextMatches,
6769 page,
6770 routeModules
6771 ]);
6772 let moduleHrefs = React9.useMemo(
6773 () => getModuleLinkHrefs(newMatchesForAssets, manifest),
6774 [newMatchesForAssets, manifest]
6775 );
6776 let keyedPrefetchLinks = useKeyedPrefetchLinks(newMatchesForAssets);
6777 return /* @__PURE__ */ React9.createElement(React9.Fragment, null, dataHrefs.map((href) => /* @__PURE__ */ React9.createElement("link", { key: href, rel: "prefetch", as: "fetch", href, ...linkProps })), moduleHrefs.map((href) => /* @__PURE__ */ React9.createElement("link", { key: href, rel: "modulepreload", href, ...linkProps })), keyedPrefetchLinks.map(({ key, link }) => (
6778 // these don't spread `linkProps` because they are full link descriptors
6779 // already with their own props
6780 /* @__PURE__ */ React9.createElement("link", { key, ...link })
6781 )));
6782}
6783function Meta() {
6784 let { isSpaMode, routeModules } = useFrameworkContext();
6785 let {
6786 errors,
6787 matches: routerMatches,
6788 loaderData
6789 } = useDataRouterStateContext();
6790 let location = useLocation();
6791 let _matches = getActiveMatches(routerMatches, errors, isSpaMode);
6792 let error = null;
6793 if (errors) {
6794 error = errors[_matches[_matches.length - 1].route.id];
6795 }
6796 let meta = [];
6797 let leafMeta = null;
6798 let matches = [];
6799 for (let i = 0; i < _matches.length; i++) {
6800 let _match = _matches[i];
6801 let routeId = _match.route.id;
6802 let data2 = loaderData[routeId];
6803 let params = _match.params;
6804 let routeModule = routeModules[routeId];
6805 let routeMeta = [];
6806 let match = {
6807 id: routeId,
6808 data: data2,
6809 meta: [],
6810 params: _match.params,
6811 pathname: _match.pathname,
6812 handle: _match.route.handle,
6813 error
6814 };
6815 matches[i] = match;
6816 if (routeModule?.meta) {
6817 routeMeta = typeof routeModule.meta === "function" ? routeModule.meta({
6818 data: data2,
6819 params,
6820 location,
6821 matches,
6822 error
6823 }) : Array.isArray(routeModule.meta) ? [...routeModule.meta] : routeModule.meta;
6824 } else if (leafMeta) {
6825 routeMeta = [...leafMeta];
6826 }
6827 routeMeta = routeMeta || [];
6828 if (!Array.isArray(routeMeta)) {
6829 throw new Error(
6830 "The route at " + _match.route.path + " returns an invalid value. All route meta functions must return an array of meta objects.\n\nTo reference the meta function API, see https://remix.run/route/meta"
6831 );
6832 }
6833 match.meta = routeMeta;
6834 matches[i] = match;
6835 meta = [...routeMeta];
6836 leafMeta = meta;
6837 }
6838 return /* @__PURE__ */ React9.createElement(React9.Fragment, null, meta.flat().map((metaProps) => {
6839 if (!metaProps) {
6840 return null;
6841 }
6842 if ("tagName" in metaProps) {
6843 let { tagName, ...rest } = metaProps;
6844 if (!isValidMetaTag(tagName)) {
6845 console.warn(
6846 `A meta object uses an invalid tagName: ${tagName}. Expected either 'link' or 'meta'`
6847 );
6848 return null;
6849 }
6850 let Comp = tagName;
6851 return /* @__PURE__ */ React9.createElement(Comp, { key: JSON.stringify(rest), ...rest });
6852 }
6853 if ("title" in metaProps) {
6854 return /* @__PURE__ */ React9.createElement("title", { key: "title" }, String(metaProps.title));
6855 }
6856 if ("charset" in metaProps) {
6857 metaProps.charSet ?? (metaProps.charSet = metaProps.charset);
6858 delete metaProps.charset;
6859 }
6860 if ("charSet" in metaProps && metaProps.charSet != null) {
6861 return typeof metaProps.charSet === "string" ? /* @__PURE__ */ React9.createElement("meta", { key: "charSet", charSet: metaProps.charSet }) : null;
6862 }
6863 if ("script:ld+json" in metaProps) {
6864 try {
6865 let json = JSON.stringify(metaProps["script:ld+json"]);
6866 return /* @__PURE__ */ React9.createElement(
6867 "script",
6868 {
6869 key: `script:ld+json:${json}`,
6870 type: "application/ld+json",
6871 dangerouslySetInnerHTML: { __html: json }
6872 }
6873 );
6874 } catch (err) {
6875 return null;
6876 }
6877 }
6878 return /* @__PURE__ */ React9.createElement("meta", { key: JSON.stringify(metaProps), ...metaProps });
6879 }));
6880}
6881function isValidMetaTag(tagName) {
6882 return typeof tagName === "string" && /^(meta|link)$/.test(tagName);
6883}
6884var isHydrated = false;
6885function Scripts(props) {
6886 let { manifest, serverHandoffString, isSpaMode, renderMeta } = useFrameworkContext();
6887 let { router, static: isStatic, staticContext } = useDataRouterContext2();
6888 let { matches: routerMatches } = useDataRouterStateContext();
6889 let enableFogOfWar = isFogOfWarEnabled(isSpaMode);
6890 if (renderMeta) {
6891 renderMeta.didRenderScripts = true;
6892 }
6893 let matches = getActiveMatches(routerMatches, null, isSpaMode);
6894 React9.useEffect(() => {
6895 isHydrated = true;
6896 }, []);
6897 let initialScripts = React9.useMemo(() => {
6898 let streamScript = "window.__reactRouterContext.stream = new ReadableStream({start(controller){window.__reactRouterContext.streamController = controller;}}).pipeThrough(new TextEncoderStream());";
6899 let contextScript = staticContext ? `window.__reactRouterContext = ${serverHandoffString};${streamScript}` : " ";
6900 let routeModulesScript = !isStatic ? " " : `${manifest.hmr?.runtime ? `import ${JSON.stringify(manifest.hmr.runtime)};` : ""}${!enableFogOfWar ? `import ${JSON.stringify(manifest.url)}` : ""};
6901${matches.map(
6902 (match, index) => `import * as route${index} from ${JSON.stringify(
6903 manifest.routes[match.route.id].module
6904 )};`
6905 ).join("\n")}
6906 ${enableFogOfWar ? (
6907 // Inline a minimal manifest with the SSR matches
6908 `window.__reactRouterManifest = ${JSON.stringify(
6909 getPartialManifest(manifest, router),
6910 null,
6911 2
6912 )};`
6913 ) : ""}
6914 window.__reactRouterRouteModules = {${matches.map((match, index) => `${JSON.stringify(match.route.id)}:route${index}`).join(",")}};
6915
6916import(${JSON.stringify(manifest.entry.module)});`;
6917 return /* @__PURE__ */ React9.createElement(React9.Fragment, null, /* @__PURE__ */ React9.createElement(
6918 "script",
6919 {
6920 ...props,
6921 suppressHydrationWarning: true,
6922 dangerouslySetInnerHTML: createHtml(contextScript),
6923 type: void 0
6924 }
6925 ), /* @__PURE__ */ React9.createElement(
6926 "script",
6927 {
6928 ...props,
6929 suppressHydrationWarning: true,
6930 dangerouslySetInnerHTML: createHtml(routeModulesScript),
6931 type: "module",
6932 async: true
6933 }
6934 ));
6935 }, []);
6936 let routePreloads = matches.map((match) => {
6937 let route = manifest.routes[match.route.id];
6938 return route ? (route.imports || []).concat([route.module]) : [];
6939 }).flat(1);
6940 let preloads = isHydrated ? [] : manifest.entry.imports.concat(routePreloads);
6941 return isHydrated ? null : /* @__PURE__ */ React9.createElement(React9.Fragment, null, !enableFogOfWar ? /* @__PURE__ */ React9.createElement(
6942 "link",
6943 {
6944 rel: "modulepreload",
6945 href: manifest.url,
6946 crossOrigin: props.crossOrigin
6947 }
6948 ) : null, /* @__PURE__ */ React9.createElement(
6949 "link",
6950 {
6951 rel: "modulepreload",
6952 href: manifest.entry.module,
6953 crossOrigin: props.crossOrigin
6954 }
6955 ), dedupe(preloads).map((path) => /* @__PURE__ */ React9.createElement(
6956 "link",
6957 {
6958 key: path,
6959 rel: "modulepreload",
6960 href: path,
6961 crossOrigin: props.crossOrigin
6962 }
6963 )), initialScripts);
6964}
6965function dedupe(array) {
6966 return [...new Set(array)];
6967}
6968function mergeRefs(...refs) {
6969 return (value) => {
6970 refs.forEach((ref) => {
6971 if (typeof ref === "function") {
6972 ref(value);
6973 } else if (ref != null) {
6974 ref.current = value;
6975 }
6976 });
6977 };
6978}
6979
6980// lib/dom/lib.tsx
6981var isBrowser = typeof window !== "undefined" && typeof window.document !== "undefined" && typeof window.document.createElement !== "undefined";
6982try {
6983 if (isBrowser) {
6984 window.__reactRouterVersion = "7.1.5";
6985 }
6986} catch (e) {
6987}
6988function createBrowserRouter(routes, opts) {
6989 return createRouter({
6990 basename: opts?.basename,
6991 future: opts?.future,
6992 history: createBrowserHistory({ window: opts?.window }),
6993 hydrationData: opts?.hydrationData || parseHydrationData(),
6994 routes,
6995 mapRouteProperties,
6996 dataStrategy: opts?.dataStrategy,
6997 patchRoutesOnNavigation: opts?.patchRoutesOnNavigation,
6998 window: opts?.window
6999 }).initialize();
7000}
7001function createHashRouter(routes, opts) {
7002 return createRouter({
7003 basename: opts?.basename,
7004 future: opts?.future,
7005 history: createHashHistory({ window: opts?.window }),
7006 hydrationData: opts?.hydrationData || parseHydrationData(),
7007 routes,
7008 mapRouteProperties,
7009 dataStrategy: opts?.dataStrategy,
7010 patchRoutesOnNavigation: opts?.patchRoutesOnNavigation,
7011 window: opts?.window
7012 }).initialize();
7013}
7014function parseHydrationData() {
7015 let state = window?.__staticRouterHydrationData;
7016 if (state && state.errors) {
7017 state = {
7018 ...state,
7019 errors: deserializeErrors(state.errors)
7020 };
7021 }
7022 return state;
7023}
7024function deserializeErrors(errors) {
7025 if (!errors) return null;
7026 let entries = Object.entries(errors);
7027 let serialized = {};
7028 for (let [key, val] of entries) {
7029 if (val && val.__type === "RouteErrorResponse") {
7030 serialized[key] = new ErrorResponseImpl(
7031 val.status,
7032 val.statusText,
7033 val.data,
7034 val.internal === true
7035 );
7036 } else if (val && val.__type === "Error") {
7037 if (val.__subType) {
7038 let ErrorConstructor = window[val.__subType];
7039 if (typeof ErrorConstructor === "function") {
7040 try {
7041 let error = new ErrorConstructor(val.message);
7042 error.stack = "";
7043 serialized[key] = error;
7044 } catch (e) {
7045 }
7046 }
7047 }
7048 if (serialized[key] == null) {
7049 let error = new Error(val.message);
7050 error.stack = "";
7051 serialized[key] = error;
7052 }
7053 } else {
7054 serialized[key] = val;
7055 }
7056 }
7057 return serialized;
7058}
7059function BrowserRouter({
7060 basename,
7061 children,
7062 window: window2
7063}) {
7064 let historyRef = React10.useRef();
7065 if (historyRef.current == null) {
7066 historyRef.current = createBrowserHistory({ window: window2, v5Compat: true });
7067 }
7068 let history = historyRef.current;
7069 let [state, setStateImpl] = React10.useState({
7070 action: history.action,
7071 location: history.location
7072 });
7073 let setState = React10.useCallback(
7074 (newState) => {
7075 React10.startTransition(() => setStateImpl(newState));
7076 },
7077 [setStateImpl]
7078 );
7079 React10.useLayoutEffect(() => history.listen(setState), [history, setState]);
7080 return /* @__PURE__ */ React10.createElement(
7081 Router,
7082 {
7083 basename,
7084 children,
7085 location: state.location,
7086 navigationType: state.action,
7087 navigator: history
7088 }
7089 );
7090}
7091function HashRouter({ basename, children, window: window2 }) {
7092 let historyRef = React10.useRef();
7093 if (historyRef.current == null) {
7094 historyRef.current = createHashHistory({ window: window2, v5Compat: true });
7095 }
7096 let history = historyRef.current;
7097 let [state, setStateImpl] = React10.useState({
7098 action: history.action,
7099 location: history.location
7100 });
7101 let setState = React10.useCallback(
7102 (newState) => {
7103 React10.startTransition(() => setStateImpl(newState));
7104 },
7105 [setStateImpl]
7106 );
7107 React10.useLayoutEffect(() => history.listen(setState), [history, setState]);
7108 return /* @__PURE__ */ React10.createElement(
7109 Router,
7110 {
7111 basename,
7112 children,
7113 location: state.location,
7114 navigationType: state.action,
7115 navigator: history
7116 }
7117 );
7118}
7119function HistoryRouter({
7120 basename,
7121 children,
7122 history
7123}) {
7124 let [state, setStateImpl] = React10.useState({
7125 action: history.action,
7126 location: history.location
7127 });
7128 let setState = React10.useCallback(
7129 (newState) => {
7130 React10.startTransition(() => setStateImpl(newState));
7131 },
7132 [setStateImpl]
7133 );
7134 React10.useLayoutEffect(() => history.listen(setState), [history, setState]);
7135 return /* @__PURE__ */ React10.createElement(
7136 Router,
7137 {
7138 basename,
7139 children,
7140 location: state.location,
7141 navigationType: state.action,
7142 navigator: history
7143 }
7144 );
7145}
7146HistoryRouter.displayName = "unstable_HistoryRouter";
7147var ABSOLUTE_URL_REGEX2 = /^(?:[a-z][a-z0-9+.-]*:|\/\/)/i;
7148var Link = React10.forwardRef(
7149 function LinkWithRef({
7150 onClick,
7151 discover = "render",
7152 prefetch = "none",
7153 relative,
7154 reloadDocument,
7155 replace: replace2,
7156 state,
7157 target,
7158 to,
7159 preventScrollReset,
7160 viewTransition,
7161 ...rest
7162 }, forwardedRef) {
7163 let { basename } = React10.useContext(NavigationContext);
7164 let isAbsolute = typeof to === "string" && ABSOLUTE_URL_REGEX2.test(to);
7165 let absoluteHref;
7166 let isExternal = false;
7167 if (typeof to === "string" && isAbsolute) {
7168 absoluteHref = to;
7169 if (isBrowser) {
7170 try {
7171 let currentUrl = new URL(window.location.href);
7172 let targetUrl = to.startsWith("//") ? new URL(currentUrl.protocol + to) : new URL(to);
7173 let path = stripBasename(targetUrl.pathname, basename);
7174 if (targetUrl.origin === currentUrl.origin && path != null) {
7175 to = path + targetUrl.search + targetUrl.hash;
7176 } else {
7177 isExternal = true;
7178 }
7179 } catch (e) {
7180 warning(
7181 false,
7182 `<Link to="${to}"> contains an invalid URL which will probably break when clicked - please update to a valid URL path.`
7183 );
7184 }
7185 }
7186 }
7187 let href = useHref(to, { relative });
7188 let [shouldPrefetch, prefetchRef, prefetchHandlers] = usePrefetchBehavior(
7189 prefetch,
7190 rest
7191 );
7192 let internalOnClick = useLinkClickHandler(to, {
7193 replace: replace2,
7194 state,
7195 target,
7196 preventScrollReset,
7197 relative,
7198 viewTransition
7199 });
7200 function handleClick(event) {
7201 if (onClick) onClick(event);
7202 if (!event.defaultPrevented) {
7203 internalOnClick(event);
7204 }
7205 }
7206 let link = (
7207 // eslint-disable-next-line jsx-a11y/anchor-has-content
7208 /* @__PURE__ */ React10.createElement(
7209 "a",
7210 {
7211 ...rest,
7212 ...prefetchHandlers,
7213 href: absoluteHref || href,
7214 onClick: isExternal || reloadDocument ? onClick : handleClick,
7215 ref: mergeRefs(forwardedRef, prefetchRef),
7216 target,
7217 "data-discover": !isAbsolute && discover === "render" ? "true" : void 0
7218 }
7219 )
7220 );
7221 return shouldPrefetch && !isAbsolute ? /* @__PURE__ */ React10.createElement(React10.Fragment, null, link, /* @__PURE__ */ React10.createElement(PrefetchPageLinks, { page: href })) : link;
7222 }
7223);
7224Link.displayName = "Link";
7225var NavLink = React10.forwardRef(
7226 function NavLinkWithRef({
7227 "aria-current": ariaCurrentProp = "page",
7228 caseSensitive = false,
7229 className: classNameProp = "",
7230 end = false,
7231 style: styleProp,
7232 to,
7233 viewTransition,
7234 children,
7235 ...rest
7236 }, ref) {
7237 let path = useResolvedPath(to, { relative: rest.relative });
7238 let location = useLocation();
7239 let routerState = React10.useContext(DataRouterStateContext);
7240 let { navigator: navigator2, basename } = React10.useContext(NavigationContext);
7241 let isTransitioning = routerState != null && // Conditional usage is OK here because the usage of a data router is static
7242 // eslint-disable-next-line react-hooks/rules-of-hooks
7243 useViewTransitionState(path) && viewTransition === true;
7244 let toPathname = navigator2.encodeLocation ? navigator2.encodeLocation(path).pathname : path.pathname;
7245 let locationPathname = location.pathname;
7246 let nextLocationPathname = routerState && routerState.navigation && routerState.navigation.location ? routerState.navigation.location.pathname : null;
7247 if (!caseSensitive) {
7248 locationPathname = locationPathname.toLowerCase();
7249 nextLocationPathname = nextLocationPathname ? nextLocationPathname.toLowerCase() : null;
7250 toPathname = toPathname.toLowerCase();
7251 }
7252 if (nextLocationPathname && basename) {
7253 nextLocationPathname = stripBasename(nextLocationPathname, basename) || nextLocationPathname;
7254 }
7255 const endSlashPosition = toPathname !== "/" && toPathname.endsWith("/") ? toPathname.length - 1 : toPathname.length;
7256 let isActive = locationPathname === toPathname || !end && locationPathname.startsWith(toPathname) && locationPathname.charAt(endSlashPosition) === "/";
7257 let isPending = nextLocationPathname != null && (nextLocationPathname === toPathname || !end && nextLocationPathname.startsWith(toPathname) && nextLocationPathname.charAt(toPathname.length) === "/");
7258 let renderProps = {
7259 isActive,
7260 isPending,
7261 isTransitioning
7262 };
7263 let ariaCurrent = isActive ? ariaCurrentProp : void 0;
7264 let className;
7265 if (typeof classNameProp === "function") {
7266 className = classNameProp(renderProps);
7267 } else {
7268 className = [
7269 classNameProp,
7270 isActive ? "active" : null,
7271 isPending ? "pending" : null,
7272 isTransitioning ? "transitioning" : null
7273 ].filter(Boolean).join(" ");
7274 }
7275 let style = typeof styleProp === "function" ? styleProp(renderProps) : styleProp;
7276 return /* @__PURE__ */ React10.createElement(
7277 Link,
7278 {
7279 ...rest,
7280 "aria-current": ariaCurrent,
7281 className,
7282 ref,
7283 style,
7284 to,
7285 viewTransition
7286 },
7287 typeof children === "function" ? children(renderProps) : children
7288 );
7289 }
7290);
7291NavLink.displayName = "NavLink";
7292var Form = React10.forwardRef(
7293 ({
7294 discover = "render",
7295 fetcherKey,
7296 navigate,
7297 reloadDocument,
7298 replace: replace2,
7299 state,
7300 method = defaultMethod,
7301 action,
7302 onSubmit,
7303 relative,
7304 preventScrollReset,
7305 viewTransition,
7306 ...props
7307 }, forwardedRef) => {
7308 let submit = useSubmit();
7309 let formAction = useFormAction(action, { relative });
7310 let formMethod = method.toLowerCase() === "get" ? "get" : "post";
7311 let isAbsolute = typeof action === "string" && ABSOLUTE_URL_REGEX2.test(action);
7312 let submitHandler = (event) => {
7313 onSubmit && onSubmit(event);
7314 if (event.defaultPrevented) return;
7315 event.preventDefault();
7316 let submitter = event.nativeEvent.submitter;
7317 let submitMethod = submitter?.getAttribute("formmethod") || method;
7318 submit(submitter || event.currentTarget, {
7319 fetcherKey,
7320 method: submitMethod,
7321 navigate,
7322 replace: replace2,
7323 state,
7324 relative,
7325 preventScrollReset,
7326 viewTransition
7327 });
7328 };
7329 return /* @__PURE__ */ React10.createElement(
7330 "form",
7331 {
7332 ref: forwardedRef,
7333 method: formMethod,
7334 action: formAction,
7335 onSubmit: reloadDocument ? onSubmit : submitHandler,
7336 ...props,
7337 "data-discover": !isAbsolute && discover === "render" ? "true" : void 0
7338 }
7339 );
7340 }
7341);
7342Form.displayName = "Form";
7343function ScrollRestoration({
7344 getKey,
7345 storageKey,
7346 ...props
7347}) {
7348 let remixContext = React10.useContext(FrameworkContext);
7349 let { basename } = React10.useContext(NavigationContext);
7350 let location = useLocation();
7351 let matches = useMatches();
7352 useScrollRestoration({ getKey, storageKey });
7353 let ssrKey = React10.useMemo(
7354 () => {
7355 if (!remixContext || !getKey) return null;
7356 let userKey = getScrollRestorationKey(
7357 location,
7358 matches,
7359 basename,
7360 getKey
7361 );
7362 return userKey !== location.key ? userKey : null;
7363 },
7364 // Nah, we only need this the first time for the SSR render
7365 // eslint-disable-next-line react-hooks/exhaustive-deps
7366 []
7367 );
7368 if (!remixContext || remixContext.isSpaMode) {
7369 return null;
7370 }
7371 let restoreScroll = ((storageKey2, restoreKey) => {
7372 if (!window.history.state || !window.history.state.key) {
7373 let key = Math.random().toString(32).slice(2);
7374 window.history.replaceState({ key }, "");
7375 }
7376 try {
7377 let positions = JSON.parse(sessionStorage.getItem(storageKey2) || "{}");
7378 let storedY = positions[restoreKey || window.history.state.key];
7379 if (typeof storedY === "number") {
7380 window.scrollTo(0, storedY);
7381 }
7382 } catch (error) {
7383 console.error(error);
7384 sessionStorage.removeItem(storageKey2);
7385 }
7386 }).toString();
7387 return /* @__PURE__ */ React10.createElement(
7388 "script",
7389 {
7390 ...props,
7391 suppressHydrationWarning: true,
7392 dangerouslySetInnerHTML: {
7393 __html: `(${restoreScroll})(${JSON.stringify(
7394 storageKey || SCROLL_RESTORATION_STORAGE_KEY
7395 )}, ${JSON.stringify(ssrKey)})`
7396 }
7397 }
7398 );
7399}
7400ScrollRestoration.displayName = "ScrollRestoration";
7401function getDataRouterConsoleError2(hookName) {
7402 return `${hookName} must be used within a data router. See https://reactrouter.com/en/main/routers/picking-a-router.`;
7403}
7404function useDataRouterContext3(hookName) {
7405 let ctx = React10.useContext(DataRouterContext);
7406 invariant(ctx, getDataRouterConsoleError2(hookName));
7407 return ctx;
7408}
7409function useDataRouterState2(hookName) {
7410 let state = React10.useContext(DataRouterStateContext);
7411 invariant(state, getDataRouterConsoleError2(hookName));
7412 return state;
7413}
7414function useLinkClickHandler(to, {
7415 target,
7416 replace: replaceProp,
7417 state,
7418 preventScrollReset,
7419 relative,
7420 viewTransition
7421} = {}) {
7422 let navigate = useNavigate();
7423 let location = useLocation();
7424 let path = useResolvedPath(to, { relative });
7425 return React10.useCallback(
7426 (event) => {
7427 if (shouldProcessLinkClick(event, target)) {
7428 event.preventDefault();
7429 let replace2 = replaceProp !== void 0 ? replaceProp : createPath(location) === createPath(path);
7430 navigate(to, {
7431 replace: replace2,
7432 state,
7433 preventScrollReset,
7434 relative,
7435 viewTransition
7436 });
7437 }
7438 },
7439 [
7440 location,
7441 navigate,
7442 path,
7443 replaceProp,
7444 state,
7445 target,
7446 to,
7447 preventScrollReset,
7448 relative,
7449 viewTransition
7450 ]
7451 );
7452}
7453function useSearchParams(defaultInit) {
7454 warning(
7455 typeof URLSearchParams !== "undefined",
7456 `You cannot use the \`useSearchParams\` hook in a browser that does not support the URLSearchParams API. If you need to support Internet Explorer 11, we recommend you load a polyfill such as https://github.com/ungap/url-search-params.`
7457 );
7458 let defaultSearchParamsRef = React10.useRef(createSearchParams(defaultInit));
7459 let hasSetSearchParamsRef = React10.useRef(false);
7460 let location = useLocation();
7461 let searchParams = React10.useMemo(
7462 () => (
7463 // Only merge in the defaults if we haven't yet called setSearchParams.
7464 // Once we call that we want those to take precedence, otherwise you can't
7465 // remove a param with setSearchParams({}) if it has an initial value
7466 getSearchParamsForLocation(
7467 location.search,
7468 hasSetSearchParamsRef.current ? null : defaultSearchParamsRef.current
7469 )
7470 ),
7471 [location.search]
7472 );
7473 let navigate = useNavigate();
7474 let setSearchParams = React10.useCallback(
7475 (nextInit, navigateOptions) => {
7476 const newSearchParams = createSearchParams(
7477 typeof nextInit === "function" ? nextInit(searchParams) : nextInit
7478 );
7479 hasSetSearchParamsRef.current = true;
7480 navigate("?" + newSearchParams, navigateOptions);
7481 },
7482 [navigate, searchParams]
7483 );
7484 return [searchParams, setSearchParams];
7485}
7486var fetcherId = 0;
7487var getUniqueFetcherId = () => `__${String(++fetcherId)}__`;
7488function useSubmit() {
7489 let { router } = useDataRouterContext3("useSubmit" /* UseSubmit */);
7490 let { basename } = React10.useContext(NavigationContext);
7491 let currentRouteId = useRouteId();
7492 return React10.useCallback(
7493 async (target, options = {}) => {
7494 let { action, method, encType, formData, body } = getFormSubmissionInfo(
7495 target,
7496 basename
7497 );
7498 if (options.navigate === false) {
7499 let key = options.fetcherKey || getUniqueFetcherId();
7500 await router.fetch(key, currentRouteId, options.action || action, {
7501 preventScrollReset: options.preventScrollReset,
7502 formData,
7503 body,
7504 formMethod: options.method || method,
7505 formEncType: options.encType || encType,
7506 flushSync: options.flushSync
7507 });
7508 } else {
7509 await router.navigate(options.action || action, {
7510 preventScrollReset: options.preventScrollReset,
7511 formData,
7512 body,
7513 formMethod: options.method || method,
7514 formEncType: options.encType || encType,
7515 replace: options.replace,
7516 state: options.state,
7517 fromRouteId: currentRouteId,
7518 flushSync: options.flushSync,
7519 viewTransition: options.viewTransition
7520 });
7521 }
7522 },
7523 [router, basename, currentRouteId]
7524 );
7525}
7526function useFormAction(action, { relative } = {}) {
7527 let { basename } = React10.useContext(NavigationContext);
7528 let routeContext = React10.useContext(RouteContext);
7529 invariant(routeContext, "useFormAction must be used inside a RouteContext");
7530 let [match] = routeContext.matches.slice(-1);
7531 let path = { ...useResolvedPath(action ? action : ".", { relative }) };
7532 let location = useLocation();
7533 if (action == null) {
7534 path.search = location.search;
7535 let params = new URLSearchParams(path.search);
7536 let indexValues = params.getAll("index");
7537 let hasNakedIndexParam = indexValues.some((v) => v === "");
7538 if (hasNakedIndexParam) {
7539 params.delete("index");
7540 indexValues.filter((v) => v).forEach((v) => params.append("index", v));
7541 let qs = params.toString();
7542 path.search = qs ? `?${qs}` : "";
7543 }
7544 }
7545 if ((!action || action === ".") && match.route.index) {
7546 path.search = path.search ? path.search.replace(/^\?/, "?index&") : "?index";
7547 }
7548 if (basename !== "/") {
7549 path.pathname = path.pathname === "/" ? basename : joinPaths([basename, path.pathname]);
7550 }
7551 return createPath(path);
7552}
7553function useFetcher({
7554 key
7555} = {}) {
7556 let { router } = useDataRouterContext3("useFetcher" /* UseFetcher */);
7557 let state = useDataRouterState2("useFetcher" /* UseFetcher */);
7558 let fetcherData = React10.useContext(FetchersContext);
7559 let route = React10.useContext(RouteContext);
7560 let routeId = route.matches[route.matches.length - 1]?.route.id;
7561 invariant(fetcherData, `useFetcher must be used inside a FetchersContext`);
7562 invariant(route, `useFetcher must be used inside a RouteContext`);
7563 invariant(
7564 routeId != null,
7565 `useFetcher can only be used on routes that contain a unique "id"`
7566 );
7567 let defaultKey = React10.useId();
7568 let [fetcherKey, setFetcherKey] = React10.useState(key || defaultKey);
7569 if (key && key !== fetcherKey) {
7570 setFetcherKey(key);
7571 }
7572 React10.useEffect(() => {
7573 router.getFetcher(fetcherKey);
7574 return () => router.deleteFetcher(fetcherKey);
7575 }, [router, fetcherKey]);
7576 let load = React10.useCallback(
7577 async (href, opts) => {
7578 invariant(routeId, "No routeId available for fetcher.load()");
7579 await router.fetch(fetcherKey, routeId, href, opts);
7580 },
7581 [fetcherKey, routeId, router]
7582 );
7583 let submitImpl = useSubmit();
7584 let submit = React10.useCallback(
7585 async (target, opts) => {
7586 await submitImpl(target, {
7587 ...opts,
7588 navigate: false,
7589 fetcherKey
7590 });
7591 },
7592 [fetcherKey, submitImpl]
7593 );
7594 let FetcherForm = React10.useMemo(() => {
7595 let FetcherForm2 = React10.forwardRef(
7596 (props, ref) => {
7597 return /* @__PURE__ */ React10.createElement(Form, { ...props, navigate: false, fetcherKey, ref });
7598 }
7599 );
7600 FetcherForm2.displayName = "fetcher.Form";
7601 return FetcherForm2;
7602 }, [fetcherKey]);
7603 let fetcher = state.fetchers.get(fetcherKey) || IDLE_FETCHER;
7604 let data2 = fetcherData.get(fetcherKey);
7605 let fetcherWithComponents = React10.useMemo(
7606 () => ({
7607 Form: FetcherForm,
7608 submit,
7609 load,
7610 ...fetcher,
7611 data: data2
7612 }),
7613 [FetcherForm, submit, load, fetcher, data2]
7614 );
7615 return fetcherWithComponents;
7616}
7617function useFetchers() {
7618 let state = useDataRouterState2("useFetchers" /* UseFetchers */);
7619 return Array.from(state.fetchers.entries()).map(([key, fetcher]) => ({
7620 ...fetcher,
7621 key
7622 }));
7623}
7624var SCROLL_RESTORATION_STORAGE_KEY = "react-router-scroll-positions";
7625var savedScrollPositions = {};
7626function getScrollRestorationKey(location, matches, basename, getKey) {
7627 let key = null;
7628 if (getKey) {
7629 if (basename !== "/") {
7630 key = getKey(
7631 {
7632 ...location,
7633 pathname: stripBasename(location.pathname, basename) || location.pathname
7634 },
7635 matches
7636 );
7637 } else {
7638 key = getKey(location, matches);
7639 }
7640 }
7641 if (key == null) {
7642 key = location.key;
7643 }
7644 return key;
7645}
7646function useScrollRestoration({
7647 getKey,
7648 storageKey
7649} = {}) {
7650 let { router } = useDataRouterContext3("useScrollRestoration" /* UseScrollRestoration */);
7651 let { restoreScrollPosition, preventScrollReset } = useDataRouterState2(
7652 "useScrollRestoration" /* UseScrollRestoration */
7653 );
7654 let { basename } = React10.useContext(NavigationContext);
7655 let location = useLocation();
7656 let matches = useMatches();
7657 let navigation = useNavigation();
7658 React10.useEffect(() => {
7659 window.history.scrollRestoration = "manual";
7660 return () => {
7661 window.history.scrollRestoration = "auto";
7662 };
7663 }, []);
7664 usePageHide(
7665 React10.useCallback(() => {
7666 if (navigation.state === "idle") {
7667 let key = getScrollRestorationKey(location, matches, basename, getKey);
7668 savedScrollPositions[key] = window.scrollY;
7669 }
7670 try {
7671 sessionStorage.setItem(
7672 storageKey || SCROLL_RESTORATION_STORAGE_KEY,
7673 JSON.stringify(savedScrollPositions)
7674 );
7675 } catch (error) {
7676 warning(
7677 false,
7678 `Failed to save scroll positions in sessionStorage, <ScrollRestoration /> will not work properly (${error}).`
7679 );
7680 }
7681 window.history.scrollRestoration = "auto";
7682 }, [navigation.state, getKey, basename, location, matches, storageKey])
7683 );
7684 if (typeof document !== "undefined") {
7685 React10.useLayoutEffect(() => {
7686 try {
7687 let sessionPositions = sessionStorage.getItem(
7688 storageKey || SCROLL_RESTORATION_STORAGE_KEY
7689 );
7690 if (sessionPositions) {
7691 savedScrollPositions = JSON.parse(sessionPositions);
7692 }
7693 } catch (e) {
7694 }
7695 }, [storageKey]);
7696 React10.useLayoutEffect(() => {
7697 let disableScrollRestoration = router?.enableScrollRestoration(
7698 savedScrollPositions,
7699 () => window.scrollY,
7700 getKey ? (location2, matches2) => getScrollRestorationKey(location2, matches2, basename, getKey) : void 0
7701 );
7702 return () => disableScrollRestoration && disableScrollRestoration();
7703 }, [router, basename, getKey]);
7704 React10.useLayoutEffect(() => {
7705 if (restoreScrollPosition === false) {
7706 return;
7707 }
7708 if (typeof restoreScrollPosition === "number") {
7709 window.scrollTo(0, restoreScrollPosition);
7710 return;
7711 }
7712 if (location.hash) {
7713 let el = document.getElementById(
7714 decodeURIComponent(location.hash.slice(1))
7715 );
7716 if (el) {
7717 el.scrollIntoView();
7718 return;
7719 }
7720 }
7721 if (preventScrollReset === true) {
7722 return;
7723 }
7724 window.scrollTo(0, 0);
7725 }, [location, restoreScrollPosition, preventScrollReset]);
7726 }
7727}
7728function useBeforeUnload(callback, options) {
7729 let { capture } = options || {};
7730 React10.useEffect(() => {
7731 let opts = capture != null ? { capture } : void 0;
7732 window.addEventListener("beforeunload", callback, opts);
7733 return () => {
7734 window.removeEventListener("beforeunload", callback, opts);
7735 };
7736 }, [callback, capture]);
7737}
7738function usePageHide(callback, options) {
7739 let { capture } = options || {};
7740 React10.useEffect(() => {
7741 let opts = capture != null ? { capture } : void 0;
7742 window.addEventListener("pagehide", callback, opts);
7743 return () => {
7744 window.removeEventListener("pagehide", callback, opts);
7745 };
7746 }, [callback, capture]);
7747}
7748function usePrompt({
7749 when,
7750 message
7751}) {
7752 let blocker = useBlocker(when);
7753 React10.useEffect(() => {
7754 if (blocker.state === "blocked") {
7755 let proceed = window.confirm(message);
7756 if (proceed) {
7757 setTimeout(blocker.proceed, 0);
7758 } else {
7759 blocker.reset();
7760 }
7761 }
7762 }, [blocker, message]);
7763 React10.useEffect(() => {
7764 if (blocker.state === "blocked" && !when) {
7765 blocker.reset();
7766 }
7767 }, [blocker, when]);
7768}
7769function useViewTransitionState(to, opts = {}) {
7770 let vtContext = React10.useContext(ViewTransitionContext);
7771 invariant(
7772 vtContext != null,
7773 "`useViewTransitionState` must be used within `react-router-dom`'s `RouterProvider`. Did you accidentally import `RouterProvider` from `react-router`?"
7774 );
7775 let { basename } = useDataRouterContext3(
7776 "useViewTransitionState" /* useViewTransitionState */
7777 );
7778 let path = useResolvedPath(to, { relative: opts.relative });
7779 if (!vtContext.isTransitioning) {
7780 return false;
7781 }
7782 let currentPath = stripBasename(vtContext.currentLocation.pathname, basename) || vtContext.currentLocation.pathname;
7783 let nextPath = stripBasename(vtContext.nextLocation.pathname, basename) || vtContext.nextLocation.pathname;
7784 return matchPath(path.pathname, nextPath) != null || matchPath(path.pathname, currentPath) != null;
7785}
7786
7787// lib/dom/server.tsx
7788import * as React11 from "react";
7789function StaticRouter({
7790 basename,
7791 children,
7792 location: locationProp = "/"
7793}) {
7794 if (typeof locationProp === "string") {
7795 locationProp = parsePath(locationProp);
7796 }
7797 let action = "POP" /* Pop */;
7798 let location = {
7799 pathname: locationProp.pathname || "/",
7800 search: locationProp.search || "",
7801 hash: locationProp.hash || "",
7802 state: locationProp.state != null ? locationProp.state : null,
7803 key: locationProp.key || "default"
7804 };
7805 let staticNavigator = getStatelessNavigator();
7806 return /* @__PURE__ */ React11.createElement(
7807 Router,
7808 {
7809 basename,
7810 children,
7811 location,
7812 navigationType: action,
7813 navigator: staticNavigator,
7814 static: true
7815 }
7816 );
7817}
7818function StaticRouterProvider({
7819 context,
7820 router,
7821 hydrate = true,
7822 nonce
7823}) {
7824 invariant(
7825 router && context,
7826 "You must provide `router` and `context` to <StaticRouterProvider>"
7827 );
7828 let dataRouterContext = {
7829 router,
7830 navigator: getStatelessNavigator(),
7831 static: true,
7832 staticContext: context,
7833 basename: context.basename || "/"
7834 };
7835 let fetchersContext = /* @__PURE__ */ new Map();
7836 let hydrateScript = "";
7837 if (hydrate !== false) {
7838 let data2 = {
7839 loaderData: context.loaderData,
7840 actionData: context.actionData,
7841 errors: serializeErrors(context.errors)
7842 };
7843 let json = htmlEscape(JSON.stringify(JSON.stringify(data2)));
7844 hydrateScript = `window.__staticRouterHydrationData = JSON.parse(${json});`;
7845 }
7846 let { state } = dataRouterContext.router;
7847 return /* @__PURE__ */ React11.createElement(React11.Fragment, null, /* @__PURE__ */ React11.createElement(DataRouterContext.Provider, { value: dataRouterContext }, /* @__PURE__ */ React11.createElement(DataRouterStateContext.Provider, { value: state }, /* @__PURE__ */ React11.createElement(FetchersContext.Provider, { value: fetchersContext }, /* @__PURE__ */ React11.createElement(ViewTransitionContext.Provider, { value: { isTransitioning: false } }, /* @__PURE__ */ React11.createElement(
7848 Router,
7849 {
7850 basename: dataRouterContext.basename,
7851 location: state.location,
7852 navigationType: state.historyAction,
7853 navigator: dataRouterContext.navigator,
7854 static: dataRouterContext.static
7855 },
7856 /* @__PURE__ */ React11.createElement(
7857 DataRoutes2,
7858 {
7859 routes: router.routes,
7860 future: router.future,
7861 state
7862 }
7863 )
7864 ))))), hydrateScript ? /* @__PURE__ */ React11.createElement(
7865 "script",
7866 {
7867 suppressHydrationWarning: true,
7868 nonce,
7869 dangerouslySetInnerHTML: { __html: hydrateScript }
7870 }
7871 ) : null);
7872}
7873function DataRoutes2({
7874 routes,
7875 future,
7876 state
7877}) {
7878 return useRoutesImpl(routes, void 0, state, future);
7879}
7880function serializeErrors(errors) {
7881 if (!errors) return null;
7882 let entries = Object.entries(errors);
7883 let serialized = {};
7884 for (let [key, val] of entries) {
7885 if (isRouteErrorResponse(val)) {
7886 serialized[key] = { ...val, __type: "RouteErrorResponse" };
7887 } else if (val instanceof Error) {
7888 serialized[key] = {
7889 message: val.message,
7890 __type: "Error",
7891 // If this is a subclass (i.e., ReferenceError), send up the type so we
7892 // can re-create the same type during hydration.
7893 ...val.name !== "Error" ? {
7894 __subType: val.name
7895 } : {}
7896 };
7897 } else {
7898 serialized[key] = val;
7899 }
7900 }
7901 return serialized;
7902}
7903function getStatelessNavigator() {
7904 return {
7905 createHref,
7906 encodeLocation,
7907 push(to) {
7908 throw new Error(
7909 `You cannot use navigator.push() on the server because it is a stateless environment. This error was probably triggered when you did a \`navigate(${JSON.stringify(to)})\` somewhere in your app.`
7910 );
7911 },
7912 replace(to) {
7913 throw new Error(
7914 `You cannot use navigator.replace() on the server because it is a stateless environment. This error was probably triggered when you did a \`navigate(${JSON.stringify(to)}, { replace: true })\` somewhere in your app.`
7915 );
7916 },
7917 go(delta) {
7918 throw new Error(
7919 `You cannot use navigator.go() on the server because it is a stateless environment. This error was probably triggered when you did a \`navigate(${delta})\` somewhere in your app.`
7920 );
7921 },
7922 back() {
7923 throw new Error(
7924 `You cannot use navigator.back() on the server because it is a stateless environment.`
7925 );
7926 },
7927 forward() {
7928 throw new Error(
7929 `You cannot use navigator.forward() on the server because it is a stateless environment.`
7930 );
7931 }
7932 };
7933}
7934function createStaticHandler2(routes, opts) {
7935 return createStaticHandler(routes, {
7936 ...opts,
7937 mapRouteProperties
7938 });
7939}
7940function createStaticRouter(routes, context, opts = {}) {
7941 let manifest = {};
7942 let dataRoutes = convertRoutesToDataRoutes(
7943 routes,
7944 mapRouteProperties,
7945 void 0,
7946 manifest
7947 );
7948 let matches = context.matches.map((match) => {
7949 let route = manifest[match.route.id] || match.route;
7950 return {
7951 ...match,
7952 route
7953 };
7954 });
7955 let msg = (method) => `You cannot use router.${method}() on the server because it is a stateless environment`;
7956 return {
7957 get basename() {
7958 return context.basename;
7959 },
7960 get future() {
7961 return {
7962 ...opts?.future
7963 };
7964 },
7965 get state() {
7966 return {
7967 historyAction: "POP" /* Pop */,
7968 location: context.location,
7969 matches,
7970 loaderData: context.loaderData,
7971 actionData: context.actionData,
7972 errors: context.errors,
7973 initialized: true,
7974 navigation: IDLE_NAVIGATION,
7975 restoreScrollPosition: null,
7976 preventScrollReset: false,
7977 revalidation: "idle",
7978 fetchers: /* @__PURE__ */ new Map(),
7979 blockers: /* @__PURE__ */ new Map()
7980 };
7981 },
7982 get routes() {
7983 return dataRoutes;
7984 },
7985 get window() {
7986 return void 0;
7987 },
7988 initialize() {
7989 throw msg("initialize");
7990 },
7991 subscribe() {
7992 throw msg("subscribe");
7993 },
7994 enableScrollRestoration() {
7995 throw msg("enableScrollRestoration");
7996 },
7997 navigate() {
7998 throw msg("navigate");
7999 },
8000 fetch() {
8001 throw msg("fetch");
8002 },
8003 revalidate() {
8004 throw msg("revalidate");
8005 },
8006 createHref,
8007 encodeLocation,
8008 getFetcher() {
8009 return IDLE_FETCHER;
8010 },
8011 deleteFetcher() {
8012 throw msg("deleteFetcher");
8013 },
8014 dispose() {
8015 throw msg("dispose");
8016 },
8017 getBlocker() {
8018 return IDLE_BLOCKER;
8019 },
8020 deleteBlocker() {
8021 throw msg("deleteBlocker");
8022 },
8023 patchRoutes() {
8024 throw msg("patchRoutes");
8025 },
8026 _internalFetchControllers: /* @__PURE__ */ new Map(),
8027 _internalSetRoutes() {
8028 throw msg("_internalSetRoutes");
8029 }
8030 };
8031}
8032function createHref(to) {
8033 return typeof to === "string" ? to : createPath(to);
8034}
8035function encodeLocation(to) {
8036 let href = typeof to === "string" ? to : createPath(to);
8037 href = href.replace(/ $/, "%20");
8038 let encoded = ABSOLUTE_URL_REGEX3.test(href) ? new URL(href) : new URL(href, "http://localhost");
8039 return {
8040 pathname: encoded.pathname,
8041 search: encoded.search,
8042 hash: encoded.hash
8043 };
8044}
8045var ABSOLUTE_URL_REGEX3 = /^(?:[a-z][a-z0-9+.-]*:|\/\/)/i;
8046var ESCAPE_LOOKUP2 = {
8047 "&": "\\u0026",
8048 ">": "\\u003e",
8049 "<": "\\u003c",
8050 "\u2028": "\\u2028",
8051 "\u2029": "\\u2029"
8052};
8053var ESCAPE_REGEX2 = /[&><\u2028\u2029]/g;
8054function htmlEscape(str) {
8055 return str.replace(ESCAPE_REGEX2, (match) => ESCAPE_LOOKUP2[match]);
8056}
8057
8058// lib/dom/ssr/server.tsx
8059import * as React12 from "react";
8060function ServerRouter({
8061 context,
8062 url,
8063 nonce
8064}) {
8065 if (typeof url === "string") {
8066 url = new URL(url);
8067 }
8068 let { manifest, routeModules, criticalCss, serverHandoffString } = context;
8069 let routes = createServerRoutes(
8070 manifest.routes,
8071 routeModules,
8072 context.future,
8073 context.isSpaMode
8074 );
8075 context.staticHandlerContext.loaderData = {
8076 ...context.staticHandlerContext.loaderData
8077 };
8078 for (let match of context.staticHandlerContext.matches) {
8079 let routeId = match.route.id;
8080 let route = routeModules[routeId];
8081 let manifestRoute = context.manifest.routes[routeId];
8082 if (route && manifestRoute && shouldHydrateRouteLoader(manifestRoute, route, context.isSpaMode) && (route.HydrateFallback || !manifestRoute.hasLoader)) {
8083 delete context.staticHandlerContext.loaderData[routeId];
8084 }
8085 }
8086 let router = createStaticRouter(routes, context.staticHandlerContext);
8087 return /* @__PURE__ */ React12.createElement(React12.Fragment, null, /* @__PURE__ */ React12.createElement(
8088 FrameworkContext.Provider,
8089 {
8090 value: {
8091 manifest,
8092 routeModules,
8093 criticalCss,
8094 serverHandoffString,
8095 future: context.future,
8096 isSpaMode: context.isSpaMode,
8097 serializeError: context.serializeError,
8098 renderMeta: context.renderMeta
8099 }
8100 },
8101 /* @__PURE__ */ React12.createElement(RemixErrorBoundary, { location: router.state.location }, /* @__PURE__ */ React12.createElement(
8102 StaticRouterProvider,
8103 {
8104 router,
8105 context: context.staticHandlerContext,
8106 hydrate: false
8107 }
8108 ))
8109 ), context.serverHandoffStream ? /* @__PURE__ */ React12.createElement(React12.Suspense, null, /* @__PURE__ */ React12.createElement(
8110 StreamTransfer,
8111 {
8112 context,
8113 identifier: 0,
8114 reader: context.serverHandoffStream.getReader(),
8115 textDecoder: new TextDecoder(),
8116 nonce
8117 }
8118 )) : null);
8119}
8120
8121// lib/dom/ssr/routes-test-stub.tsx
8122import * as React13 from "react";
8123function createRoutesStub(routes, context = {}) {
8124 return function RoutesTestStub({
8125 initialEntries,
8126 initialIndex,
8127 hydrationData,
8128 future
8129 }) {
8130 let routerRef = React13.useRef();
8131 let remixContextRef = React13.useRef();
8132 if (routerRef.current == null) {
8133 remixContextRef.current = {
8134 future: {},
8135 manifest: {
8136 routes: {},
8137 entry: { imports: [], module: "" },
8138 url: "",
8139 version: ""
8140 },
8141 routeModules: {},
8142 isSpaMode: false
8143 };
8144 let patched = processRoutes(
8145 // @ts-expect-error loader/action context types don't match :/
8146 convertRoutesToDataRoutes(routes, (r) => r),
8147 context,
8148 remixContextRef.current.manifest,
8149 remixContextRef.current.routeModules
8150 );
8151 routerRef.current = createMemoryRouter(patched, {
8152 initialEntries,
8153 initialIndex,
8154 hydrationData
8155 });
8156 }
8157 return /* @__PURE__ */ React13.createElement(FrameworkContext.Provider, { value: remixContextRef.current }, /* @__PURE__ */ React13.createElement(RouterProvider, { router: routerRef.current }));
8158 };
8159}
8160function processRoutes(routes, context, manifest, routeModules, parentId) {
8161 return routes.map((route) => {
8162 if (!route.id) {
8163 throw new Error(
8164 "Expected a route.id in @remix-run/testing processRoutes() function"
8165 );
8166 }
8167 let { loader, action } = route;
8168 let newRoute = {
8169 id: route.id,
8170 path: route.path,
8171 index: route.index,
8172 Component: route.Component,
8173 HydrateFallback: route.HydrateFallback,
8174 ErrorBoundary: route.ErrorBoundary,
8175 action: action ? (args) => action({ ...args, context }) : void 0,
8176 loader: loader ? (args) => loader({ ...args, context }) : void 0,
8177 handle: route.handle,
8178 shouldRevalidate: route.shouldRevalidate
8179 };
8180 let entryRoute = {
8181 id: route.id,
8182 path: route.path,
8183 index: route.index,
8184 parentId,
8185 hasAction: route.action != null,
8186 hasLoader: route.loader != null,
8187 // When testing routes, you should just be stubbing loader/action, not
8188 // trying to re-implement the full loader/clientLoader/SSR/hydration flow.
8189 // That is better tested via E2E tests.
8190 hasClientAction: false,
8191 hasClientLoader: false,
8192 hasErrorBoundary: route.ErrorBoundary != null,
8193 module: "build/stub-path-to-module.js"
8194 // any need for this?
8195 };
8196 manifest.routes[newRoute.id] = entryRoute;
8197 routeModules[route.id] = {
8198 default: route.Component || Outlet,
8199 ErrorBoundary: route.ErrorBoundary || void 0,
8200 handle: route.handle,
8201 links: route.links,
8202 meta: route.meta,
8203 shouldRevalidate: route.shouldRevalidate
8204 };
8205 if (route.children) {
8206 newRoute.children = processRoutes(
8207 route.children,
8208 context,
8209 manifest,
8210 routeModules,
8211 newRoute.id
8212 );
8213 }
8214 return newRoute;
8215 });
8216}
8217
8218// lib/server-runtime/cookies.ts
8219import { parse, serialize } from "cookie";
8220
8221// lib/server-runtime/crypto.ts
8222var encoder = new TextEncoder();
8223var sign = async (value, secret) => {
8224 let data2 = encoder.encode(value);
8225 let key = await createKey2(secret, ["sign"]);
8226 let signature = await crypto.subtle.sign("HMAC", key, data2);
8227 let hash = btoa(String.fromCharCode(...new Uint8Array(signature))).replace(
8228 /=+$/,
8229 ""
8230 );
8231 return value + "." + hash;
8232};
8233var unsign = async (cookie, secret) => {
8234 let index = cookie.lastIndexOf(".");
8235 let value = cookie.slice(0, index);
8236 let hash = cookie.slice(index + 1);
8237 let data2 = encoder.encode(value);
8238 let key = await createKey2(secret, ["verify"]);
8239 let signature = byteStringToUint8Array(atob(hash));
8240 let valid = await crypto.subtle.verify("HMAC", key, signature, data2);
8241 return valid ? value : false;
8242};
8243var createKey2 = async (secret, usages) => crypto.subtle.importKey(
8244 "raw",
8245 encoder.encode(secret),
8246 { name: "HMAC", hash: "SHA-256" },
8247 false,
8248 usages
8249);
8250function byteStringToUint8Array(byteString) {
8251 let array = new Uint8Array(byteString.length);
8252 for (let i = 0; i < byteString.length; i++) {
8253 array[i] = byteString.charCodeAt(i);
8254 }
8255 return array;
8256}
8257
8258// lib/server-runtime/cookies.ts
8259var createCookie = (name, cookieOptions = {}) => {
8260 let { secrets = [], ...options } = {
8261 path: "/",
8262 sameSite: "lax",
8263 ...cookieOptions
8264 };
8265 warnOnceAboutExpiresCookie(name, options.expires);
8266 return {
8267 get name() {
8268 return name;
8269 },
8270 get isSigned() {
8271 return secrets.length > 0;
8272 },
8273 get expires() {
8274 return typeof options.maxAge !== "undefined" ? new Date(Date.now() + options.maxAge * 1e3) : options.expires;
8275 },
8276 async parse(cookieHeader, parseOptions) {
8277 if (!cookieHeader) return null;
8278 let cookies = parse(cookieHeader, { ...options, ...parseOptions });
8279 if (name in cookies) {
8280 let value = cookies[name];
8281 if (typeof value === "string" && value !== "") {
8282 let decoded = await decodeCookieValue(value, secrets);
8283 return decoded;
8284 } else {
8285 return "";
8286 }
8287 } else {
8288 return null;
8289 }
8290 },
8291 async serialize(value, serializeOptions) {
8292 return serialize(
8293 name,
8294 value === "" ? "" : await encodeCookieValue(value, secrets),
8295 {
8296 ...options,
8297 ...serializeOptions
8298 }
8299 );
8300 }
8301 };
8302};
8303var isCookie = (object) => {
8304 return object != null && typeof object.name === "string" && typeof object.isSigned === "boolean" && typeof object.parse === "function" && typeof object.serialize === "function";
8305};
8306async function encodeCookieValue(value, secrets) {
8307 let encoded = encodeData(value);
8308 if (secrets.length > 0) {
8309 encoded = await sign(encoded, secrets[0]);
8310 }
8311 return encoded;
8312}
8313async function decodeCookieValue(value, secrets) {
8314 if (secrets.length > 0) {
8315 for (let secret of secrets) {
8316 let unsignedValue = await unsign(value, secret);
8317 if (unsignedValue !== false) {
8318 return decodeData(unsignedValue);
8319 }
8320 }
8321 return null;
8322 }
8323 return decodeData(value);
8324}
8325function encodeData(value) {
8326 return btoa(myUnescape(encodeURIComponent(JSON.stringify(value))));
8327}
8328function decodeData(value) {
8329 try {
8330 return JSON.parse(decodeURIComponent(myEscape(atob(value))));
8331 } catch (error) {
8332 return {};
8333 }
8334}
8335function myEscape(value) {
8336 let str = value.toString();
8337 let result = "";
8338 let index = 0;
8339 let chr, code;
8340 while (index < str.length) {
8341 chr = str.charAt(index++);
8342 if (/[\w*+\-./@]/.exec(chr)) {
8343 result += chr;
8344 } else {
8345 code = chr.charCodeAt(0);
8346 if (code < 256) {
8347 result += "%" + hex(code, 2);
8348 } else {
8349 result += "%u" + hex(code, 4).toUpperCase();
8350 }
8351 }
8352 }
8353 return result;
8354}
8355function hex(code, length) {
8356 let result = code.toString(16);
8357 while (result.length < length) result = "0" + result;
8358 return result;
8359}
8360function myUnescape(value) {
8361 let str = value.toString();
8362 let result = "";
8363 let index = 0;
8364 let chr, part;
8365 while (index < str.length) {
8366 chr = str.charAt(index++);
8367 if (chr === "%") {
8368 if (str.charAt(index) === "u") {
8369 part = str.slice(index + 1, index + 5);
8370 if (/^[\da-f]{4}$/i.exec(part)) {
8371 result += String.fromCharCode(parseInt(part, 16));
8372 index += 5;
8373 continue;
8374 }
8375 } else {
8376 part = str.slice(index, index + 2);
8377 if (/^[\da-f]{2}$/i.exec(part)) {
8378 result += String.fromCharCode(parseInt(part, 16));
8379 index += 2;
8380 continue;
8381 }
8382 }
8383 }
8384 result += chr;
8385 }
8386 return result;
8387}
8388function warnOnceAboutExpiresCookie(name, expires) {
8389 warnOnce(
8390 !expires,
8391 `The "${name}" cookie has an "expires" property set. This will cause the expires value to not be updated when the session is committed. Instead, you should set the expires value when serializing the cookie. You can use \`commitSession(session, { expires })\` if using a session storage object, or \`cookie.serialize("value", { expires })\` if you're using the cookie directly.`
8392 );
8393}
8394
8395// lib/server-runtime/entry.ts
8396function createEntryRouteModules(manifest) {
8397 return Object.keys(manifest).reduce((memo2, routeId) => {
8398 let route = manifest[routeId];
8399 if (route) {
8400 memo2[routeId] = route.module;
8401 }
8402 return memo2;
8403 }, {});
8404}
8405
8406// lib/server-runtime/mode.ts
8407var ServerMode = /* @__PURE__ */ ((ServerMode2) => {
8408 ServerMode2["Development"] = "development";
8409 ServerMode2["Production"] = "production";
8410 ServerMode2["Test"] = "test";
8411 return ServerMode2;
8412})(ServerMode || {});
8413function isServerMode(value) {
8414 return value === "development" /* Development */ || value === "production" /* Production */ || value === "test" /* Test */;
8415}
8416
8417// lib/server-runtime/errors.ts
8418function sanitizeError(error, serverMode) {
8419 if (error instanceof Error && serverMode !== "development" /* Development */) {
8420 let sanitized = new Error("Unexpected Server Error");
8421 sanitized.stack = void 0;
8422 return sanitized;
8423 }
8424 return error;
8425}
8426function sanitizeErrors(errors, serverMode) {
8427 return Object.entries(errors).reduce((acc, [routeId, error]) => {
8428 return Object.assign(acc, { [routeId]: sanitizeError(error, serverMode) });
8429 }, {});
8430}
8431function serializeError(error, serverMode) {
8432 let sanitized = sanitizeError(error, serverMode);
8433 return {
8434 message: sanitized.message,
8435 stack: sanitized.stack
8436 };
8437}
8438function serializeErrors2(errors, serverMode) {
8439 if (!errors) return null;
8440 let entries = Object.entries(errors);
8441 let serialized = {};
8442 for (let [key, val] of entries) {
8443 if (isRouteErrorResponse(val)) {
8444 serialized[key] = { ...val, __type: "RouteErrorResponse" };
8445 } else if (val instanceof Error) {
8446 let sanitized = sanitizeError(val, serverMode);
8447 serialized[key] = {
8448 message: sanitized.message,
8449 stack: sanitized.stack,
8450 __type: "Error",
8451 // If this is a subclass (i.e., ReferenceError), send up the type so we
8452 // can re-create the same type during hydration. This will only apply
8453 // in dev mode since all production errors are sanitized to normal
8454 // Error instances
8455 ...sanitized.name !== "Error" ? {
8456 __subType: sanitized.name
8457 } : {}
8458 };
8459 } else {
8460 serialized[key] = val;
8461 }
8462 }
8463 return serialized;
8464}
8465
8466// lib/server-runtime/routeMatching.ts
8467function matchServerRoutes(routes, pathname, basename) {
8468 let matches = matchRoutes(
8469 routes,
8470 pathname,
8471 basename
8472 );
8473 if (!matches) return null;
8474 return matches.map((match) => ({
8475 params: match.params,
8476 pathname: match.pathname,
8477 route: match.route
8478 }));
8479}
8480
8481// lib/server-runtime/data.ts
8482async function callRouteHandler(handler, args) {
8483 let result = await handler({
8484 request: stripRoutesParam(stripIndexParam2(args.request)),
8485 params: args.params,
8486 context: args.context
8487 });
8488 if (isDataWithResponseInit(result) && result.init && result.init.status && isRedirectStatusCode(result.init.status)) {
8489 throw new Response(null, result.init);
8490 }
8491 return result;
8492}
8493function stripIndexParam2(request) {
8494 let url = new URL(request.url);
8495 let indexValues = url.searchParams.getAll("index");
8496 url.searchParams.delete("index");
8497 let indexValuesToKeep = [];
8498 for (let indexValue of indexValues) {
8499 if (indexValue) {
8500 indexValuesToKeep.push(indexValue);
8501 }
8502 }
8503 for (let toKeep of indexValuesToKeep) {
8504 url.searchParams.append("index", toKeep);
8505 }
8506 let init = {
8507 method: request.method,
8508 body: request.body,
8509 headers: request.headers,
8510 signal: request.signal
8511 };
8512 if (init.body) {
8513 init.duplex = "half";
8514 }
8515 return new Request(url.href, init);
8516}
8517function stripRoutesParam(request) {
8518 let url = new URL(request.url);
8519 url.searchParams.delete("_routes");
8520 let init = {
8521 method: request.method,
8522 body: request.body,
8523 headers: request.headers,
8524 signal: request.signal
8525 };
8526 if (init.body) {
8527 init.duplex = "half";
8528 }
8529 return new Request(url.href, init);
8530}
8531
8532// lib/server-runtime/invariant.ts
8533function invariant3(value, message) {
8534 if (value === false || value === null || typeof value === "undefined") {
8535 console.error(
8536 "The following error is a bug in React Router; please open an issue! https://github.com/remix-run/react-router/issues/new/choose"
8537 );
8538 throw new Error(message);
8539 }
8540}
8541
8542// lib/server-runtime/routes.ts
8543function groupRoutesByParentId2(manifest) {
8544 let routes = {};
8545 Object.values(manifest).forEach((route) => {
8546 if (route) {
8547 let parentId = route.parentId || "";
8548 if (!routes[parentId]) {
8549 routes[parentId] = [];
8550 }
8551 routes[parentId].push(route);
8552 }
8553 });
8554 return routes;
8555}
8556function createRoutes(manifest, parentId = "", routesByParentId = groupRoutesByParentId2(manifest)) {
8557 return (routesByParentId[parentId] || []).map((route) => ({
8558 ...route,
8559 children: createRoutes(manifest, route.id, routesByParentId)
8560 }));
8561}
8562function createStaticHandlerDataRoutes(manifest, future, parentId = "", routesByParentId = groupRoutesByParentId2(manifest)) {
8563 return (routesByParentId[parentId] || []).map((route) => {
8564 let commonRoute = {
8565 // Always include root due to default boundaries
8566 hasErrorBoundary: route.id === "root" || route.module.ErrorBoundary != null,
8567 id: route.id,
8568 path: route.path,
8569 // Need to use RR's version in the param typed here to permit the optional
8570 // context even though we know it'll always be provided in remix
8571 loader: route.module.loader ? async (args) => {
8572 if (args.request.headers.has("X-React-Router-Prerender-Data")) {
8573 const preRenderedData = args.request.headers.get(
8574 "X-React-Router-Prerender-Data"
8575 );
8576 let encoded = preRenderedData ? decodeURI(preRenderedData) : preRenderedData;
8577 invariant3(encoded, "Missing prerendered data for route");
8578 let uint8array = new TextEncoder().encode(encoded);
8579 let stream = new ReadableStream({
8580 start(controller) {
8581 controller.enqueue(uint8array);
8582 controller.close();
8583 }
8584 });
8585 let decoded = await decodeViaTurboStream(stream, global);
8586 let data2 = decoded.value;
8587 invariant3(
8588 data2 && route.id in data2,
8589 "Unable to decode prerendered data"
8590 );
8591 let result = data2[route.id];
8592 invariant3("data" in result, "Unable to process prerendered data");
8593 return result.data;
8594 }
8595 let val = await callRouteHandler(route.module.loader, args);
8596 return val;
8597 } : void 0,
8598 action: route.module.action ? (args) => callRouteHandler(route.module.action, args) : void 0,
8599 handle: route.module.handle
8600 };
8601 return route.index ? {
8602 index: true,
8603 ...commonRoute
8604 } : {
8605 caseSensitive: route.caseSensitive,
8606 children: createStaticHandlerDataRoutes(
8607 manifest,
8608 future,
8609 route.id,
8610 routesByParentId
8611 ),
8612 ...commonRoute
8613 };
8614 });
8615}
8616
8617// lib/server-runtime/markup.ts
8618var ESCAPE_LOOKUP3 = {
8619 "&": "\\u0026",
8620 ">": "\\u003e",
8621 "<": "\\u003c",
8622 "\u2028": "\\u2028",
8623 "\u2029": "\\u2029"
8624};
8625var ESCAPE_REGEX3 = /[&><\u2028\u2029]/g;
8626function escapeHtml2(html) {
8627 return html.replace(ESCAPE_REGEX3, (match) => ESCAPE_LOOKUP3[match]);
8628}
8629
8630// lib/server-runtime/serverHandoff.ts
8631function createServerHandoffString(serverHandoff) {
8632 return escapeHtml2(JSON.stringify(serverHandoff));
8633}
8634
8635// lib/server-runtime/dev.ts
8636var globalDevServerHooksKey = "__reactRouterDevServerHooks";
8637function setDevServerHooks(devServerHooks) {
8638 globalThis[globalDevServerHooksKey] = devServerHooks;
8639}
8640function getDevServerHooks() {
8641 return globalThis[globalDevServerHooksKey];
8642}
8643
8644// lib/server-runtime/single-fetch.ts
8645import { encode } from "turbo-stream";
8646
8647// lib/server-runtime/headers.ts
8648import { splitCookiesString } from "set-cookie-parser";
8649function getDocumentHeaders(build, context) {
8650 let boundaryIdx = context.errors ? context.matches.findIndex((m) => context.errors[m.route.id]) : -1;
8651 let matches = boundaryIdx >= 0 ? context.matches.slice(0, boundaryIdx + 1) : context.matches;
8652 let errorHeaders;
8653 if (boundaryIdx >= 0) {
8654 let { actionHeaders, actionData, loaderHeaders, loaderData } = context;
8655 context.matches.slice(boundaryIdx).some((match) => {
8656 let id = match.route.id;
8657 if (actionHeaders[id] && (!actionData || !actionData.hasOwnProperty(id))) {
8658 errorHeaders = actionHeaders[id];
8659 } else if (loaderHeaders[id] && !loaderData.hasOwnProperty(id)) {
8660 errorHeaders = loaderHeaders[id];
8661 }
8662 return errorHeaders != null;
8663 });
8664 }
8665 return matches.reduce((parentHeaders, match, idx) => {
8666 let { id } = match.route;
8667 let route = build.routes[id];
8668 invariant3(route, `Route with id "${id}" not found in build`);
8669 let routeModule = route.module;
8670 let loaderHeaders = context.loaderHeaders[id] || new Headers();
8671 let actionHeaders = context.actionHeaders[id] || new Headers();
8672 let includeErrorHeaders = errorHeaders != null && idx === matches.length - 1;
8673 let includeErrorCookies = includeErrorHeaders && errorHeaders !== loaderHeaders && errorHeaders !== actionHeaders;
8674 if (routeModule.headers == null) {
8675 let headers2 = new Headers(parentHeaders);
8676 if (includeErrorCookies) {
8677 prependCookies(errorHeaders, headers2);
8678 }
8679 prependCookies(actionHeaders, headers2);
8680 prependCookies(loaderHeaders, headers2);
8681 return headers2;
8682 }
8683 let headers = new Headers(
8684 routeModule.headers ? typeof routeModule.headers === "function" ? routeModule.headers({
8685 loaderHeaders,
8686 parentHeaders,
8687 actionHeaders,
8688 errorHeaders: includeErrorHeaders ? errorHeaders : void 0
8689 }) : routeModule.headers : void 0
8690 );
8691 if (includeErrorCookies) {
8692 prependCookies(errorHeaders, headers);
8693 }
8694 prependCookies(actionHeaders, headers);
8695 prependCookies(loaderHeaders, headers);
8696 prependCookies(parentHeaders, headers);
8697 return headers;
8698 }, new Headers());
8699}
8700function prependCookies(parentHeaders, childHeaders) {
8701 let parentSetCookieString = parentHeaders.get("Set-Cookie");
8702 if (parentSetCookieString) {
8703 let cookies = splitCookiesString(parentSetCookieString);
8704 let childCookies = new Set(childHeaders.getSetCookie());
8705 cookies.forEach((cookie) => {
8706 if (!childCookies.has(cookie)) {
8707 childHeaders.append("Set-Cookie", cookie);
8708 }
8709 });
8710 }
8711}
8712
8713// lib/server-runtime/single-fetch.ts
8714var SINGLE_FETCH_REDIRECT_STATUS = 202;
8715function getSingleFetchDataStrategy2({
8716 isActionDataRequest,
8717 loadRouteIds
8718} = {}) {
8719 return async ({ request, matches }) => {
8720 if (isActionDataRequest && request.method === "GET") {
8721 return {};
8722 }
8723 let matchesToLoad = loadRouteIds ? matches.filter((m) => loadRouteIds.includes(m.route.id)) : matches;
8724 let results = await Promise.all(
8725 matchesToLoad.map((match) => match.resolve())
8726 );
8727 return results.reduce(
8728 (acc, result, i) => Object.assign(acc, { [matchesToLoad[i].route.id]: result }),
8729 {}
8730 );
8731 };
8732}
8733async function singleFetchAction(build, serverMode, staticHandler, request, handlerUrl, loadContext, handleError) {
8734 try {
8735 let handlerRequest = new Request(handlerUrl, {
8736 method: request.method,
8737 body: request.body,
8738 headers: request.headers,
8739 signal: request.signal,
8740 ...request.body ? { duplex: "half" } : void 0
8741 });
8742 let result = await staticHandler.query(handlerRequest, {
8743 requestContext: loadContext,
8744 skipLoaderErrorBubbling: true,
8745 dataStrategy: getSingleFetchDataStrategy2({
8746 isActionDataRequest: true
8747 })
8748 });
8749 if (isResponse(result)) {
8750 return {
8751 result: getSingleFetchRedirect(
8752 result.status,
8753 result.headers,
8754 build.basename
8755 ),
8756 headers: result.headers,
8757 status: SINGLE_FETCH_REDIRECT_STATUS
8758 };
8759 }
8760 let context = result;
8761 let headers = getDocumentHeaders(build, context);
8762 if (isRedirectStatusCode(context.statusCode) && headers.has("Location")) {
8763 return {
8764 result: getSingleFetchRedirect(
8765 context.statusCode,
8766 headers,
8767 build.basename
8768 ),
8769 headers,
8770 status: SINGLE_FETCH_REDIRECT_STATUS
8771 };
8772 }
8773 if (context.errors) {
8774 Object.values(context.errors).forEach((err) => {
8775 if (!isRouteErrorResponse(err) || err.error) {
8776 handleError(err);
8777 }
8778 });
8779 context.errors = sanitizeErrors(context.errors, serverMode);
8780 }
8781 let singleFetchResult;
8782 if (context.errors) {
8783 singleFetchResult = { error: Object.values(context.errors)[0] };
8784 } else {
8785 singleFetchResult = { data: Object.values(context.actionData || {})[0] };
8786 }
8787 return {
8788 result: singleFetchResult,
8789 headers,
8790 status: context.statusCode
8791 };
8792 } catch (error) {
8793 handleError(error);
8794 return {
8795 result: { error },
8796 headers: new Headers(),
8797 status: 500
8798 };
8799 }
8800}
8801async function singleFetchLoaders(build, serverMode, staticHandler, request, handlerUrl, loadContext, handleError) {
8802 try {
8803 let handlerRequest = new Request(handlerUrl, {
8804 headers: request.headers,
8805 signal: request.signal
8806 });
8807 let loadRouteIds = new URL(request.url).searchParams.get("_routes")?.split(",") || void 0;
8808 let result = await staticHandler.query(handlerRequest, {
8809 requestContext: loadContext,
8810 skipLoaderErrorBubbling: true,
8811 dataStrategy: getSingleFetchDataStrategy2({
8812 loadRouteIds
8813 })
8814 });
8815 if (isResponse(result)) {
8816 return {
8817 result: {
8818 [SingleFetchRedirectSymbol]: getSingleFetchRedirect(
8819 result.status,
8820 result.headers,
8821 build.basename
8822 )
8823 },
8824 headers: result.headers,
8825 status: SINGLE_FETCH_REDIRECT_STATUS
8826 };
8827 }
8828 let context = result;
8829 let headers = getDocumentHeaders(build, context);
8830 if (isRedirectStatusCode(context.statusCode) && headers.has("Location")) {
8831 return {
8832 result: {
8833 [SingleFetchRedirectSymbol]: getSingleFetchRedirect(
8834 context.statusCode,
8835 headers,
8836 build.basename
8837 )
8838 },
8839 headers,
8840 status: SINGLE_FETCH_REDIRECT_STATUS
8841 };
8842 }
8843 if (context.errors) {
8844 Object.values(context.errors).forEach((err) => {
8845 if (!isRouteErrorResponse(err) || err.error) {
8846 handleError(err);
8847 }
8848 });
8849 context.errors = sanitizeErrors(context.errors, serverMode);
8850 }
8851 let results = {};
8852 let loadedMatches = loadRouteIds ? context.matches.filter(
8853 (m) => m.route.loader && loadRouteIds.includes(m.route.id)
8854 ) : context.matches;
8855 loadedMatches.forEach((m) => {
8856 let { id } = m.route;
8857 if (context.errors && context.errors.hasOwnProperty(id)) {
8858 results[id] = { error: context.errors[id] };
8859 } else if (context.loaderData.hasOwnProperty(id)) {
8860 results[id] = { data: context.loaderData[id] };
8861 }
8862 });
8863 return {
8864 result: results,
8865 headers,
8866 status: context.statusCode
8867 };
8868 } catch (error) {
8869 handleError(error);
8870 return {
8871 result: { root: { error } },
8872 headers: new Headers(),
8873 status: 500
8874 };
8875 }
8876}
8877function getSingleFetchRedirect(status, headers, basename) {
8878 let redirect2 = headers.get("Location");
8879 if (basename) {
8880 redirect2 = stripBasename(redirect2, basename) || redirect2;
8881 }
8882 return {
8883 redirect: redirect2,
8884 status,
8885 revalidate: (
8886 // Technically X-Remix-Revalidate isn't needed here - that was an implementation
8887 // detail of ?_data requests as our way to tell the front end to revalidate when
8888 // we didn't have a response body to include that information in.
8889 // With single fetch, we tell the front end via this revalidate boolean field.
8890 // However, we're respecting it for now because it may be something folks have
8891 // used in their own responses
8892 // TODO(v3): Consider removing or making this official public API
8893 headers.has("X-Remix-Revalidate") || headers.has("Set-Cookie")
8894 ),
8895 reload: headers.has("X-Remix-Reload-Document"),
8896 replace: headers.has("X-Remix-Replace")
8897 };
8898}
8899function encodeViaTurboStream(data2, requestSignal, streamTimeout, serverMode) {
8900 let controller = new AbortController();
8901 let timeoutId = setTimeout(
8902 () => controller.abort(new Error("Server Timeout")),
8903 typeof streamTimeout === "number" ? streamTimeout : 4950
8904 );
8905 requestSignal.addEventListener("abort", () => clearTimeout(timeoutId));
8906 return encode(data2, {
8907 signal: controller.signal,
8908 plugins: [
8909 (value) => {
8910 if (value instanceof Error) {
8911 let { name, message, stack } = serverMode === "production" /* Production */ ? sanitizeError(value, serverMode) : value;
8912 return ["SanitizedError", name, message, stack];
8913 }
8914 if (value instanceof ErrorResponseImpl) {
8915 let { data: data3, status, statusText } = value;
8916 return ["ErrorResponse", data3, status, statusText];
8917 }
8918 if (value && typeof value === "object" && SingleFetchRedirectSymbol in value) {
8919 return ["SingleFetchRedirect", value[SingleFetchRedirectSymbol]];
8920 }
8921 }
8922 ],
8923 postPlugins: [
8924 (value) => {
8925 if (!value) return;
8926 if (typeof value !== "object") return;
8927 return [
8928 "SingleFetchClassInstance",
8929 Object.fromEntries(Object.entries(value))
8930 ];
8931 },
8932 () => ["SingleFetchFallback"]
8933 ]
8934 });
8935}
8936
8937// lib/server-runtime/server.ts
8938var NO_BODY_STATUS_CODES = /* @__PURE__ */ new Set([100, 101, 204, 205, 304]);
8939function derive(build, mode) {
8940 let routes = createRoutes(build.routes);
8941 let dataRoutes = createStaticHandlerDataRoutes(build.routes, build.future);
8942 let serverMode = isServerMode(mode) ? mode : "production" /* Production */;
8943 let staticHandler = createStaticHandler(dataRoutes, {
8944 basename: build.basename
8945 });
8946 let errorHandler = build.entry.module.handleError || ((error, { request }) => {
8947 if (serverMode !== "test" /* Test */ && !request.signal.aborted) {
8948 console.error(
8949 // @ts-expect-error This is "private" from users but intended for internal use
8950 isRouteErrorResponse(error) && error.error ? error.error : error
8951 );
8952 }
8953 });
8954 return {
8955 routes,
8956 dataRoutes,
8957 serverMode,
8958 staticHandler,
8959 errorHandler
8960 };
8961}
8962var createRequestHandler = (build, mode) => {
8963 let _build;
8964 let routes;
8965 let serverMode;
8966 let staticHandler;
8967 let errorHandler;
8968 return async function requestHandler(request, loadContext = {}) {
8969 _build = typeof build === "function" ? await build() : build;
8970 if (typeof build === "function") {
8971 let derived = derive(_build, mode);
8972 routes = derived.routes;
8973 serverMode = derived.serverMode;
8974 staticHandler = derived.staticHandler;
8975 errorHandler = derived.errorHandler;
8976 } else if (!routes || !serverMode || !staticHandler || !errorHandler) {
8977 let derived = derive(_build, mode);
8978 routes = derived.routes;
8979 serverMode = derived.serverMode;
8980 staticHandler = derived.staticHandler;
8981 errorHandler = derived.errorHandler;
8982 }
8983 let url = new URL(request.url);
8984 let params = {};
8985 let handleError = (error) => {
8986 if (mode === "development" /* Development */) {
8987 getDevServerHooks()?.processRequestError?.(error);
8988 }
8989 errorHandler(error, {
8990 context: loadContext,
8991 params,
8992 request
8993 });
8994 };
8995 let manifestUrl = `${_build.basename ?? "/"}/__manifest`.replace(
8996 /\/+/g,
8997 "/"
8998 );
8999 if (url.pathname === manifestUrl) {
9000 try {
9001 let res = await handleManifestRequest(_build, routes, url);
9002 return res;
9003 } catch (e) {
9004 handleError(e);
9005 return new Response("Unknown Server Error", { status: 500 });
9006 }
9007 }
9008 let matches = matchServerRoutes(routes, url.pathname, _build.basename);
9009 if (matches && matches.length > 0) {
9010 Object.assign(params, matches[0].params);
9011 }
9012 let response;
9013 if (url.pathname.endsWith(".data")) {
9014 let handlerUrl = new URL(request.url);
9015 handlerUrl.pathname = handlerUrl.pathname.replace(/\.data$/, "").replace(/^\/_root$/, "/");
9016 let singleFetchMatches = matchServerRoutes(
9017 routes,
9018 handlerUrl.pathname,
9019 _build.basename
9020 );
9021 response = await handleSingleFetchRequest(
9022 serverMode,
9023 _build,
9024 staticHandler,
9025 request,
9026 handlerUrl,
9027 loadContext,
9028 handleError
9029 );
9030 if (_build.entry.module.handleDataRequest) {
9031 response = await _build.entry.module.handleDataRequest(response, {
9032 context: loadContext,
9033 params: singleFetchMatches ? singleFetchMatches[0].params : {},
9034 request
9035 });
9036 if (isRedirectResponse(response)) {
9037 let result = getSingleFetchRedirect(
9038 response.status,
9039 response.headers,
9040 _build.basename
9041 );
9042 if (request.method === "GET") {
9043 result = {
9044 [SingleFetchRedirectSymbol]: result
9045 };
9046 }
9047 let headers = new Headers(response.headers);
9048 headers.set("Content-Type", "text/x-script");
9049 return new Response(
9050 encodeViaTurboStream(
9051 result,
9052 request.signal,
9053 _build.entry.module.streamTimeout,
9054 serverMode
9055 ),
9056 {
9057 status: SINGLE_FETCH_REDIRECT_STATUS,
9058 headers
9059 }
9060 );
9061 }
9062 }
9063 } else if (matches && matches[matches.length - 1].route.module.default == null && matches[matches.length - 1].route.module.ErrorBoundary == null) {
9064 response = await handleResourceRequest(
9065 serverMode,
9066 staticHandler,
9067 matches.slice(-1)[0].route.id,
9068 request,
9069 loadContext,
9070 handleError
9071 );
9072 } else {
9073 let criticalCss = mode === "development" /* Development */ ? await getDevServerHooks()?.getCriticalCss?.(_build, url.pathname) : void 0;
9074 response = await handleDocumentRequest(
9075 serverMode,
9076 _build,
9077 staticHandler,
9078 request,
9079 loadContext,
9080 handleError,
9081 criticalCss
9082 );
9083 }
9084 if (request.method === "HEAD") {
9085 return new Response(null, {
9086 headers: response.headers,
9087 status: response.status,
9088 statusText: response.statusText
9089 });
9090 }
9091 return response;
9092 };
9093};
9094async function handleManifestRequest(build, routes, url) {
9095 let patches = {};
9096 if (url.searchParams.has("p")) {
9097 for (let path of url.searchParams.getAll("p")) {
9098 let matches = matchServerRoutes(routes, path, build.basename);
9099 if (matches) {
9100 for (let match of matches) {
9101 let routeId = match.route.id;
9102 let route = build.assets.routes[routeId];
9103 if (route) {
9104 patches[routeId] = route;
9105 }
9106 }
9107 }
9108 }
9109 return Response.json(patches, {
9110 headers: {
9111 "Cache-Control": "public, max-age=31536000, immutable"
9112 }
9113 });
9114 }
9115 return new Response("Invalid Request", { status: 400 });
9116}
9117async function handleSingleFetchRequest(serverMode, build, staticHandler, request, handlerUrl, loadContext, handleError) {
9118 let { result, headers, status } = request.method !== "GET" ? await singleFetchAction(
9119 build,
9120 serverMode,
9121 staticHandler,
9122 request,
9123 handlerUrl,
9124 loadContext,
9125 handleError
9126 ) : await singleFetchLoaders(
9127 build,
9128 serverMode,
9129 staticHandler,
9130 request,
9131 handlerUrl,
9132 loadContext,
9133 handleError
9134 );
9135 let resultHeaders = new Headers(headers);
9136 resultHeaders.set("X-Remix-Response", "yes");
9137 if (NO_BODY_STATUS_CODES.has(status)) {
9138 return new Response(null, { status, headers: resultHeaders });
9139 }
9140 resultHeaders.set("Content-Type", "text/x-script");
9141 return new Response(
9142 encodeViaTurboStream(
9143 result,
9144 request.signal,
9145 build.entry.module.streamTimeout,
9146 serverMode
9147 ),
9148 {
9149 status: status || 200,
9150 headers: resultHeaders
9151 }
9152 );
9153}
9154async function handleDocumentRequest(serverMode, build, staticHandler, request, loadContext, handleError, criticalCss) {
9155 let context;
9156 try {
9157 context = await staticHandler.query(request, {
9158 requestContext: loadContext
9159 });
9160 } catch (error) {
9161 handleError(error);
9162 return new Response(null, { status: 500 });
9163 }
9164 if (isResponse(context)) {
9165 return context;
9166 }
9167 let headers = getDocumentHeaders(build, context);
9168 if (NO_BODY_STATUS_CODES.has(context.statusCode)) {
9169 return new Response(null, { status: context.statusCode, headers });
9170 }
9171 if (context.errors) {
9172 Object.values(context.errors).forEach((err) => {
9173 if (!isRouteErrorResponse(err) || err.error) {
9174 handleError(err);
9175 }
9176 });
9177 context.errors = sanitizeErrors(context.errors, serverMode);
9178 }
9179 let state = {
9180 loaderData: context.loaderData,
9181 actionData: context.actionData,
9182 errors: serializeErrors2(context.errors, serverMode)
9183 };
9184 let entryContext = {
9185 manifest: build.assets,
9186 routeModules: createEntryRouteModules(build.routes),
9187 staticHandlerContext: context,
9188 criticalCss,
9189 serverHandoffString: createServerHandoffString({
9190 basename: build.basename,
9191 criticalCss,
9192 future: build.future,
9193 isSpaMode: build.isSpaMode
9194 }),
9195 serverHandoffStream: encodeViaTurboStream(
9196 state,
9197 request.signal,
9198 build.entry.module.streamTimeout,
9199 serverMode
9200 ),
9201 renderMeta: {},
9202 future: build.future,
9203 isSpaMode: build.isSpaMode,
9204 serializeError: (err) => serializeError(err, serverMode)
9205 };
9206 let handleDocumentRequestFunction = build.entry.module.default;
9207 try {
9208 return await handleDocumentRequestFunction(
9209 request,
9210 context.statusCode,
9211 headers,
9212 entryContext,
9213 loadContext
9214 );
9215 } catch (error) {
9216 handleError(error);
9217 let errorForSecondRender = error;
9218 if (isResponse(error)) {
9219 try {
9220 let data2 = await unwrapResponse(error);
9221 errorForSecondRender = new ErrorResponseImpl(
9222 error.status,
9223 error.statusText,
9224 data2
9225 );
9226 } catch (e) {
9227 }
9228 }
9229 context = getStaticContextFromError(
9230 staticHandler.dataRoutes,
9231 context,
9232 errorForSecondRender
9233 );
9234 if (context.errors) {
9235 context.errors = sanitizeErrors(context.errors, serverMode);
9236 }
9237 let state2 = {
9238 loaderData: context.loaderData,
9239 actionData: context.actionData,
9240 errors: serializeErrors2(context.errors, serverMode)
9241 };
9242 entryContext = {
9243 ...entryContext,
9244 staticHandlerContext: context,
9245 serverHandoffString: createServerHandoffString({
9246 basename: build.basename,
9247 future: build.future,
9248 isSpaMode: build.isSpaMode
9249 }),
9250 serverHandoffStream: encodeViaTurboStream(
9251 state2,
9252 request.signal,
9253 build.entry.module.streamTimeout,
9254 serverMode
9255 ),
9256 renderMeta: {}
9257 };
9258 try {
9259 return await handleDocumentRequestFunction(
9260 request,
9261 context.statusCode,
9262 headers,
9263 entryContext,
9264 loadContext
9265 );
9266 } catch (error2) {
9267 handleError(error2);
9268 return returnLastResortErrorResponse(error2, serverMode);
9269 }
9270 }
9271}
9272async function handleResourceRequest(serverMode, staticHandler, routeId, request, loadContext, handleError) {
9273 try {
9274 let response = await staticHandler.queryRoute(request, {
9275 routeId,
9276 requestContext: loadContext
9277 });
9278 if (isResponse(response)) {
9279 return response;
9280 }
9281 if (typeof response === "string") {
9282 return new Response(response);
9283 }
9284 return Response.json(response);
9285 } catch (error) {
9286 if (isResponse(error)) {
9287 error.headers.set("X-Remix-Catch", "yes");
9288 return error;
9289 }
9290 if (isRouteErrorResponse(error)) {
9291 if (error) {
9292 handleError(error);
9293 }
9294 return errorResponseToJson(error, serverMode);
9295 }
9296 handleError(error);
9297 return returnLastResortErrorResponse(error, serverMode);
9298 }
9299}
9300function errorResponseToJson(errorResponse, serverMode) {
9301 return Response.json(
9302 serializeError(
9303 // @ts-expect-error This is "private" from users but intended for internal use
9304 errorResponse.error || new Error("Unexpected Server Error"),
9305 serverMode
9306 ),
9307 {
9308 status: errorResponse.status,
9309 statusText: errorResponse.statusText,
9310 headers: {
9311 "X-Remix-Error": "yes"
9312 }
9313 }
9314 );
9315}
9316function returnLastResortErrorResponse(error, serverMode) {
9317 let message = "Unexpected Server Error";
9318 if (serverMode !== "production" /* Production */) {
9319 message += `
9320
9321${String(error)}`;
9322 }
9323 return new Response(message, {
9324 status: 500,
9325 headers: {
9326 "Content-Type": "text/plain"
9327 }
9328 });
9329}
9330function unwrapResponse(response) {
9331 let contentType = response.headers.get("Content-Type");
9332 return contentType && /\bapplication\/json\b/.test(contentType) ? response.body == null ? null : response.json() : response.text();
9333}
9334
9335// lib/server-runtime/sessions.ts
9336function flash(name) {
9337 return `__flash_${name}__`;
9338}
9339var createSession = (initialData = {}, id = "") => {
9340 let map = new Map(Object.entries(initialData));
9341 return {
9342 get id() {
9343 return id;
9344 },
9345 get data() {
9346 return Object.fromEntries(map);
9347 },
9348 has(name) {
9349 return map.has(name) || map.has(flash(name));
9350 },
9351 get(name) {
9352 if (map.has(name)) return map.get(name);
9353 let flashName = flash(name);
9354 if (map.has(flashName)) {
9355 let value = map.get(flashName);
9356 map.delete(flashName);
9357 return value;
9358 }
9359 return void 0;
9360 },
9361 set(name, value) {
9362 map.set(name, value);
9363 },
9364 flash(name, value) {
9365 map.set(flash(name), value);
9366 },
9367 unset(name) {
9368 map.delete(name);
9369 }
9370 };
9371};
9372var isSession = (object) => {
9373 return object != null && typeof object.id === "string" && typeof object.data !== "undefined" && typeof object.has === "function" && typeof object.get === "function" && typeof object.set === "function" && typeof object.flash === "function" && typeof object.unset === "function";
9374};
9375function createSessionStorage({
9376 cookie: cookieArg,
9377 createData,
9378 readData,
9379 updateData,
9380 deleteData
9381}) {
9382 let cookie = isCookie(cookieArg) ? cookieArg : createCookie(cookieArg?.name || "__session", cookieArg);
9383 warnOnceAboutSigningSessionCookie(cookie);
9384 return {
9385 async getSession(cookieHeader, options) {
9386 let id = cookieHeader && await cookie.parse(cookieHeader, options);
9387 let data2 = id && await readData(id);
9388 return createSession(data2 || {}, id || "");
9389 },
9390 async commitSession(session, options) {
9391 let { id, data: data2 } = session;
9392 let expires = options?.maxAge != null ? new Date(Date.now() + options.maxAge * 1e3) : options?.expires != null ? options.expires : cookie.expires;
9393 if (id) {
9394 await updateData(id, data2, expires);
9395 } else {
9396 id = await createData(data2, expires);
9397 }
9398 return cookie.serialize(id, options);
9399 },
9400 async destroySession(session, options) {
9401 await deleteData(session.id);
9402 return cookie.serialize("", {
9403 ...options,
9404 maxAge: void 0,
9405 expires: /* @__PURE__ */ new Date(0)
9406 });
9407 }
9408 };
9409}
9410function warnOnceAboutSigningSessionCookie(cookie) {
9411 warnOnce(
9412 cookie.isSigned,
9413 `The "${cookie.name}" cookie is not signed, but session cookies should be signed to prevent tampering on the client before they are sent back to the server. See https://remix.run/utils/cookies#signing-cookies for more information.`
9414 );
9415}
9416
9417// lib/server-runtime/sessions/cookieStorage.ts
9418function createCookieSessionStorage({ cookie: cookieArg } = {}) {
9419 let cookie = isCookie(cookieArg) ? cookieArg : createCookie(cookieArg?.name || "__session", cookieArg);
9420 warnOnceAboutSigningSessionCookie(cookie);
9421 return {
9422 async getSession(cookieHeader, options) {
9423 return createSession(
9424 cookieHeader && await cookie.parse(cookieHeader, options) || {}
9425 );
9426 },
9427 async commitSession(session, options) {
9428 let serializedCookie = await cookie.serialize(session.data, options);
9429 if (serializedCookie.length > 4096) {
9430 throw new Error(
9431 "Cookie length will exceed browser maximum. Length: " + serializedCookie.length
9432 );
9433 }
9434 return serializedCookie;
9435 },
9436 async destroySession(_session, options) {
9437 return cookie.serialize("", {
9438 ...options,
9439 maxAge: void 0,
9440 expires: /* @__PURE__ */ new Date(0)
9441 });
9442 }
9443 };
9444}
9445
9446// lib/server-runtime/sessions/memoryStorage.ts
9447function createMemorySessionStorage({ cookie } = {}) {
9448 let map = /* @__PURE__ */ new Map();
9449 return createSessionStorage({
9450 cookie,
9451 async createData(data2, expires) {
9452 let id = Math.random().toString(36).substring(2, 10);
9453 map.set(id, { data: data2, expires });
9454 return id;
9455 },
9456 async readData(id) {
9457 if (map.has(id)) {
9458 let { data: data2, expires } = map.get(id);
9459 if (!expires || expires > /* @__PURE__ */ new Date()) {
9460 return data2;
9461 }
9462 if (expires) map.delete(id);
9463 }
9464 return null;
9465 },
9466 async updateData(id, data2, expires) {
9467 map.set(id, { data: data2, expires });
9468 },
9469 async deleteData(id) {
9470 map.delete(id);
9471 }
9472 });
9473}
9474
9475// lib/dom/ssr/errors.ts
9476function deserializeErrors2(errors) {
9477 if (!errors) return null;
9478 let entries = Object.entries(errors);
9479 let serialized = {};
9480 for (let [key, val] of entries) {
9481 if (val && val.__type === "RouteErrorResponse") {
9482 serialized[key] = new ErrorResponseImpl(
9483 val.status,
9484 val.statusText,
9485 val.data,
9486 val.internal === true
9487 );
9488 } else if (val && val.__type === "Error") {
9489 if (val.__subType) {
9490 let ErrorConstructor = window[val.__subType];
9491 if (typeof ErrorConstructor === "function") {
9492 try {
9493 let error = new ErrorConstructor(val.message);
9494 error.stack = val.stack;
9495 serialized[key] = error;
9496 } catch (e) {
9497 }
9498 }
9499 }
9500 if (serialized[key] == null) {
9501 let error = new Error(val.message);
9502 error.stack = val.stack;
9503 serialized[key] = error;
9504 }
9505 } else {
9506 serialized[key] = val;
9507 }
9508 }
9509 return serialized;
9510}
9511
9512export {
9513 Action,
9514 createBrowserHistory,
9515 invariant,
9516 createPath,
9517 parsePath,
9518 matchRoutes,
9519 generatePath,
9520 matchPath,
9521 resolvePath,
9522 data,
9523 redirect,
9524 redirectDocument,
9525 replace,
9526 ErrorResponseImpl,
9527 isRouteErrorResponse,
9528 IDLE_NAVIGATION,
9529 IDLE_FETCHER,
9530 IDLE_BLOCKER,
9531 createRouter,
9532 DataRouterContext,
9533 DataRouterStateContext,
9534 ViewTransitionContext,
9535 FetchersContext,
9536 NavigationContext,
9537 LocationContext,
9538 RouteContext,
9539 useHref,
9540 useInRouterContext,
9541 useLocation,
9542 useNavigationType,
9543 useMatch,
9544 useNavigate,
9545 useOutletContext,
9546 useOutlet,
9547 useParams,
9548 useResolvedPath,
9549 useRoutes,
9550 useNavigation,
9551 useRevalidator,
9552 useMatches,
9553 useLoaderData,
9554 useRouteLoaderData,
9555 useActionData,
9556 useRouteError,
9557 useAsyncValue,
9558 useAsyncError,
9559 useBlocker,
9560 mapRouteProperties,
9561 createMemoryRouter,
9562 RouterProvider,
9563 MemoryRouter,
9564 Navigate,
9565 Outlet,
9566 Route,
9567 Router,
9568 Routes,
9569 Await,
9570 createRoutesFromChildren,
9571 createRoutesFromElements,
9572 renderMatches,
9573 createSearchParams,
9574 SingleFetchRedirectSymbol,
9575 getSingleFetchDataStrategy,
9576 decodeViaTurboStream,
9577 RemixErrorBoundary,
9578 createClientRoutesWithHMRRevalidationOptOut,
9579 createClientRoutes,
9580 shouldHydrateRouteLoader,
9581 getPatchRoutesOnNavigationFunction,
9582 useFogOFWarDiscovery,
9583 FrameworkContext,
9584 Links,
9585 PrefetchPageLinks,
9586 Meta,
9587 Scripts,
9588 createBrowserRouter,
9589 createHashRouter,
9590 BrowserRouter,
9591 HashRouter,
9592 HistoryRouter,
9593 Link,
9594 NavLink,
9595 Form,
9596 ScrollRestoration,
9597 useLinkClickHandler,
9598 useSearchParams,
9599 useSubmit,
9600 useFormAction,
9601 useFetcher,
9602 useFetchers,
9603 useScrollRestoration,
9604 useBeforeUnload,
9605 usePrompt,
9606 useViewTransitionState,
9607 StaticRouter,
9608 StaticRouterProvider,
9609 createStaticHandler2 as createStaticHandler,
9610 createStaticRouter,
9611 ServerRouter,
9612 createRoutesStub,
9613 createCookie,
9614 isCookie,
9615 ServerMode,
9616 setDevServerHooks,
9617 createRequestHandler,
9618 createSession,
9619 isSession,
9620 createSessionStorage,
9621 createCookieSessionStorage,
9622 createMemorySessionStorage,
9623 deserializeErrors2 as deserializeErrors
9624};