UNPKG

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