UNPKG

309 kBJavaScriptView Raw
1/**
2 * react-router v7.0.1
3 *
4 * Copyright (c) Remix Software Inc.
5 *
6 * This source code is licensed under the MIT license found in the
7 * LICENSE.md file in the root directory of this source tree.
8 *
9 * @license MIT
10 */
11
12// lib/router/history.ts
13var Action = /* @__PURE__ */ ((Action2) => {
14 Action2["Pop"] = "POP";
15 Action2["Push"] = "PUSH";
16 Action2["Replace"] = "REPLACE";
17 return Action2;
18})(Action || {});
19var PopStateEventType = "popstate";
20function createMemoryHistory(options = {}) {
21 let { initialEntries = ["/"], initialIndex, v5Compat = false } = options;
22 let entries;
23 entries = initialEntries.map(
24 (entry, index2) => createMemoryLocation(
25 entry,
26 typeof entry === "string" ? null : entry.state,
27 index2 === 0 ? "default" : void 0
28 )
29 );
30 let index = clampIndex(
31 initialIndex == null ? entries.length - 1 : initialIndex
32 );
33 let action = "POP" /* Pop */;
34 let listener = null;
35 function clampIndex(n) {
36 return Math.min(Math.max(n, 0), entries.length - 1);
37 }
38 function getCurrentLocation() {
39 return entries[index];
40 }
41 function createMemoryLocation(to, state = null, key) {
42 let location = createLocation(
43 entries ? getCurrentLocation().pathname : "/",
44 to,
45 state,
46 key
47 );
48 warning(
49 location.pathname.charAt(0) === "/",
50 `relative pathnames are not supported in memory history: ${JSON.stringify(
51 to
52 )}`
53 );
54 return location;
55 }
56 function createHref2(to) {
57 return typeof to === "string" ? to : createPath(to);
58 }
59 let history = {
60 get index() {
61 return index;
62 },
63 get action() {
64 return action;
65 },
66 get location() {
67 return getCurrentLocation();
68 },
69 createHref: createHref2,
70 createURL(to) {
71 return new URL(createHref2(to), "http://localhost");
72 },
73 encodeLocation(to) {
74 let path = typeof to === "string" ? parsePath(to) : to;
75 return {
76 pathname: path.pathname || "",
77 search: path.search || "",
78 hash: path.hash || ""
79 };
80 },
81 push(to, state) {
82 action = "PUSH" /* Push */;
83 let nextLocation = createMemoryLocation(to, state);
84 index += 1;
85 entries.splice(index, entries.length, nextLocation);
86 if (v5Compat && listener) {
87 listener({ action, location: nextLocation, delta: 1 });
88 }
89 },
90 replace(to, state) {
91 action = "REPLACE" /* Replace */;
92 let nextLocation = createMemoryLocation(to, state);
93 entries[index] = nextLocation;
94 if (v5Compat && listener) {
95 listener({ action, location: nextLocation, delta: 0 });
96 }
97 },
98 go(delta) {
99 action = "POP" /* Pop */;
100 let nextIndex = clampIndex(index + delta);
101 let nextLocation = entries[nextIndex];
102 index = nextIndex;
103 if (listener) {
104 listener({ action, location: nextLocation, delta });
105 }
106 },
107 listen(fn) {
108 listener = fn;
109 return () => {
110 listener = null;
111 };
112 }
113 };
114 return history;
115}
116function createBrowserHistory(options = {}) {
117 function createBrowserLocation(window2, globalHistory) {
118 let { pathname, search, hash } = window2.location;
119 return createLocation(
120 "",
121 { pathname, search, hash },
122 // state defaults to `null` because `window.history.state` does
123 globalHistory.state && globalHistory.state.usr || null,
124 globalHistory.state && globalHistory.state.key || "default"
125 );
126 }
127 function createBrowserHref(window2, to) {
128 return typeof to === "string" ? to : createPath(to);
129 }
130 return getUrlBasedHistory(
131 createBrowserLocation,
132 createBrowserHref,
133 null,
134 options
135 );
136}
137function createHashHistory(options = {}) {
138 function createHashLocation(window2, globalHistory) {
139 let {
140 pathname = "/",
141 search = "",
142 hash = ""
143 } = parsePath(window2.location.hash.substring(1));
144 if (!pathname.startsWith("/") && !pathname.startsWith(".")) {
145 pathname = "/" + pathname;
146 }
147 return createLocation(
148 "",
149 { pathname, search, hash },
150 // state defaults to `null` because `window.history.state` does
151 globalHistory.state && globalHistory.state.usr || null,
152 globalHistory.state && globalHistory.state.key || "default"
153 );
154 }
155 function createHashHref(window2, to) {
156 let base = window2.document.querySelector("base");
157 let href = "";
158 if (base && base.getAttribute("href")) {
159 let url = window2.location.href;
160 let hashIndex = url.indexOf("#");
161 href = hashIndex === -1 ? url : url.slice(0, hashIndex);
162 }
163 return href + "#" + (typeof to === "string" ? to : createPath(to));
164 }
165 function validateHashLocation(location, to) {
166 warning(
167 location.pathname.charAt(0) === "/",
168 `relative pathnames are not supported in hash history.push(${JSON.stringify(
169 to
170 )})`
171 );
172 }
173 return getUrlBasedHistory(
174 createHashLocation,
175 createHashHref,
176 validateHashLocation,
177 options
178 );
179}
180function invariant(value, message) {
181 if (value === false || value === null || typeof value === "undefined") {
182 throw new Error(message);
183 }
184}
185function warning(cond, message) {
186 if (!cond) {
187 if (typeof console !== "undefined") console.warn(message);
188 try {
189 throw new Error(message);
190 } catch (e) {
191 }
192 }
193}
194function createKey() {
195 return Math.random().toString(36).substring(2, 10);
196}
197function getHistoryState(location, index) {
198 return {
199 usr: location.state,
200 key: location.key,
201 idx: index
202 };
203}
204function createLocation(current, to, state = null, key) {
205 let location = {
206 pathname: typeof current === "string" ? current : current.pathname,
207 search: "",
208 hash: "",
209 ...typeof to === "string" ? parsePath(to) : to,
210 state,
211 // TODO: This could be cleaned up. push/replace should probably just take
212 // full Locations now and avoid the need to run through this flow at all
213 // But that's a pretty big refactor to the current test suite so going to
214 // keep as is for the time being and just let any incoming keys take precedence
215 key: to && to.key || key || createKey()
216 };
217 return location;
218}
219function createPath({
220 pathname = "/",
221 search = "",
222 hash = ""
223}) {
224 if (search && search !== "?")
225 pathname += search.charAt(0) === "?" ? search : "?" + search;
226 if (hash && hash !== "#")
227 pathname += hash.charAt(0) === "#" ? hash : "#" + hash;
228 return pathname;
229}
230function parsePath(path) {
231 let parsedPath = {};
232 if (path) {
233 let hashIndex = path.indexOf("#");
234 if (hashIndex >= 0) {
235 parsedPath.hash = path.substring(hashIndex);
236 path = path.substring(0, hashIndex);
237 }
238 let searchIndex = path.indexOf("?");
239 if (searchIndex >= 0) {
240 parsedPath.search = path.substring(searchIndex);
241 path = path.substring(0, searchIndex);
242 }
243 if (path) {
244 parsedPath.pathname = path;
245 }
246 }
247 return parsedPath;
248}
249function getUrlBasedHistory(getLocation, createHref2, validateLocation, options = {}) {
250 let { window: window2 = document.defaultView, v5Compat = false } = options;
251 let globalHistory = window2.history;
252 let action = "POP" /* Pop */;
253 let listener = null;
254 let index = getIndex();
255 if (index == null) {
256 index = 0;
257 globalHistory.replaceState({ ...globalHistory.state, idx: index }, "");
258 }
259 function getIndex() {
260 let state = globalHistory.state || { idx: null };
261 return state.idx;
262 }
263 function handlePop() {
264 action = "POP" /* Pop */;
265 let nextIndex = getIndex();
266 let delta = nextIndex == null ? null : nextIndex - index;
267 index = nextIndex;
268 if (listener) {
269 listener({ action, location: history.location, delta });
270 }
271 }
272 function push(to, state) {
273 action = "PUSH" /* Push */;
274 let location = createLocation(history.location, to, state);
275 if (validateLocation) validateLocation(location, to);
276 index = getIndex() + 1;
277 let historyState = getHistoryState(location, index);
278 let url = history.createHref(location);
279 try {
280 globalHistory.pushState(historyState, "", url);
281 } catch (error) {
282 if (error instanceof DOMException && error.name === "DataCloneError") {
283 throw error;
284 }
285 window2.location.assign(url);
286 }
287 if (v5Compat && listener) {
288 listener({ action, location: history.location, delta: 1 });
289 }
290 }
291 function replace2(to, state) {
292 action = "REPLACE" /* Replace */;
293 let location = createLocation(history.location, to, state);
294 if (validateLocation) validateLocation(location, to);
295 index = getIndex();
296 let historyState = getHistoryState(location, index);
297 let url = history.createHref(location);
298 globalHistory.replaceState(historyState, "", url);
299 if (v5Compat && listener) {
300 listener({ action, location: history.location, delta: 0 });
301 }
302 }
303 function createURL(to) {
304 let base = window2.location.origin !== "null" ? window2.location.origin : window2.location.href;
305 let href = typeof to === "string" ? to : createPath(to);
306 href = href.replace(/ $/, "%20");
307 invariant(
308 base,
309 `No window.location.(origin|href) available to create URL for href: ${href}`
310 );
311 return new URL(href, base);
312 }
313 let history = {
314 get action() {
315 return action;
316 },
317 get location() {
318 return getLocation(window2, globalHistory);
319 },
320 listen(fn) {
321 if (listener) {
322 throw new Error("A history only accepts one active listener");
323 }
324 window2.addEventListener(PopStateEventType, handlePop);
325 listener = fn;
326 return () => {
327 window2.removeEventListener(PopStateEventType, handlePop);
328 listener = null;
329 };
330 },
331 createHref(to) {
332 return createHref2(window2, to);
333 },
334 createURL,
335 encodeLocation(to) {
336 let url = createURL(to);
337 return {
338 pathname: url.pathname,
339 search: url.search,
340 hash: url.hash
341 };
342 },
343 push,
344 replace: replace2,
345 go(n) {
346 return globalHistory.go(n);
347 }
348 };
349 return history;
350}
351
352// lib/router/utils.ts
353var immutableRouteKeys = /* @__PURE__ */ new Set([
354 "lazy",
355 "caseSensitive",
356 "path",
357 "id",
358 "index",
359 "children"
360]);
361function isIndexRoute(route) {
362 return route.index === true;
363}
364function convertRoutesToDataRoutes(routes, mapRouteProperties2, parentPath = [], manifest = {}) {
365 return routes.map((route, index) => {
366 let treePath = [...parentPath, String(index)];
367 let id = typeof route.id === "string" ? route.id : treePath.join("-");
368 invariant(
369 route.index !== true || !route.children,
370 `Cannot specify children on an index route`
371 );
372 invariant(
373 !manifest[id],
374 `Found a route id collision on id "${id}". Route id's must be globally unique within Data Router usages`
375 );
376 if (isIndexRoute(route)) {
377 let indexRoute = {
378 ...route,
379 ...mapRouteProperties2(route),
380 id
381 };
382 manifest[id] = indexRoute;
383 return indexRoute;
384 } else {
385 let pathOrLayoutRoute = {
386 ...route,
387 ...mapRouteProperties2(route),
388 id,
389 children: void 0
390 };
391 manifest[id] = pathOrLayoutRoute;
392 if (route.children) {
393 pathOrLayoutRoute.children = convertRoutesToDataRoutes(
394 route.children,
395 mapRouteProperties2,
396 treePath,
397 manifest
398 );
399 }
400 return pathOrLayoutRoute;
401 }
402 });
403}
404function matchRoutes(routes, locationArg, basename = "/") {
405 return matchRoutesImpl(routes, locationArg, basename, false);
406}
407function matchRoutesImpl(routes, locationArg, basename, allowPartial) {
408 let location = typeof locationArg === "string" ? parsePath(locationArg) : locationArg;
409 let pathname = stripBasename(location.pathname || "/", basename);
410 if (pathname == null) {
411 return null;
412 }
413 let branches = flattenRoutes(routes);
414 rankRouteBranches(branches);
415 let matches = null;
416 for (let i = 0; matches == null && i < branches.length; ++i) {
417 let decoded = decodePath(pathname);
418 matches = matchRouteBranch(
419 branches[i],
420 decoded,
421 allowPartial
422 );
423 }
424 return matches;
425}
426function convertRouteMatchToUiMatch(match, loaderData) {
427 let { route, pathname, params } = match;
428 return {
429 id: route.id,
430 pathname,
431 params,
432 data: loaderData[route.id],
433 handle: route.handle
434 };
435}
436function flattenRoutes(routes, branches = [], parentsMeta = [], parentPath = "") {
437 let flattenRoute = (route, index, relativePath) => {
438 let meta = {
439 relativePath: relativePath === void 0 ? route.path || "" : relativePath,
440 caseSensitive: route.caseSensitive === true,
441 childrenIndex: index,
442 route
443 };
444 if (meta.relativePath.startsWith("/")) {
445 invariant(
446 meta.relativePath.startsWith(parentPath),
447 `Absolute route path "${meta.relativePath}" nested under path "${parentPath}" is not valid. An absolute child route path must start with the combined path of all its parent routes.`
448 );
449 meta.relativePath = meta.relativePath.slice(parentPath.length);
450 }
451 let path = joinPaths([parentPath, meta.relativePath]);
452 let routesMeta = parentsMeta.concat(meta);
453 if (route.children && route.children.length > 0) {
454 invariant(
455 // Our types know better, but runtime JS may not!
456 // @ts-expect-error
457 route.index !== true,
458 `Index routes must not have child routes. Please remove all child routes from route path "${path}".`
459 );
460 flattenRoutes(route.children, branches, routesMeta, path);
461 }
462 if (route.path == null && !route.index) {
463 return;
464 }
465 branches.push({
466 path,
467 score: computeScore(path, route.index),
468 routesMeta
469 });
470 };
471 routes.forEach((route, index) => {
472 if (route.path === "" || !route.path?.includes("?")) {
473 flattenRoute(route, index);
474 } else {
475 for (let exploded of explodeOptionalSegments(route.path)) {
476 flattenRoute(route, index, exploded);
477 }
478 }
479 });
480 return branches;
481}
482function explodeOptionalSegments(path) {
483 let segments = path.split("/");
484 if (segments.length === 0) return [];
485 let [first, ...rest] = segments;
486 let isOptional = first.endsWith("?");
487 let required = first.replace(/\?$/, "");
488 if (rest.length === 0) {
489 return isOptional ? [required, ""] : [required];
490 }
491 let restExploded = explodeOptionalSegments(rest.join("/"));
492 let result = [];
493 result.push(
494 ...restExploded.map(
495 (subpath) => subpath === "" ? required : [required, subpath].join("/")
496 )
497 );
498 if (isOptional) {
499 result.push(...restExploded);
500 }
501 return result.map(
502 (exploded) => path.startsWith("/") && exploded === "" ? "/" : exploded
503 );
504}
505function rankRouteBranches(branches) {
506 branches.sort(
507 (a, b) => a.score !== b.score ? b.score - a.score : compareIndexes(
508 a.routesMeta.map((meta) => meta.childrenIndex),
509 b.routesMeta.map((meta) => meta.childrenIndex)
510 )
511 );
512}
513var paramRe = /^:[\w-]+$/;
514var dynamicSegmentValue = 3;
515var indexRouteValue = 2;
516var emptySegmentValue = 1;
517var staticSegmentValue = 10;
518var splatPenalty = -2;
519var isSplat = (s) => s === "*";
520function computeScore(path, index) {
521 let segments = path.split("/");
522 let initialScore = segments.length;
523 if (segments.some(isSplat)) {
524 initialScore += splatPenalty;
525 }
526 if (index) {
527 initialScore += indexRouteValue;
528 }
529 return segments.filter((s) => !isSplat(s)).reduce(
530 (score, segment) => score + (paramRe.test(segment) ? dynamicSegmentValue : segment === "" ? emptySegmentValue : staticSegmentValue),
531 initialScore
532 );
533}
534function compareIndexes(a, b) {
535 let siblings = a.length === b.length && a.slice(0, -1).every((n, i) => n === b[i]);
536 return siblings ? (
537 // If two routes are siblings, we should try to match the earlier sibling
538 // first. This allows people to have fine-grained control over the matching
539 // behavior by simply putting routes with identical paths in the order they
540 // want them tried.
541 a[a.length - 1] - b[b.length - 1]
542 ) : (
543 // Otherwise, it doesn't really make sense to rank non-siblings by index,
544 // so they sort equally.
545 0
546 );
547}
548function matchRouteBranch(branch, pathname, allowPartial = false) {
549 let { routesMeta } = branch;
550 let matchedParams = {};
551 let matchedPathname = "/";
552 let matches = [];
553 for (let i = 0; i < routesMeta.length; ++i) {
554 let meta = routesMeta[i];
555 let end = i === routesMeta.length - 1;
556 let remainingPathname = matchedPathname === "/" ? pathname : pathname.slice(matchedPathname.length) || "/";
557 let match = matchPath(
558 { path: meta.relativePath, caseSensitive: meta.caseSensitive, end },
559 remainingPathname
560 );
561 let route = meta.route;
562 if (!match && end && allowPartial && !routesMeta[routesMeta.length - 1].route.index) {
563 match = matchPath(
564 {
565 path: meta.relativePath,
566 caseSensitive: meta.caseSensitive,
567 end: false
568 },
569 remainingPathname
570 );
571 }
572 if (!match) {
573 return null;
574 }
575 Object.assign(matchedParams, match.params);
576 matches.push({
577 // TODO: Can this as be avoided?
578 params: matchedParams,
579 pathname: joinPaths([matchedPathname, match.pathname]),
580 pathnameBase: normalizePathname(
581 joinPaths([matchedPathname, match.pathnameBase])
582 ),
583 route
584 });
585 if (match.pathnameBase !== "/") {
586 matchedPathname = joinPaths([matchedPathname, match.pathnameBase]);
587 }
588 }
589 return matches;
590}
591function generatePath(originalPath, params = {}) {
592 let path = originalPath;
593 if (path.endsWith("*") && path !== "*" && !path.endsWith("/*")) {
594 warning(
595 false,
596 `Route path "${path}" will be treated as if it were "${path.replace(/\*$/, "/*")}" because the \`*\` character must always follow a \`/\` in the pattern. To get rid of this warning, please change the route path to "${path.replace(/\*$/, "/*")}".`
597 );
598 path = path.replace(/\*$/, "/*");
599 }
600 const prefix = path.startsWith("/") ? "/" : "";
601 const stringify = (p) => p == null ? "" : typeof p === "string" ? p : String(p);
602 const segments = path.split(/\/+/).map((segment, index, array) => {
603 const isLastSegment = index === array.length - 1;
604 if (isLastSegment && segment === "*") {
605 const star = "*";
606 return stringify(params[star]);
607 }
608 const keyMatch = segment.match(/^:([\w-]+)(\??)$/);
609 if (keyMatch) {
610 const [, key, optional] = keyMatch;
611 let param = params[key];
612 invariant(optional === "?" || param != null, `Missing ":${key}" param`);
613 return stringify(param);
614 }
615 return segment.replace(/\?$/g, "");
616 }).filter((segment) => !!segment);
617 return prefix + segments.join("/");
618}
619function matchPath(pattern, pathname) {
620 if (typeof pattern === "string") {
621 pattern = { path: pattern, caseSensitive: false, end: true };
622 }
623 let [matcher, compiledParams] = compilePath(
624 pattern.path,
625 pattern.caseSensitive,
626 pattern.end
627 );
628 let match = pathname.match(matcher);
629 if (!match) return null;
630 let matchedPathname = match[0];
631 let pathnameBase = matchedPathname.replace(/(.)\/+$/, "$1");
632 let captureGroups = match.slice(1);
633 let params = compiledParams.reduce(
634 (memo2, { paramName, isOptional }, index) => {
635 if (paramName === "*") {
636 let splatValue = captureGroups[index] || "";
637 pathnameBase = matchedPathname.slice(0, matchedPathname.length - splatValue.length).replace(/(.)\/+$/, "$1");
638 }
639 const value = captureGroups[index];
640 if (isOptional && !value) {
641 memo2[paramName] = void 0;
642 } else {
643 memo2[paramName] = (value || "").replace(/%2F/g, "/");
644 }
645 return memo2;
646 },
647 {}
648 );
649 return {
650 params,
651 pathname: matchedPathname,
652 pathnameBase,
653 pattern
654 };
655}
656function compilePath(path, caseSensitive = false, end = true) {
657 warning(
658 path === "*" || !path.endsWith("*") || path.endsWith("/*"),
659 `Route path "${path}" will be treated as if it were "${path.replace(/\*$/, "/*")}" because the \`*\` character must always follow a \`/\` in the pattern. To get rid of this warning, please change the route path to "${path.replace(/\*$/, "/*")}".`
660 );
661 let params = [];
662 let regexpSource = "^" + path.replace(/\/*\*?$/, "").replace(/^\/*/, "/").replace(/[\\.*+^${}|()[\]]/g, "\\$&").replace(
663 /\/:([\w-]+)(\?)?/g,
664 (_, paramName, isOptional) => {
665 params.push({ paramName, isOptional: isOptional != null });
666 return isOptional ? "/?([^\\/]+)?" : "/([^\\/]+)";
667 }
668 );
669 if (path.endsWith("*")) {
670 params.push({ paramName: "*" });
671 regexpSource += path === "*" || path === "/*" ? "(.*)$" : "(?:\\/(.+)|\\/*)$";
672 } else if (end) {
673 regexpSource += "\\/*$";
674 } else if (path !== "" && path !== "/") {
675 regexpSource += "(?:(?=\\/|$))";
676 } else {
677 }
678 let matcher = new RegExp(regexpSource, caseSensitive ? void 0 : "i");
679 return [matcher, params];
680}
681function decodePath(value) {
682 try {
683 return value.split("/").map((v) => decodeURIComponent(v).replace(/\//g, "%2F")).join("/");
684 } catch (error) {
685 warning(
686 false,
687 `The URL path "${value}" could not be decoded because it is is a malformed URL segment. This is probably due to a bad percent encoding (${error}).`
688 );
689 return value;
690 }
691}
692function stripBasename(pathname, basename) {
693 if (basename === "/") return pathname;
694 if (!pathname.toLowerCase().startsWith(basename.toLowerCase())) {
695 return null;
696 }
697 let startIndex = basename.endsWith("/") ? basename.length - 1 : basename.length;
698 let nextChar = pathname.charAt(startIndex);
699 if (nextChar && nextChar !== "/") {
700 return null;
701 }
702 return pathname.slice(startIndex) || "/";
703}
704function resolvePath(to, fromPathname = "/") {
705 let {
706 pathname: toPathname,
707 search = "",
708 hash = ""
709 } = typeof to === "string" ? parsePath(to) : to;
710 let pathname = toPathname ? toPathname.startsWith("/") ? toPathname : resolvePathname(toPathname, fromPathname) : fromPathname;
711 return {
712 pathname,
713 search: normalizeSearch(search),
714 hash: normalizeHash(hash)
715 };
716}
717function resolvePathname(relativePath, fromPathname) {
718 let segments = fromPathname.replace(/\/+$/, "").split("/");
719 let relativeSegments = relativePath.split("/");
720 relativeSegments.forEach((segment) => {
721 if (segment === "..") {
722 if (segments.length > 1) segments.pop();
723 } else if (segment !== ".") {
724 segments.push(segment);
725 }
726 });
727 return segments.length > 1 ? segments.join("/") : "/";
728}
729function getInvalidPathError(char, field, dest, path) {
730 return `Cannot include a '${char}' character in a manually specified \`to.${field}\` field [${JSON.stringify(
731 path
732 )}]. Please separate it out to the \`to.${dest}\` field. Alternatively you may provide the full path as a string in <Link to="..."> and the router will parse it for you.`;
733}
734function getPathContributingMatches(matches) {
735 return matches.filter(
736 (match, index) => index === 0 || match.route.path && match.route.path.length > 0
737 );
738}
739function getResolveToMatches(matches) {
740 let pathMatches = getPathContributingMatches(matches);
741 return pathMatches.map(
742 (match, idx) => idx === pathMatches.length - 1 ? match.pathname : match.pathnameBase
743 );
744}
745function resolveTo(toArg, routePathnames, locationPathname, isPathRelative = false) {
746 let to;
747 if (typeof toArg === "string") {
748 to = parsePath(toArg);
749 } else {
750 to = { ...toArg };
751 invariant(
752 !to.pathname || !to.pathname.includes("?"),
753 getInvalidPathError("?", "pathname", "search", to)
754 );
755 invariant(
756 !to.pathname || !to.pathname.includes("#"),
757 getInvalidPathError("#", "pathname", "hash", to)
758 );
759 invariant(
760 !to.search || !to.search.includes("#"),
761 getInvalidPathError("#", "search", "hash", to)
762 );
763 }
764 let isEmptyPath = toArg === "" || to.pathname === "";
765 let toPathname = isEmptyPath ? "/" : to.pathname;
766 let from;
767 if (toPathname == null) {
768 from = locationPathname;
769 } else {
770 let routePathnameIndex = routePathnames.length - 1;
771 if (!isPathRelative && toPathname.startsWith("..")) {
772 let toSegments = toPathname.split("/");
773 while (toSegments[0] === "..") {
774 toSegments.shift();
775 routePathnameIndex -= 1;
776 }
777 to.pathname = toSegments.join("/");
778 }
779 from = routePathnameIndex >= 0 ? routePathnames[routePathnameIndex] : "/";
780 }
781 let path = resolvePath(to, from);
782 let hasExplicitTrailingSlash = toPathname && toPathname !== "/" && toPathname.endsWith("/");
783 let hasCurrentTrailingSlash = (isEmptyPath || toPathname === ".") && locationPathname.endsWith("/");
784 if (!path.pathname.endsWith("/") && (hasExplicitTrailingSlash || hasCurrentTrailingSlash)) {
785 path.pathname += "/";
786 }
787 return path;
788}
789var joinPaths = (paths) => paths.join("/").replace(/\/\/+/g, "/");
790var normalizePathname = (pathname) => pathname.replace(/\/+$/, "").replace(/^\/*/, "/");
791var normalizeSearch = (search) => !search || search === "?" ? "" : search.startsWith("?") ? search : "?" + search;
792var normalizeHash = (hash) => !hash || hash === "#" ? "" : hash.startsWith("#") ? hash : "#" + hash;
793var DataWithResponseInit = class {
794 constructor(data2, init) {
795 this.type = "DataWithResponseInit";
796 this.data = data2;
797 this.init = init || null;
798 }
799};
800function data(data2, init) {
801 return new DataWithResponseInit(
802 data2,
803 typeof init === "number" ? { status: init } : init
804 );
805}
806var redirect = (url, init = 302) => {
807 let responseInit = init;
808 if (typeof responseInit === "number") {
809 responseInit = { status: responseInit };
810 } else if (typeof responseInit.status === "undefined") {
811 responseInit.status = 302;
812 }
813 let headers = new Headers(responseInit.headers);
814 headers.set("Location", url);
815 return new Response(null, {
816 ...responseInit,
817 headers
818 });
819};
820var redirectDocument = (url, init) => {
821 let response = redirect(url, init);
822 response.headers.set("X-Remix-Reload-Document", "true");
823 return response;
824};
825var replace = (url, init) => {
826 let response = redirect(url, init);
827 response.headers.set("X-Remix-Replace", "true");
828 return response;
829};
830var ErrorResponseImpl = class {
831 constructor(status, statusText, data2, internal = false) {
832 this.status = status;
833 this.statusText = statusText || "";
834 this.internal = internal;
835 if (data2 instanceof Error) {
836 this.data = data2.toString();
837 this.error = data2;
838 } else {
839 this.data = data2;
840 }
841 }
842};
843function isRouteErrorResponse(error) {
844 return error != null && typeof error.status === "number" && typeof error.statusText === "string" && typeof error.internal === "boolean" && "data" in error;
845}
846
847// lib/router/router.ts
848var validMutationMethodsArr = [
849 "POST",
850 "PUT",
851 "PATCH",
852 "DELETE"
853];
854var validMutationMethods = new Set(
855 validMutationMethodsArr
856);
857var validRequestMethodsArr = [
858 "GET",
859 ...validMutationMethodsArr
860];
861var validRequestMethods = new Set(validRequestMethodsArr);
862var redirectStatusCodes = /* @__PURE__ */ new Set([301, 302, 303, 307, 308]);
863var redirectPreserveMethodStatusCodes = /* @__PURE__ */ new Set([307, 308]);
864var IDLE_NAVIGATION = {
865 state: "idle",
866 location: void 0,
867 formMethod: void 0,
868 formAction: void 0,
869 formEncType: void 0,
870 formData: void 0,
871 json: void 0,
872 text: void 0
873};
874var IDLE_FETCHER = {
875 state: "idle",
876 data: void 0,
877 formMethod: void 0,
878 formAction: void 0,
879 formEncType: void 0,
880 formData: void 0,
881 json: void 0,
882 text: void 0
883};
884var IDLE_BLOCKER = {
885 state: "unblocked",
886 proceed: void 0,
887 reset: void 0,
888 location: void 0
889};
890var ABSOLUTE_URL_REGEX = /^(?:[a-z][a-z0-9+.-]*:|\/\/)/i;
891var defaultMapRouteProperties = (route) => ({
892 hasErrorBoundary: Boolean(route.hasErrorBoundary)
893});
894var TRANSITIONS_STORAGE_KEY = "remix-router-transitions";
895var ResetLoaderDataSymbol = Symbol("ResetLoaderData");
896function createRouter(init) {
897 const routerWindow = init.window ? init.window : typeof window !== "undefined" ? window : void 0;
898 const isBrowser2 = typeof routerWindow !== "undefined" && typeof routerWindow.document !== "undefined" && typeof routerWindow.document.createElement !== "undefined";
899 invariant(
900 init.routes.length > 0,
901 "You must provide a non-empty routes array to createRouter"
902 );
903 let mapRouteProperties2 = init.mapRouteProperties || defaultMapRouteProperties;
904 let manifest = {};
905 let dataRoutes = convertRoutesToDataRoutes(
906 init.routes,
907 mapRouteProperties2,
908 void 0,
909 manifest
910 );
911 let inFlightDataRoutes;
912 let basename = init.basename || "/";
913 let dataStrategyImpl = init.dataStrategy || defaultDataStrategy;
914 let patchRoutesOnNavigationImpl = init.patchRoutesOnNavigation;
915 let future = {
916 ...init.future
917 };
918 let unlistenHistory = null;
919 let subscribers = /* @__PURE__ */ new Set();
920 let savedScrollPositions2 = null;
921 let getScrollRestorationKey2 = null;
922 let getScrollPosition = null;
923 let initialScrollRestored = init.hydrationData != null;
924 let initialMatches = matchRoutes(dataRoutes, init.history.location, basename);
925 let initialErrors = null;
926 if (initialMatches == null && !patchRoutesOnNavigationImpl) {
927 let error = getInternalRouterError(404, {
928 pathname: init.history.location.pathname
929 });
930 let { matches, route } = getShortCircuitMatches(dataRoutes);
931 initialMatches = matches;
932 initialErrors = { [route.id]: error };
933 }
934 if (initialMatches && !init.hydrationData) {
935 let fogOfWar = checkFogOfWar(
936 initialMatches,
937 dataRoutes,
938 init.history.location.pathname
939 );
940 if (fogOfWar.active) {
941 initialMatches = null;
942 }
943 }
944 let initialized;
945 if (!initialMatches) {
946 initialized = false;
947 initialMatches = [];
948 let fogOfWar = checkFogOfWar(
949 null,
950 dataRoutes,
951 init.history.location.pathname
952 );
953 if (fogOfWar.active && fogOfWar.matches) {
954 initialMatches = fogOfWar.matches;
955 }
956 } else if (initialMatches.some((m) => m.route.lazy)) {
957 initialized = false;
958 } else if (!initialMatches.some((m) => m.route.loader)) {
959 initialized = true;
960 } else {
961 let loaderData = init.hydrationData ? init.hydrationData.loaderData : null;
962 let errors = init.hydrationData ? init.hydrationData.errors : null;
963 if (errors) {
964 let idx = initialMatches.findIndex(
965 (m) => errors[m.route.id] !== void 0
966 );
967 initialized = initialMatches.slice(0, idx + 1).every((m) => !shouldLoadRouteOnHydration(m.route, loaderData, errors));
968 } else {
969 initialized = initialMatches.every(
970 (m) => !shouldLoadRouteOnHydration(m.route, loaderData, errors)
971 );
972 }
973 }
974 let router;
975 let state = {
976 historyAction: init.history.action,
977 location: init.history.location,
978 matches: initialMatches,
979 initialized,
980 navigation: IDLE_NAVIGATION,
981 // Don't restore on initial updateState() if we were SSR'd
982 restoreScrollPosition: init.hydrationData != null ? false : null,
983 preventScrollReset: false,
984 revalidation: "idle",
985 loaderData: init.hydrationData && init.hydrationData.loaderData || {},
986 actionData: init.hydrationData && init.hydrationData.actionData || null,
987 errors: init.hydrationData && init.hydrationData.errors || initialErrors,
988 fetchers: /* @__PURE__ */ new Map(),
989 blockers: /* @__PURE__ */ new Map()
990 };
991 let pendingAction = "POP" /* Pop */;
992 let pendingPreventScrollReset = false;
993 let pendingNavigationController;
994 let pendingViewTransitionEnabled = false;
995 let appliedViewTransitions = /* @__PURE__ */ new Map();
996 let removePageHideEventListener = null;
997 let isUninterruptedRevalidation = false;
998 let isRevalidationRequired = false;
999 let cancelledFetcherLoads = /* @__PURE__ */ new Set();
1000 let fetchControllers = /* @__PURE__ */ new Map();
1001 let incrementingLoadId = 0;
1002 let pendingNavigationLoadId = -1;
1003 let fetchReloadIds = /* @__PURE__ */ new Map();
1004 let fetchRedirectIds = /* @__PURE__ */ new Set();
1005 let fetchLoadMatches = /* @__PURE__ */ new Map();
1006 let activeFetchers = /* @__PURE__ */ new Map();
1007 let fetchersQueuedForDeletion = /* @__PURE__ */ new Set();
1008 let blockerFunctions = /* @__PURE__ */ new Map();
1009 let unblockBlockerHistoryUpdate = void 0;
1010 let pendingRevalidationDfd = null;
1011 function initialize() {
1012 unlistenHistory = init.history.listen(
1013 ({ action: historyAction, location, delta }) => {
1014 if (unblockBlockerHistoryUpdate) {
1015 unblockBlockerHistoryUpdate();
1016 unblockBlockerHistoryUpdate = void 0;
1017 return;
1018 }
1019 warning(
1020 blockerFunctions.size === 0 || delta != null,
1021 "You are trying to use a blocker on a POP navigation to a location that was not created by @remix-run/router. This will fail silently in production. This can happen if you are navigating outside the router via `window.history.pushState`/`window.location.hash` instead of using router navigation APIs. This can also happen if you are using createHashRouter and the user manually changes the URL."
1022 );
1023 let blockerKey = shouldBlockNavigation({
1024 currentLocation: state.location,
1025 nextLocation: location,
1026 historyAction
1027 });
1028 if (blockerKey && delta != null) {
1029 let nextHistoryUpdatePromise = new Promise((resolve) => {
1030 unblockBlockerHistoryUpdate = resolve;
1031 });
1032 init.history.go(delta * -1);
1033 updateBlocker(blockerKey, {
1034 state: "blocked",
1035 location,
1036 proceed() {
1037 updateBlocker(blockerKey, {
1038 state: "proceeding",
1039 proceed: void 0,
1040 reset: void 0,
1041 location
1042 });
1043 nextHistoryUpdatePromise.then(() => init.history.go(delta));
1044 },
1045 reset() {
1046 let blockers = new Map(state.blockers);
1047 blockers.set(blockerKey, IDLE_BLOCKER);
1048 updateState({ blockers });
1049 }
1050 });
1051 return;
1052 }
1053 return startNavigation(historyAction, location);
1054 }
1055 );
1056 if (isBrowser2) {
1057 restoreAppliedTransitions(routerWindow, appliedViewTransitions);
1058 let _saveAppliedTransitions = () => persistAppliedTransitions(routerWindow, appliedViewTransitions);
1059 routerWindow.addEventListener("pagehide", _saveAppliedTransitions);
1060 removePageHideEventListener = () => routerWindow.removeEventListener("pagehide", _saveAppliedTransitions);
1061 }
1062 if (!state.initialized) {
1063 startNavigation("POP" /* Pop */, state.location, {
1064 initialHydration: true
1065 });
1066 }
1067 return router;
1068 }
1069 function dispose() {
1070 if (unlistenHistory) {
1071 unlistenHistory();
1072 }
1073 if (removePageHideEventListener) {
1074 removePageHideEventListener();
1075 }
1076 subscribers.clear();
1077 pendingNavigationController && pendingNavigationController.abort();
1078 state.fetchers.forEach((_, key) => deleteFetcher(key));
1079 state.blockers.forEach((_, key) => deleteBlocker(key));
1080 }
1081 function subscribe(fn) {
1082 subscribers.add(fn);
1083 return () => subscribers.delete(fn);
1084 }
1085 function updateState(newState, opts = {}) {
1086 state = {
1087 ...state,
1088 ...newState
1089 };
1090 let unmountedFetchers = [];
1091 let mountedFetchers = [];
1092 state.fetchers.forEach((fetcher, key) => {
1093 if (fetcher.state === "idle") {
1094 if (fetchersQueuedForDeletion.has(key)) {
1095 unmountedFetchers.push(key);
1096 } else {
1097 mountedFetchers.push(key);
1098 }
1099 }
1100 });
1101 [...subscribers].forEach(
1102 (subscriber) => subscriber(state, {
1103 deletedFetchers: unmountedFetchers,
1104 viewTransitionOpts: opts.viewTransitionOpts,
1105 flushSync: opts.flushSync === true
1106 })
1107 );
1108 unmountedFetchers.forEach((key) => deleteFetcher(key));
1109 mountedFetchers.forEach((key) => state.fetchers.delete(key));
1110 }
1111 function completeNavigation(location, newState, { flushSync } = {}) {
1112 let isActionReload = state.actionData != null && state.navigation.formMethod != null && isMutationMethod(state.navigation.formMethod) && state.navigation.state === "loading" && location.state?._isRedirect !== true;
1113 let actionData;
1114 if (newState.actionData) {
1115 if (Object.keys(newState.actionData).length > 0) {
1116 actionData = newState.actionData;
1117 } else {
1118 actionData = null;
1119 }
1120 } else if (isActionReload) {
1121 actionData = state.actionData;
1122 } else {
1123 actionData = null;
1124 }
1125 let loaderData = newState.loaderData ? mergeLoaderData(
1126 state.loaderData,
1127 newState.loaderData,
1128 newState.matches || [],
1129 newState.errors
1130 ) : state.loaderData;
1131 let blockers = state.blockers;
1132 if (blockers.size > 0) {
1133 blockers = new Map(blockers);
1134 blockers.forEach((_, k) => blockers.set(k, IDLE_BLOCKER));
1135 }
1136 let preventScrollReset = pendingPreventScrollReset === true || state.navigation.formMethod != null && isMutationMethod(state.navigation.formMethod) && location.state?._isRedirect !== true;
1137 if (inFlightDataRoutes) {
1138 dataRoutes = inFlightDataRoutes;
1139 inFlightDataRoutes = void 0;
1140 }
1141 if (isUninterruptedRevalidation) {
1142 } else if (pendingAction === "POP" /* Pop */) {
1143 } else if (pendingAction === "PUSH" /* Push */) {
1144 init.history.push(location, location.state);
1145 } else if (pendingAction === "REPLACE" /* Replace */) {
1146 init.history.replace(location, location.state);
1147 }
1148 let viewTransitionOpts;
1149 if (pendingAction === "POP" /* Pop */) {
1150 let priorPaths = appliedViewTransitions.get(state.location.pathname);
1151 if (priorPaths && priorPaths.has(location.pathname)) {
1152 viewTransitionOpts = {
1153 currentLocation: state.location,
1154 nextLocation: location
1155 };
1156 } else if (appliedViewTransitions.has(location.pathname)) {
1157 viewTransitionOpts = {
1158 currentLocation: location,
1159 nextLocation: state.location
1160 };
1161 }
1162 } else if (pendingViewTransitionEnabled) {
1163 let toPaths = appliedViewTransitions.get(state.location.pathname);
1164 if (toPaths) {
1165 toPaths.add(location.pathname);
1166 } else {
1167 toPaths = /* @__PURE__ */ new Set([location.pathname]);
1168 appliedViewTransitions.set(state.location.pathname, toPaths);
1169 }
1170 viewTransitionOpts = {
1171 currentLocation: state.location,
1172 nextLocation: location
1173 };
1174 }
1175 updateState(
1176 {
1177 ...newState,
1178 // matches, errors, fetchers go through as-is
1179 actionData,
1180 loaderData,
1181 historyAction: pendingAction,
1182 location,
1183 initialized: true,
1184 navigation: IDLE_NAVIGATION,
1185 revalidation: "idle",
1186 restoreScrollPosition: getSavedScrollPosition(
1187 location,
1188 newState.matches || state.matches
1189 ),
1190 preventScrollReset,
1191 blockers
1192 },
1193 {
1194 viewTransitionOpts,
1195 flushSync: flushSync === true
1196 }
1197 );
1198 pendingAction = "POP" /* Pop */;
1199 pendingPreventScrollReset = false;
1200 pendingViewTransitionEnabled = false;
1201 isUninterruptedRevalidation = false;
1202 isRevalidationRequired = false;
1203 pendingRevalidationDfd?.resolve();
1204 pendingRevalidationDfd = null;
1205 }
1206 async function navigate(to, opts) {
1207 if (typeof to === "number") {
1208 init.history.go(to);
1209 return;
1210 }
1211 let normalizedPath = normalizeTo(
1212 state.location,
1213 state.matches,
1214 basename,
1215 to,
1216 opts?.fromRouteId,
1217 opts?.relative
1218 );
1219 let { path, submission, error } = normalizeNavigateOptions(
1220 false,
1221 normalizedPath,
1222 opts
1223 );
1224 let currentLocation = state.location;
1225 let nextLocation = createLocation(state.location, path, opts && opts.state);
1226 nextLocation = {
1227 ...nextLocation,
1228 ...init.history.encodeLocation(nextLocation)
1229 };
1230 let userReplace = opts && opts.replace != null ? opts.replace : void 0;
1231 let historyAction = "PUSH" /* Push */;
1232 if (userReplace === true) {
1233 historyAction = "REPLACE" /* Replace */;
1234 } else if (userReplace === false) {
1235 } else if (submission != null && isMutationMethod(submission.formMethod) && submission.formAction === state.location.pathname + state.location.search) {
1236 historyAction = "REPLACE" /* Replace */;
1237 }
1238 let preventScrollReset = opts && "preventScrollReset" in opts ? opts.preventScrollReset === true : void 0;
1239 let flushSync = (opts && opts.flushSync) === true;
1240 let blockerKey = shouldBlockNavigation({
1241 currentLocation,
1242 nextLocation,
1243 historyAction
1244 });
1245 if (blockerKey) {
1246 updateBlocker(blockerKey, {
1247 state: "blocked",
1248 location: nextLocation,
1249 proceed() {
1250 updateBlocker(blockerKey, {
1251 state: "proceeding",
1252 proceed: void 0,
1253 reset: void 0,
1254 location: nextLocation
1255 });
1256 navigate(to, opts);
1257 },
1258 reset() {
1259 let blockers = new Map(state.blockers);
1260 blockers.set(blockerKey, IDLE_BLOCKER);
1261 updateState({ blockers });
1262 }
1263 });
1264 return;
1265 }
1266 await startNavigation(historyAction, nextLocation, {
1267 submission,
1268 // Send through the formData serialization error if we have one so we can
1269 // render at the right error boundary after we match routes
1270 pendingError: error,
1271 preventScrollReset,
1272 replace: opts && opts.replace,
1273 enableViewTransition: opts && opts.viewTransition,
1274 flushSync
1275 });
1276 }
1277 function revalidate() {
1278 if (!pendingRevalidationDfd) {
1279 pendingRevalidationDfd = createDeferred();
1280 }
1281 interruptActiveLoads();
1282 updateState({ revalidation: "loading" });
1283 let promise = pendingRevalidationDfd.promise;
1284 if (state.navigation.state === "submitting") {
1285 return promise;
1286 }
1287 if (state.navigation.state === "idle") {
1288 startNavigation(state.historyAction, state.location, {
1289 startUninterruptedRevalidation: true
1290 });
1291 return promise;
1292 }
1293 startNavigation(
1294 pendingAction || state.historyAction,
1295 state.navigation.location,
1296 {
1297 overrideNavigation: state.navigation,
1298 // Proxy through any rending view transition
1299 enableViewTransition: pendingViewTransitionEnabled === true
1300 }
1301 );
1302 return promise;
1303 }
1304 async function startNavigation(historyAction, location, opts) {
1305 pendingNavigationController && pendingNavigationController.abort();
1306 pendingNavigationController = null;
1307 pendingAction = historyAction;
1308 isUninterruptedRevalidation = (opts && opts.startUninterruptedRevalidation) === true;
1309 saveScrollPosition(state.location, state.matches);
1310 pendingPreventScrollReset = (opts && opts.preventScrollReset) === true;
1311 pendingViewTransitionEnabled = (opts && opts.enableViewTransition) === true;
1312 let routesToUse = inFlightDataRoutes || dataRoutes;
1313 let loadingNavigation = opts && opts.overrideNavigation;
1314 let matches = matchRoutes(routesToUse, location, basename);
1315 let flushSync = (opts && opts.flushSync) === true;
1316 let fogOfWar = checkFogOfWar(matches, routesToUse, location.pathname);
1317 if (fogOfWar.active && fogOfWar.matches) {
1318 matches = fogOfWar.matches;
1319 }
1320 if (!matches) {
1321 let { error, notFoundMatches, route } = handleNavigational404(
1322 location.pathname
1323 );
1324 completeNavigation(
1325 location,
1326 {
1327 matches: notFoundMatches,
1328 loaderData: {},
1329 errors: {
1330 [route.id]: error
1331 }
1332 },
1333 { flushSync }
1334 );
1335 return;
1336 }
1337 if (state.initialized && !isRevalidationRequired && isHashChangeOnly(state.location, location) && !(opts && opts.submission && isMutationMethod(opts.submission.formMethod))) {
1338 completeNavigation(location, { matches }, { flushSync });
1339 return;
1340 }
1341 pendingNavigationController = new AbortController();
1342 let request = createClientSideRequest(
1343 init.history,
1344 location,
1345 pendingNavigationController.signal,
1346 opts && opts.submission
1347 );
1348 let pendingActionResult;
1349 if (opts && opts.pendingError) {
1350 pendingActionResult = [
1351 findNearestBoundary(matches).route.id,
1352 { type: "error" /* error */, error: opts.pendingError }
1353 ];
1354 } else if (opts && opts.submission && isMutationMethod(opts.submission.formMethod)) {
1355 let actionResult = await handleAction(
1356 request,
1357 location,
1358 opts.submission,
1359 matches,
1360 fogOfWar.active,
1361 { replace: opts.replace, flushSync }
1362 );
1363 if (actionResult.shortCircuited) {
1364 return;
1365 }
1366 if (actionResult.pendingActionResult) {
1367 let [routeId, result] = actionResult.pendingActionResult;
1368 if (isErrorResult(result) && isRouteErrorResponse(result.error) && result.error.status === 404) {
1369 pendingNavigationController = null;
1370 completeNavigation(location, {
1371 matches: actionResult.matches,
1372 loaderData: {},
1373 errors: {
1374 [routeId]: result.error
1375 }
1376 });
1377 return;
1378 }
1379 }
1380 matches = actionResult.matches || matches;
1381 pendingActionResult = actionResult.pendingActionResult;
1382 loadingNavigation = getLoadingNavigation(location, opts.submission);
1383 flushSync = false;
1384 fogOfWar.active = false;
1385 request = createClientSideRequest(
1386 init.history,
1387 request.url,
1388 request.signal
1389 );
1390 }
1391 let {
1392 shortCircuited,
1393 matches: updatedMatches,
1394 loaderData,
1395 errors
1396 } = await handleLoaders(
1397 request,
1398 location,
1399 matches,
1400 fogOfWar.active,
1401 loadingNavigation,
1402 opts && opts.submission,
1403 opts && opts.fetcherSubmission,
1404 opts && opts.replace,
1405 opts && opts.initialHydration === true,
1406 flushSync,
1407 pendingActionResult
1408 );
1409 if (shortCircuited) {
1410 return;
1411 }
1412 pendingNavigationController = null;
1413 completeNavigation(location, {
1414 matches: updatedMatches || matches,
1415 ...getActionDataForCommit(pendingActionResult),
1416 loaderData,
1417 errors
1418 });
1419 }
1420 async function handleAction(request, location, submission, matches, isFogOfWar, opts = {}) {
1421 interruptActiveLoads();
1422 let navigation = getSubmittingNavigation(location, submission);
1423 updateState({ navigation }, { flushSync: opts.flushSync === true });
1424 if (isFogOfWar) {
1425 let discoverResult = await discoverRoutes(
1426 matches,
1427 location.pathname,
1428 request.signal
1429 );
1430 if (discoverResult.type === "aborted") {
1431 return { shortCircuited: true };
1432 } else if (discoverResult.type === "error") {
1433 let boundaryId = findNearestBoundary(discoverResult.partialMatches).route.id;
1434 return {
1435 matches: discoverResult.partialMatches,
1436 pendingActionResult: [
1437 boundaryId,
1438 {
1439 type: "error" /* error */,
1440 error: discoverResult.error
1441 }
1442 ]
1443 };
1444 } else if (!discoverResult.matches) {
1445 let { notFoundMatches, error, route } = handleNavigational404(
1446 location.pathname
1447 );
1448 return {
1449 matches: notFoundMatches,
1450 pendingActionResult: [
1451 route.id,
1452 {
1453 type: "error" /* error */,
1454 error
1455 }
1456 ]
1457 };
1458 } else {
1459 matches = discoverResult.matches;
1460 }
1461 }
1462 let result;
1463 let actionMatch = getTargetMatch(matches, location);
1464 if (!actionMatch.route.action && !actionMatch.route.lazy) {
1465 result = {
1466 type: "error" /* error */,
1467 error: getInternalRouterError(405, {
1468 method: request.method,
1469 pathname: location.pathname,
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 = true;
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 = true;
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}
5165function renderMatches(matches) {
5166 return _renderMatches(matches);
5167}
5168
5169// lib/dom/lib.tsx
5170import * as React10 from "react";
5171
5172// lib/dom/dom.ts
5173var defaultMethod = "get";
5174var defaultEncType = "application/x-www-form-urlencoded";
5175function isHtmlElement(object) {
5176 return object != null && typeof object.tagName === "string";
5177}
5178function isButtonElement(object) {
5179 return isHtmlElement(object) && object.tagName.toLowerCase() === "button";
5180}
5181function isFormElement(object) {
5182 return isHtmlElement(object) && object.tagName.toLowerCase() === "form";
5183}
5184function isInputElement(object) {
5185 return isHtmlElement(object) && object.tagName.toLowerCase() === "input";
5186}
5187function isModifiedEvent(event) {
5188 return !!(event.metaKey || event.altKey || event.ctrlKey || event.shiftKey);
5189}
5190function shouldProcessLinkClick(event, target) {
5191 return event.button === 0 && // Ignore everything but left clicks
5192 (!target || target === "_self") && // Let browser handle "target=_blank" etc.
5193 !isModifiedEvent(event);
5194}
5195function createSearchParams(init = "") {
5196 return new URLSearchParams(
5197 typeof init === "string" || Array.isArray(init) || init instanceof URLSearchParams ? init : Object.keys(init).reduce((memo2, key) => {
5198 let value = init[key];
5199 return memo2.concat(
5200 Array.isArray(value) ? value.map((v) => [key, v]) : [[key, value]]
5201 );
5202 }, [])
5203 );
5204}
5205function getSearchParamsForLocation(locationSearch, defaultSearchParams) {
5206 let searchParams = createSearchParams(locationSearch);
5207 if (defaultSearchParams) {
5208 defaultSearchParams.forEach((_, key) => {
5209 if (!searchParams.has(key)) {
5210 defaultSearchParams.getAll(key).forEach((value) => {
5211 searchParams.append(key, value);
5212 });
5213 }
5214 });
5215 }
5216 return searchParams;
5217}
5218var _formDataSupportsSubmitter = null;
5219function isFormDataSubmitterSupported() {
5220 if (_formDataSupportsSubmitter === null) {
5221 try {
5222 new FormData(
5223 document.createElement("form"),
5224 // @ts-expect-error if FormData supports the submitter parameter, this will throw
5225 0
5226 );
5227 _formDataSupportsSubmitter = false;
5228 } catch (e) {
5229 _formDataSupportsSubmitter = true;
5230 }
5231 }
5232 return _formDataSupportsSubmitter;
5233}
5234var supportedFormEncTypes = /* @__PURE__ */ new Set([
5235 "application/x-www-form-urlencoded",
5236 "multipart/form-data",
5237 "text/plain"
5238]);
5239function getFormEncType(encType) {
5240 if (encType != null && !supportedFormEncTypes.has(encType)) {
5241 warning(
5242 false,
5243 `"${encType}" is not a valid \`encType\` for \`<Form>\`/\`<fetcher.Form>\` and will default to "${defaultEncType}"`
5244 );
5245 return null;
5246 }
5247 return encType;
5248}
5249function getFormSubmissionInfo(target, basename) {
5250 let method;
5251 let action;
5252 let encType;
5253 let formData;
5254 let body;
5255 if (isFormElement(target)) {
5256 let attr = target.getAttribute("action");
5257 action = attr ? stripBasename(attr, basename) : null;
5258 method = target.getAttribute("method") || defaultMethod;
5259 encType = getFormEncType(target.getAttribute("enctype")) || defaultEncType;
5260 formData = new FormData(target);
5261 } else if (isButtonElement(target) || isInputElement(target) && (target.type === "submit" || target.type === "image")) {
5262 let form = target.form;
5263 if (form == null) {
5264 throw new Error(
5265 `Cannot submit a <button> or <input type="submit"> without a <form>`
5266 );
5267 }
5268 let attr = target.getAttribute("formaction") || form.getAttribute("action");
5269 action = attr ? stripBasename(attr, basename) : null;
5270 method = target.getAttribute("formmethod") || form.getAttribute("method") || defaultMethod;
5271 encType = getFormEncType(target.getAttribute("formenctype")) || getFormEncType(form.getAttribute("enctype")) || defaultEncType;
5272 formData = new FormData(form, target);
5273 if (!isFormDataSubmitterSupported()) {
5274 let { name, type, value } = target;
5275 if (type === "image") {
5276 let prefix = name ? `${name}.` : "";
5277 formData.append(`${prefix}x`, "0");
5278 formData.append(`${prefix}y`, "0");
5279 } else if (name) {
5280 formData.append(name, value);
5281 }
5282 }
5283 } else if (isHtmlElement(target)) {
5284 throw new Error(
5285 `Cannot submit element that is not <form>, <button>, or <input type="submit|image">`
5286 );
5287 } else {
5288 method = defaultMethod;
5289 action = null;
5290 encType = defaultEncType;
5291 body = target;
5292 }
5293 if (formData && encType === "text/plain") {
5294 body = formData;
5295 formData = void 0;
5296 }
5297 return { action, method: method.toLowerCase(), encType, formData, body };
5298}
5299
5300// lib/dom/ssr/components.tsx
5301import * as React9 from "react";
5302
5303// lib/dom/ssr/invariant.ts
5304function invariant2(value, message) {
5305 if (value === false || value === null || typeof value === "undefined") {
5306 throw new Error(message);
5307 }
5308}
5309
5310// lib/dom/ssr/routeModules.ts
5311async function loadRouteModule(route, routeModulesCache) {
5312 if (route.id in routeModulesCache) {
5313 return routeModulesCache[route.id];
5314 }
5315 try {
5316 let routeModule = await import(
5317 /* @vite-ignore */
5318 /* webpackIgnore: true */
5319 route.module
5320 );
5321 routeModulesCache[route.id] = routeModule;
5322 return routeModule;
5323 } catch (error) {
5324 console.error(
5325 `Error loading route module \`${route.module}\`, reloading page...`
5326 );
5327 console.error(error);
5328 if (window.__reactRouterContext && window.__reactRouterContext.isSpaMode && // @ts-expect-error
5329 import.meta.hot) {
5330 throw error;
5331 }
5332 window.location.reload();
5333 return new Promise(() => {
5334 });
5335 }
5336}
5337
5338// lib/dom/ssr/links.ts
5339function getKeyedLinksForMatches(matches, routeModules, manifest) {
5340 let descriptors = matches.map((match) => {
5341 let module = routeModules[match.route.id];
5342 let route = manifest.routes[match.route.id];
5343 return [
5344 route && route.css ? route.css.map((href) => ({ rel: "stylesheet", href })) : [],
5345 module?.links?.() || []
5346 ];
5347 }).flat(2);
5348 let preloads = getCurrentPageModulePreloadHrefs(matches, manifest);
5349 return dedupeLinkDescriptors(descriptors, preloads);
5350}
5351async function prefetchStyleLinks(route, routeModule) {
5352 if (!route.css && !routeModule.links || !isPreloadSupported()) return;
5353 let descriptors = [];
5354 if (route.css) {
5355 descriptors.push(...route.css.map((href) => ({ rel: "stylesheet", href })));
5356 }
5357 if (routeModule.links) {
5358 descriptors.push(...routeModule.links());
5359 }
5360 if (descriptors.length === 0) return;
5361 let styleLinks = [];
5362 for (let descriptor of descriptors) {
5363 if (!isPageLinkDescriptor(descriptor) && descriptor.rel === "stylesheet") {
5364 styleLinks.push({
5365 ...descriptor,
5366 rel: "preload",
5367 as: "style"
5368 });
5369 }
5370 }
5371 let matchingLinks = styleLinks.filter(
5372 (link) => (!link.media || window.matchMedia(link.media).matches) && !document.querySelector(`link[rel="stylesheet"][href="${link.href}"]`)
5373 );
5374 await Promise.all(matchingLinks.map(prefetchStyleLink));
5375}
5376async function prefetchStyleLink(descriptor) {
5377 return new Promise((resolve) => {
5378 let link = document.createElement("link");
5379 Object.assign(link, descriptor);
5380 function removeLink() {
5381 if (document.head.contains(link)) {
5382 document.head.removeChild(link);
5383 }
5384 }
5385 link.onload = () => {
5386 removeLink();
5387 resolve();
5388 };
5389 link.onerror = () => {
5390 removeLink();
5391 resolve();
5392 };
5393 document.head.appendChild(link);
5394 });
5395}
5396function isPageLinkDescriptor(object) {
5397 return object != null && typeof object.page === "string";
5398}
5399function isHtmlLinkDescriptor(object) {
5400 if (object == null) {
5401 return false;
5402 }
5403 if (object.href == null) {
5404 return object.rel === "preload" && typeof object.imageSrcSet === "string" && typeof object.imageSizes === "string";
5405 }
5406 return typeof object.rel === "string" && typeof object.href === "string";
5407}
5408async function getKeyedPrefetchLinks(matches, manifest, routeModules) {
5409 let links = await Promise.all(
5410 matches.map(async (match) => {
5411 let route = manifest.routes[match.route.id];
5412 if (route) {
5413 let mod = await loadRouteModule(route, routeModules);
5414 return mod.links ? mod.links() : [];
5415 }
5416 return [];
5417 })
5418 );
5419 return dedupeLinkDescriptors(
5420 links.flat(1).filter(isHtmlLinkDescriptor).filter((link) => link.rel === "stylesheet" || link.rel === "preload").map(
5421 (link) => link.rel === "stylesheet" ? { ...link, rel: "prefetch", as: "style" } : { ...link, rel: "prefetch" }
5422 )
5423 );
5424}
5425function getNewMatchesForLinks(page, nextMatches, currentMatches, manifest, location, mode) {
5426 let isNew = (match, index) => {
5427 if (!currentMatches[index]) return true;
5428 return match.route.id !== currentMatches[index].route.id;
5429 };
5430 let matchPathChanged = (match, index) => {
5431 return (
5432 // param change, /users/123 -> /users/456
5433 currentMatches[index].pathname !== match.pathname || // splat param changed, which is not present in match.path
5434 // e.g. /files/images/avatar.jpg -> files/finances.xls
5435 currentMatches[index].route.path?.endsWith("*") && currentMatches[index].params["*"] !== match.params["*"]
5436 );
5437 };
5438 if (mode === "assets") {
5439 return nextMatches.filter(
5440 (match, index) => isNew(match, index) || matchPathChanged(match, index)
5441 );
5442 }
5443 if (mode === "data") {
5444 return nextMatches.filter((match, index) => {
5445 let manifestRoute = manifest.routes[match.route.id];
5446 if (!manifestRoute || !manifestRoute.hasLoader) {
5447 return false;
5448 }
5449 if (isNew(match, index) || matchPathChanged(match, index)) {
5450 return true;
5451 }
5452 if (match.route.shouldRevalidate) {
5453 let routeChoice = match.route.shouldRevalidate({
5454 currentUrl: new URL(
5455 location.pathname + location.search + location.hash,
5456 window.origin
5457 ),
5458 currentParams: currentMatches[0]?.params || {},
5459 nextUrl: new URL(page, window.origin),
5460 nextParams: match.params,
5461 defaultShouldRevalidate: true
5462 });
5463 if (typeof routeChoice === "boolean") {
5464 return routeChoice;
5465 }
5466 }
5467 return true;
5468 });
5469 }
5470 return [];
5471}
5472function getModuleLinkHrefs(matches, manifestPatch) {
5473 return dedupeHrefs(
5474 matches.map((match) => {
5475 let route = manifestPatch.routes[match.route.id];
5476 if (!route) return [];
5477 let hrefs = [route.module];
5478 if (route.imports) {
5479 hrefs = hrefs.concat(route.imports);
5480 }
5481 return hrefs;
5482 }).flat(1)
5483 );
5484}
5485function getCurrentPageModulePreloadHrefs(matches, manifest) {
5486 return dedupeHrefs(
5487 matches.map((match) => {
5488 let route = manifest.routes[match.route.id];
5489 if (!route) return [];
5490 let hrefs = [route.module];
5491 if (route.imports) {
5492 hrefs = hrefs.concat(route.imports);
5493 }
5494 return hrefs;
5495 }).flat(1)
5496 );
5497}
5498function dedupeHrefs(hrefs) {
5499 return [...new Set(hrefs)];
5500}
5501function sortKeys(obj) {
5502 let sorted = {};
5503 let keys = Object.keys(obj).sort();
5504 for (let key of keys) {
5505 sorted[key] = obj[key];
5506 }
5507 return sorted;
5508}
5509function dedupeLinkDescriptors(descriptors, preloads) {
5510 let set = /* @__PURE__ */ new Set();
5511 let preloadsSet = new Set(preloads);
5512 return descriptors.reduce((deduped, descriptor) => {
5513 let alreadyModulePreload = preloads && !isPageLinkDescriptor(descriptor) && descriptor.as === "script" && descriptor.href && preloadsSet.has(descriptor.href);
5514 if (alreadyModulePreload) {
5515 return deduped;
5516 }
5517 let key = JSON.stringify(sortKeys(descriptor));
5518 if (!set.has(key)) {
5519 set.add(key);
5520 deduped.push({ key, link: descriptor });
5521 }
5522 return deduped;
5523 }, []);
5524}
5525var _isPreloadSupported;
5526function isPreloadSupported() {
5527 if (_isPreloadSupported !== void 0) {
5528 return _isPreloadSupported;
5529 }
5530 let el = document.createElement("link");
5531 _isPreloadSupported = el.relList.supports("preload");
5532 el = null;
5533 return _isPreloadSupported;
5534}
5535
5536// lib/dom/ssr/markup.ts
5537var ESCAPE_LOOKUP = {
5538 "&": "\\u0026",
5539 ">": "\\u003e",
5540 "<": "\\u003c",
5541 "\u2028": "\\u2028",
5542 "\u2029": "\\u2029"
5543};
5544var ESCAPE_REGEX = /[&><\u2028\u2029]/g;
5545function escapeHtml(html) {
5546 return html.replace(ESCAPE_REGEX, (match) => ESCAPE_LOOKUP[match]);
5547}
5548function createHtml(html) {
5549 return { __html: html };
5550}
5551
5552// lib/dom/ssr/single-fetch.tsx
5553import * as React4 from "react";
5554import { decode } from "turbo-stream";
5555
5556// lib/dom/ssr/data.ts
5557async function createRequestInit(request) {
5558 let init = { signal: request.signal };
5559 if (request.method !== "GET") {
5560 init.method = request.method;
5561 let contentType = request.headers.get("Content-Type");
5562 if (contentType && /\bapplication\/json\b/.test(contentType)) {
5563 init.headers = { "Content-Type": contentType };
5564 init.body = JSON.stringify(await request.json());
5565 } else if (contentType && /\btext\/plain\b/.test(contentType)) {
5566 init.headers = { "Content-Type": contentType };
5567 init.body = await request.text();
5568 } else if (contentType && /\bapplication\/x-www-form-urlencoded\b/.test(contentType)) {
5569 init.body = new URLSearchParams(await request.text());
5570 } else {
5571 init.body = await request.formData();
5572 }
5573 }
5574 return init;
5575}
5576
5577// lib/dom/ssr/single-fetch.tsx
5578var SingleFetchRedirectSymbol = Symbol("SingleFetchRedirect");
5579function StreamTransfer({
5580 context,
5581 identifier,
5582 reader,
5583 textDecoder,
5584 nonce
5585}) {
5586 if (!context.renderMeta || !context.renderMeta.didRenderScripts) {
5587 return null;
5588 }
5589 if (!context.renderMeta.streamCache) {
5590 context.renderMeta.streamCache = {};
5591 }
5592 let { streamCache } = context.renderMeta;
5593 let promise = streamCache[identifier];
5594 if (!promise) {
5595 promise = streamCache[identifier] = reader.read().then((result) => {
5596 streamCache[identifier].result = {
5597 done: result.done,
5598 value: textDecoder.decode(result.value, { stream: true })
5599 };
5600 }).catch((e) => {
5601 streamCache[identifier].error = e;
5602 });
5603 }
5604 if (promise.error) {
5605 throw promise.error;
5606 }
5607 if (promise.result === void 0) {
5608 throw promise;
5609 }
5610 let { done, value } = promise.result;
5611 let scriptTag = value ? /* @__PURE__ */ React4.createElement(
5612 "script",
5613 {
5614 nonce,
5615 dangerouslySetInnerHTML: {
5616 __html: `window.__reactRouterContext.streamController.enqueue(${escapeHtml(
5617 JSON.stringify(value)
5618 )});`
5619 }
5620 }
5621 ) : null;
5622 if (done) {
5623 return /* @__PURE__ */ React4.createElement(React4.Fragment, null, scriptTag, /* @__PURE__ */ React4.createElement(
5624 "script",
5625 {
5626 nonce,
5627 dangerouslySetInnerHTML: {
5628 __html: `window.__reactRouterContext.streamController.close();`
5629 }
5630 }
5631 ));
5632 } else {
5633 return /* @__PURE__ */ React4.createElement(React4.Fragment, null, scriptTag, /* @__PURE__ */ React4.createElement(React4.Suspense, null, /* @__PURE__ */ React4.createElement(
5634 StreamTransfer,
5635 {
5636 context,
5637 identifier: identifier + 1,
5638 reader,
5639 textDecoder,
5640 nonce
5641 }
5642 )));
5643 }
5644}
5645function getSingleFetchDataStrategy(manifest, routeModules, getRouter) {
5646 return async ({ request, matches, fetcherKey }) => {
5647 if (request.method !== "GET") {
5648 return singleFetchActionStrategy(request, matches);
5649 }
5650 if (fetcherKey) {
5651 return singleFetchLoaderFetcherStrategy(request, matches);
5652 }
5653 return singleFetchLoaderNavigationStrategy(
5654 manifest,
5655 routeModules,
5656 getRouter(),
5657 request,
5658 matches
5659 );
5660 };
5661}
5662async function singleFetchActionStrategy(request, matches) {
5663 let actionMatch = matches.find((m) => m.shouldLoad);
5664 invariant2(actionMatch, "No action match found");
5665 let actionStatus = void 0;
5666 let result = await actionMatch.resolve(async (handler) => {
5667 let result2 = await handler(async () => {
5668 let url = singleFetchUrl(request.url);
5669 let init = await createRequestInit(request);
5670 let { data: data2, status } = await fetchAndDecode(url, init);
5671 actionStatus = status;
5672 return unwrapSingleFetchResult(
5673 data2,
5674 actionMatch.route.id
5675 );
5676 });
5677 return result2;
5678 });
5679 if (isResponse(result.result) || isRouteErrorResponse(result.result)) {
5680 return { [actionMatch.route.id]: result };
5681 }
5682 return {
5683 [actionMatch.route.id]: {
5684 type: result.type,
5685 result: data(result.result, actionStatus)
5686 }
5687 };
5688}
5689async function singleFetchLoaderNavigationStrategy(manifest, routeModules, router, request, matches) {
5690 let routesParams = /* @__PURE__ */ new Set();
5691 let foundOptOutRoute = false;
5692 let routeDfds = matches.map(() => createDeferred2());
5693 let routesLoadedPromise = Promise.all(routeDfds.map((d) => d.promise));
5694 let singleFetchDfd = createDeferred2();
5695 let url = stripIndexParam(singleFetchUrl(request.url));
5696 let init = await createRequestInit(request);
5697 let results = {};
5698 let resolvePromise = Promise.all(
5699 matches.map(
5700 async (m, i) => m.resolve(async (handler) => {
5701 routeDfds[i].resolve();
5702 let manifestRoute = manifest.routes[m.route.id];
5703 if (!m.shouldLoad) {
5704 if (!router.state.initialized) {
5705 return;
5706 }
5707 if (m.route.id in router.state.loaderData && manifestRoute && manifestRoute.hasLoader && routeModules[m.route.id]?.shouldRevalidate) {
5708 foundOptOutRoute = true;
5709 return;
5710 }
5711 }
5712 if (manifestRoute && manifestRoute.hasClientLoader) {
5713 if (manifestRoute.hasLoader) {
5714 foundOptOutRoute = true;
5715 }
5716 try {
5717 let result = await fetchSingleLoader(
5718 handler,
5719 url,
5720 init,
5721 m.route.id
5722 );
5723 results[m.route.id] = { type: "data", result };
5724 } catch (e) {
5725 results[m.route.id] = { type: "error", result: e };
5726 }
5727 return;
5728 }
5729 if (manifestRoute && manifestRoute.hasLoader) {
5730 routesParams.add(m.route.id);
5731 }
5732 try {
5733 let result = await handler(async () => {
5734 let data2 = await singleFetchDfd.promise;
5735 return unwrapSingleFetchResults(data2, m.route.id);
5736 });
5737 results[m.route.id] = {
5738 type: "data",
5739 result
5740 };
5741 } catch (e) {
5742 results[m.route.id] = {
5743 type: "error",
5744 result: e
5745 };
5746 }
5747 })
5748 )
5749 );
5750 await routesLoadedPromise;
5751 if ((!router.state.initialized || routesParams.size === 0) && !window.__reactRouterHdrActive) {
5752 singleFetchDfd.resolve({});
5753 } else {
5754 try {
5755 if (foundOptOutRoute && routesParams.size > 0) {
5756 url.searchParams.set(
5757 "_routes",
5758 matches.filter((m) => routesParams.has(m.route.id)).map((m) => m.route.id).join(",")
5759 );
5760 }
5761 let data2 = await fetchAndDecode(url, init);
5762 singleFetchDfd.resolve(data2.data);
5763 } catch (e) {
5764 singleFetchDfd.reject(e);
5765 }
5766 }
5767 await resolvePromise;
5768 return results;
5769}
5770async function singleFetchLoaderFetcherStrategy(request, matches) {
5771 let fetcherMatch = matches.find((m) => m.shouldLoad);
5772 invariant2(fetcherMatch, "No fetcher match found");
5773 let result = await fetcherMatch.resolve(async (handler) => {
5774 let url = stripIndexParam(singleFetchUrl(request.url));
5775 let init = await createRequestInit(request);
5776 return fetchSingleLoader(handler, url, init, fetcherMatch.route.id);
5777 });
5778 return { [fetcherMatch.route.id]: result };
5779}
5780function fetchSingleLoader(handler, url, init, routeId) {
5781 return handler(async () => {
5782 let singleLoaderUrl = new URL(url);
5783 singleLoaderUrl.searchParams.set("_routes", routeId);
5784 let { data: data2 } = await fetchAndDecode(singleLoaderUrl, init);
5785 return unwrapSingleFetchResults(data2, routeId);
5786 });
5787}
5788function stripIndexParam(url) {
5789 let indexValues = url.searchParams.getAll("index");
5790 url.searchParams.delete("index");
5791 let indexValuesToKeep = [];
5792 for (let indexValue of indexValues) {
5793 if (indexValue) {
5794 indexValuesToKeep.push(indexValue);
5795 }
5796 }
5797 for (let toKeep of indexValuesToKeep) {
5798 url.searchParams.append("index", toKeep);
5799 }
5800 return url;
5801}
5802function singleFetchUrl(reqUrl) {
5803 let url = typeof reqUrl === "string" ? new URL(
5804 reqUrl,
5805 // This can be called during the SSR flow via PrefetchPageLinksImpl so
5806 // don't assume window is available
5807 typeof window === "undefined" ? "server://singlefetch/" : window.location.origin
5808 ) : reqUrl;
5809 if (url.pathname === "/") {
5810 url.pathname = "_root.data";
5811 } else {
5812 url.pathname = `${url.pathname.replace(/\/$/, "")}.data`;
5813 }
5814 return url;
5815}
5816async function fetchAndDecode(url, init) {
5817 let res = await fetch(url, init);
5818 if (res.status === 404 && !res.headers.has("X-Remix-Response")) {
5819 throw new ErrorResponseImpl(404, "Not Found", true);
5820 }
5821 invariant2(res.body, "No response body to decode");
5822 try {
5823 let decoded = await decodeViaTurboStream(res.body, window);
5824 return { status: res.status, data: decoded.value };
5825 } catch (e) {
5826 throw new Error("Unable to decode turbo-stream response");
5827 }
5828}
5829function decodeViaTurboStream(body, global2) {
5830 return decode(body, {
5831 plugins: [
5832 (type, ...rest) => {
5833 if (type === "SanitizedError") {
5834 let [name, message, stack] = rest;
5835 let Constructor = Error;
5836 if (name && name in global2 && typeof global2[name] === "function") {
5837 Constructor = global2[name];
5838 }
5839 let error = new Constructor(message);
5840 error.stack = stack;
5841 return { value: error };
5842 }
5843 if (type === "ErrorResponse") {
5844 let [data2, status, statusText] = rest;
5845 return {
5846 value: new ErrorResponseImpl(status, statusText, data2)
5847 };
5848 }
5849 if (type === "SingleFetchRedirect") {
5850 return { value: { [SingleFetchRedirectSymbol]: rest[0] } };
5851 }
5852 if (type === "SingleFetchClassInstance") {
5853 return { value: rest[0] };
5854 }
5855 if (type === "SingleFetchFallback") {
5856 return { value: void 0 };
5857 }
5858 }
5859 ]
5860 });
5861}
5862function unwrapSingleFetchResults(results, routeId) {
5863 let redirect2 = results[SingleFetchRedirectSymbol];
5864 if (redirect2) {
5865 return unwrapSingleFetchResult(redirect2, routeId);
5866 }
5867 return results[routeId] !== void 0 ? unwrapSingleFetchResult(results[routeId], routeId) : null;
5868}
5869function unwrapSingleFetchResult(result, routeId) {
5870 if ("error" in result) {
5871 throw result.error;
5872 } else if ("redirect" in result) {
5873 let headers = {};
5874 if (result.revalidate) {
5875 headers["X-Remix-Revalidate"] = "yes";
5876 }
5877 if (result.reload) {
5878 headers["X-Remix-Reload-Document"] = "yes";
5879 }
5880 if (result.replace) {
5881 headers["X-Remix-Replace"] = "yes";
5882 }
5883 return redirect(result.redirect, { status: result.status, headers });
5884 } else if ("data" in result) {
5885 return result.data;
5886 } else {
5887 throw new Error(`No response found for routeId "${routeId}"`);
5888 }
5889}
5890function createDeferred2() {
5891 let resolve;
5892 let reject;
5893 let promise = new Promise((res, rej) => {
5894 resolve = async (val) => {
5895 res(val);
5896 try {
5897 await promise;
5898 } catch (e) {
5899 }
5900 };
5901 reject = async (error) => {
5902 rej(error);
5903 try {
5904 await promise;
5905 } catch (e) {
5906 }
5907 };
5908 });
5909 return {
5910 promise,
5911 //@ts-ignore
5912 resolve,
5913 //@ts-ignore
5914 reject
5915 };
5916}
5917
5918// lib/dom/ssr/fog-of-war.ts
5919import * as React8 from "react";
5920
5921// lib/dom/ssr/routes.tsx
5922import * as React7 from "react";
5923
5924// lib/dom/ssr/errorBoundaries.tsx
5925import * as React5 from "react";
5926var RemixErrorBoundary = class extends React5.Component {
5927 constructor(props) {
5928 super(props);
5929 this.state = { error: props.error || null, location: props.location };
5930 }
5931 static getDerivedStateFromError(error) {
5932 return { error };
5933 }
5934 static getDerivedStateFromProps(props, state) {
5935 if (state.location !== props.location) {
5936 return { error: props.error || null, location: props.location };
5937 }
5938 return { error: props.error || state.error, location: state.location };
5939 }
5940 render() {
5941 if (this.state.error) {
5942 return /* @__PURE__ */ React5.createElement(
5943 RemixRootDefaultErrorBoundary,
5944 {
5945 error: this.state.error,
5946 isOutsideRemixApp: true
5947 }
5948 );
5949 } else {
5950 return this.props.children;
5951 }
5952 }
5953};
5954function RemixRootDefaultErrorBoundary({
5955 error,
5956 isOutsideRemixApp
5957}) {
5958 console.error(error);
5959 let heyDeveloper = /* @__PURE__ */ React5.createElement(
5960 "script",
5961 {
5962 dangerouslySetInnerHTML: {
5963 __html: `
5964 console.log(
5965 "\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."
5966 );
5967 `
5968 }
5969 }
5970 );
5971 if (isRouteErrorResponse(error)) {
5972 return /* @__PURE__ */ React5.createElement(BoundaryShell, { title: "Unhandled Thrown Response!" }, /* @__PURE__ */ React5.createElement("h1", { style: { fontSize: "24px" } }, error.status, " ", error.statusText), heyDeveloper);
5973 }
5974 let errorInstance;
5975 if (error instanceof Error) {
5976 errorInstance = error;
5977 } else {
5978 let errorString = error == null ? "Unknown Error" : typeof error === "object" && "toString" in error ? error.toString() : JSON.stringify(error);
5979 errorInstance = new Error(errorString);
5980 }
5981 return /* @__PURE__ */ React5.createElement(
5982 BoundaryShell,
5983 {
5984 title: "Application Error!",
5985 isOutsideRemixApp
5986 },
5987 /* @__PURE__ */ React5.createElement("h1", { style: { fontSize: "24px" } }, "Application Error"),
5988 /* @__PURE__ */ React5.createElement(
5989 "pre",
5990 {
5991 style: {
5992 padding: "2rem",
5993 background: "hsla(10, 50%, 50%, 0.1)",
5994 color: "red",
5995 overflow: "auto"
5996 }
5997 },
5998 errorInstance.stack
5999 ),
6000 heyDeveloper
6001 );
6002}
6003function BoundaryShell({
6004 title,
6005 renderScripts,
6006 isOutsideRemixApp,
6007 children
6008}) {
6009 let { routeModules } = useFrameworkContext();
6010 if (routeModules.root?.Layout && !isOutsideRemixApp) {
6011 return children;
6012 }
6013 return /* @__PURE__ */ React5.createElement("html", { lang: "en" }, /* @__PURE__ */ React5.createElement("head", null, /* @__PURE__ */ React5.createElement("meta", { charSet: "utf-8" }), /* @__PURE__ */ React5.createElement(
6014 "meta",
6015 {
6016 name: "viewport",
6017 content: "width=device-width,initial-scale=1,viewport-fit=cover"
6018 }
6019 ), /* @__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)));
6020}
6021
6022// lib/dom/ssr/fallback.tsx
6023import * as React6 from "react";
6024function RemixRootDefaultHydrateFallback() {
6025 return /* @__PURE__ */ React6.createElement(BoundaryShell, { title: "Loading...", renderScripts: true }, /* @__PURE__ */ React6.createElement(
6026 "script",
6027 {
6028 dangerouslySetInnerHTML: {
6029 __html: `
6030 console.log(
6031 "\u{1F4BF} Hey developer \u{1F44B}. You can provide a way better UX than this " +
6032 "when your app is loading JS modules and/or running \`clientLoader\` " +
6033 "functions. Check out https://remix.run/route/hydrate-fallback " +
6034 "for more information."
6035 );
6036 `
6037 }
6038 }
6039 ));
6040}
6041
6042// lib/dom/ssr/routes.tsx
6043function groupRoutesByParentId(manifest) {
6044 let routes = {};
6045 Object.values(manifest).forEach((route) => {
6046 if (route) {
6047 let parentId = route.parentId || "";
6048 if (!routes[parentId]) {
6049 routes[parentId] = [];
6050 }
6051 routes[parentId].push(route);
6052 }
6053 });
6054 return routes;
6055}
6056function getRouteComponents(route, routeModule, isSpaMode) {
6057 let Component4 = getRouteModuleComponent(routeModule);
6058 let HydrateFallback = routeModule.HydrateFallback && (!isSpaMode || route.id === "root") ? routeModule.HydrateFallback : route.id === "root" ? RemixRootDefaultHydrateFallback : void 0;
6059 let ErrorBoundary = routeModule.ErrorBoundary ? routeModule.ErrorBoundary : route.id === "root" ? () => /* @__PURE__ */ React7.createElement(RemixRootDefaultErrorBoundary, { error: useRouteError() }) : void 0;
6060 if (route.id === "root" && routeModule.Layout) {
6061 return {
6062 ...Component4 ? {
6063 element: /* @__PURE__ */ React7.createElement(routeModule.Layout, null, /* @__PURE__ */ React7.createElement(Component4, null))
6064 } : { Component: Component4 },
6065 ...ErrorBoundary ? {
6066 errorElement: /* @__PURE__ */ React7.createElement(routeModule.Layout, null, /* @__PURE__ */ React7.createElement(ErrorBoundary, null))
6067 } : { ErrorBoundary },
6068 ...HydrateFallback ? {
6069 hydrateFallbackElement: /* @__PURE__ */ React7.createElement(routeModule.Layout, null, /* @__PURE__ */ React7.createElement(HydrateFallback, null))
6070 } : { HydrateFallback }
6071 };
6072 }
6073 return { Component: Component4, ErrorBoundary, HydrateFallback };
6074}
6075function createServerRoutes(manifest, routeModules, future, isSpaMode, parentId = "", routesByParentId = groupRoutesByParentId(manifest), spaModeLazyPromise = Promise.resolve({ Component: () => null })) {
6076 return (routesByParentId[parentId] || []).map((route) => {
6077 let routeModule = routeModules[route.id];
6078 invariant2(
6079 routeModule,
6080 "No `routeModule` available to create server routes"
6081 );
6082 let dataRoute = {
6083 ...getRouteComponents(route, routeModule, isSpaMode),
6084 caseSensitive: route.caseSensitive,
6085 id: route.id,
6086 index: route.index,
6087 path: route.path,
6088 handle: routeModule.handle,
6089 // For SPA Mode, all routes are lazy except root. However we tell the
6090 // router root is also lazy here too since we don't need a full
6091 // implementation - we just need a `lazy` prop to tell the RR rendering
6092 // where to stop which is always at the root route in SPA mode
6093 lazy: isSpaMode ? () => spaModeLazyPromise : void 0,
6094 // For partial hydration rendering, we need to indicate when the route
6095 // has a loader/clientLoader, but it won't ever be called during the static
6096 // render, so just give it a no-op function so we can render down to the
6097 // proper fallback
6098 loader: route.hasLoader || route.hasClientLoader ? () => null : void 0
6099 // We don't need action/shouldRevalidate on these routes since they're
6100 // for a static render
6101 };
6102 let children = createServerRoutes(
6103 manifest,
6104 routeModules,
6105 future,
6106 isSpaMode,
6107 route.id,
6108 routesByParentId,
6109 spaModeLazyPromise
6110 );
6111 if (children.length > 0) dataRoute.children = children;
6112 return dataRoute;
6113 });
6114}
6115function createClientRoutesWithHMRRevalidationOptOut(needsRevalidation, manifest, routeModulesCache, initialState, future, isSpaMode) {
6116 return createClientRoutes(
6117 manifest,
6118 routeModulesCache,
6119 initialState,
6120 isSpaMode,
6121 "",
6122 groupRoutesByParentId(manifest),
6123 needsRevalidation
6124 );
6125}
6126function preventInvalidServerHandlerCall(type, route, isSpaMode) {
6127 if (isSpaMode) {
6128 let fn2 = type === "action" ? "serverAction()" : "serverLoader()";
6129 let msg2 = `You cannot call ${fn2} in SPA Mode (routeId: "${route.id}")`;
6130 console.error(msg2);
6131 throw new ErrorResponseImpl(400, "Bad Request", new Error(msg2), true);
6132 }
6133 let fn = type === "action" ? "serverAction()" : "serverLoader()";
6134 let msg = `You are trying to call ${fn} on a route that does not have a server ${type} (routeId: "${route.id}")`;
6135 if (type === "loader" && !route.hasLoader || type === "action" && !route.hasAction) {
6136 console.error(msg);
6137 throw new ErrorResponseImpl(400, "Bad Request", new Error(msg), true);
6138 }
6139}
6140function noActionDefinedError(type, routeId) {
6141 let article = type === "clientAction" ? "a" : "an";
6142 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`;
6143 console.error(msg);
6144 throw new ErrorResponseImpl(405, "Method Not Allowed", new Error(msg), true);
6145}
6146function createClientRoutes(manifest, routeModulesCache, initialState, isSpaMode, parentId = "", routesByParentId = groupRoutesByParentId(manifest), needsRevalidation) {
6147 return (routesByParentId[parentId] || []).map((route) => {
6148 let routeModule = routeModulesCache[route.id];
6149 function fetchServerHandler(singleFetch) {
6150 invariant2(
6151 typeof singleFetch === "function",
6152 "No single fetch function available for route handler"
6153 );
6154 return singleFetch();
6155 }
6156 function fetchServerLoader(singleFetch) {
6157 if (!route.hasLoader) return Promise.resolve(null);
6158 return fetchServerHandler(singleFetch);
6159 }
6160 function fetchServerAction(singleFetch) {
6161 if (!route.hasAction) {
6162 throw noActionDefinedError("action", route.id);
6163 }
6164 return fetchServerHandler(singleFetch);
6165 }
6166 async function prefetchStylesAndCallHandler(handler) {
6167 let cachedModule = routeModulesCache[route.id];
6168 let linkPrefetchPromise = cachedModule ? prefetchStyleLinks(route, cachedModule) : Promise.resolve();
6169 try {
6170 return handler();
6171 } finally {
6172 await linkPrefetchPromise;
6173 }
6174 }
6175 let dataRoute = {
6176 id: route.id,
6177 index: route.index,
6178 path: route.path
6179 };
6180 if (routeModule) {
6181 Object.assign(dataRoute, {
6182 ...dataRoute,
6183 ...getRouteComponents(route, routeModule, isSpaMode),
6184 handle: routeModule.handle,
6185 shouldRevalidate: getShouldRevalidateFunction(
6186 routeModule,
6187 route.id,
6188 needsRevalidation
6189 )
6190 });
6191 let hasInitialData = initialState && initialState.loaderData && route.id in initialState.loaderData;
6192 let initialData = hasInitialData ? initialState?.loaderData?.[route.id] : void 0;
6193 let hasInitialError = initialState && initialState.errors && route.id in initialState.errors;
6194 let initialError = hasInitialError ? initialState?.errors?.[route.id] : void 0;
6195 let isHydrationRequest = needsRevalidation == null && (routeModule.clientLoader?.hydrate === true || !route.hasLoader);
6196 dataRoute.loader = async ({ request, params }, singleFetch) => {
6197 try {
6198 let result = await prefetchStylesAndCallHandler(async () => {
6199 invariant2(
6200 routeModule,
6201 "No `routeModule` available for critical-route loader"
6202 );
6203 if (!routeModule.clientLoader) {
6204 if (isSpaMode) return null;
6205 return fetchServerLoader(singleFetch);
6206 }
6207 return routeModule.clientLoader({
6208 request,
6209 params,
6210 async serverLoader() {
6211 preventInvalidServerHandlerCall("loader", route, isSpaMode);
6212 if (isHydrationRequest) {
6213 if (hasInitialData) {
6214 return initialData;
6215 }
6216 if (hasInitialError) {
6217 throw initialError;
6218 }
6219 }
6220 return fetchServerLoader(singleFetch);
6221 }
6222 });
6223 });
6224 return result;
6225 } finally {
6226 isHydrationRequest = false;
6227 }
6228 };
6229 dataRoute.loader.hydrate = shouldHydrateRouteLoader(
6230 route,
6231 routeModule,
6232 isSpaMode
6233 );
6234 dataRoute.action = ({ request, params }, singleFetch) => {
6235 return prefetchStylesAndCallHandler(async () => {
6236 invariant2(
6237 routeModule,
6238 "No `routeModule` available for critical-route action"
6239 );
6240 if (!routeModule.clientAction) {
6241 if (isSpaMode) {
6242 throw noActionDefinedError("clientAction", route.id);
6243 }
6244 return fetchServerAction(singleFetch);
6245 }
6246 return routeModule.clientAction({
6247 request,
6248 params,
6249 async serverAction() {
6250 preventInvalidServerHandlerCall("action", route, isSpaMode);
6251 return fetchServerAction(singleFetch);
6252 }
6253 });
6254 });
6255 };
6256 } else {
6257 if (!route.hasClientLoader) {
6258 dataRoute.loader = ({ request }, singleFetch) => prefetchStylesAndCallHandler(() => {
6259 if (isSpaMode) return Promise.resolve(null);
6260 return fetchServerLoader(singleFetch);
6261 });
6262 }
6263 if (!route.hasClientAction) {
6264 dataRoute.action = ({ request }, singleFetch) => prefetchStylesAndCallHandler(() => {
6265 if (isSpaMode) {
6266 throw noActionDefinedError("clientAction", route.id);
6267 }
6268 return fetchServerAction(singleFetch);
6269 });
6270 }
6271 dataRoute.lazy = async () => {
6272 let mod = await loadRouteModuleWithBlockingLinks(
6273 route,
6274 routeModulesCache
6275 );
6276 let lazyRoute = { ...mod };
6277 if (mod.clientLoader) {
6278 let clientLoader = mod.clientLoader;
6279 lazyRoute.loader = (args, singleFetch) => clientLoader({
6280 ...args,
6281 async serverLoader() {
6282 preventInvalidServerHandlerCall("loader", route, isSpaMode);
6283 return fetchServerLoader(singleFetch);
6284 }
6285 });
6286 }
6287 if (mod.clientAction) {
6288 let clientAction = mod.clientAction;
6289 lazyRoute.action = (args, singleFetch) => clientAction({
6290 ...args,
6291 async serverAction() {
6292 preventInvalidServerHandlerCall("action", route, isSpaMode);
6293 return fetchServerAction(singleFetch);
6294 }
6295 });
6296 }
6297 return {
6298 ...lazyRoute.loader ? { loader: lazyRoute.loader } : {},
6299 ...lazyRoute.action ? { action: lazyRoute.action } : {},
6300 hasErrorBoundary: lazyRoute.hasErrorBoundary,
6301 shouldRevalidate: getShouldRevalidateFunction(
6302 lazyRoute,
6303 route.id,
6304 needsRevalidation
6305 ),
6306 handle: lazyRoute.handle,
6307 // No need to wrap these in layout since the root route is never
6308 // loaded via route.lazy()
6309 Component: lazyRoute.Component,
6310 ErrorBoundary: lazyRoute.ErrorBoundary
6311 };
6312 };
6313 }
6314 let children = createClientRoutes(
6315 manifest,
6316 routeModulesCache,
6317 initialState,
6318 isSpaMode,
6319 route.id,
6320 routesByParentId,
6321 needsRevalidation
6322 );
6323 if (children.length > 0) dataRoute.children = children;
6324 return dataRoute;
6325 });
6326}
6327function getShouldRevalidateFunction(route, routeId, needsRevalidation) {
6328 if (needsRevalidation) {
6329 return wrapShouldRevalidateForHdr(
6330 routeId,
6331 route.shouldRevalidate,
6332 needsRevalidation
6333 );
6334 }
6335 if (route.shouldRevalidate) {
6336 let fn = route.shouldRevalidate;
6337 return (opts) => fn({ ...opts, defaultShouldRevalidate: true });
6338 }
6339 return route.shouldRevalidate;
6340}
6341function wrapShouldRevalidateForHdr(routeId, routeShouldRevalidate, needsRevalidation) {
6342 let handledRevalidation = false;
6343 return (arg) => {
6344 if (!handledRevalidation) {
6345 handledRevalidation = true;
6346 return needsRevalidation.has(routeId);
6347 }
6348 return routeShouldRevalidate ? routeShouldRevalidate(arg) : arg.defaultShouldRevalidate;
6349 };
6350}
6351async function loadRouteModuleWithBlockingLinks(route, routeModules) {
6352 let routeModule = await loadRouteModule(route, routeModules);
6353 await prefetchStyleLinks(route, routeModule);
6354 return {
6355 Component: getRouteModuleComponent(routeModule),
6356 ErrorBoundary: routeModule.ErrorBoundary,
6357 clientAction: routeModule.clientAction,
6358 clientLoader: routeModule.clientLoader,
6359 handle: routeModule.handle,
6360 links: routeModule.links,
6361 meta: routeModule.meta,
6362 shouldRevalidate: routeModule.shouldRevalidate
6363 };
6364}
6365function getRouteModuleComponent(routeModule) {
6366 if (routeModule.default == null) return void 0;
6367 let isEmptyObject = typeof routeModule.default === "object" && Object.keys(routeModule.default).length === 0;
6368 if (!isEmptyObject) {
6369 return routeModule.default;
6370 }
6371}
6372function shouldHydrateRouteLoader(route, routeModule, isSpaMode) {
6373 return isSpaMode && route.id !== "root" || routeModule.clientLoader != null && (routeModule.clientLoader.hydrate === true || route.hasLoader !== true);
6374}
6375
6376// lib/dom/ssr/fog-of-war.ts
6377var nextPaths = /* @__PURE__ */ new Set();
6378var discoveredPathsMaxSize = 1e3;
6379var discoveredPaths = /* @__PURE__ */ new Set();
6380var URL_LIMIT = 7680;
6381function isFogOfWarEnabled(isSpaMode) {
6382 return !isSpaMode;
6383}
6384function getPartialManifest(manifest, router) {
6385 let routeIds = new Set(router.state.matches.map((m) => m.route.id));
6386 let segments = router.state.location.pathname.split("/").filter(Boolean);
6387 let paths = ["/"];
6388 segments.pop();
6389 while (segments.length > 0) {
6390 paths.push(`/${segments.join("/")}`);
6391 segments.pop();
6392 }
6393 paths.forEach((path) => {
6394 let matches = matchRoutes(router.routes, path, router.basename);
6395 if (matches) {
6396 matches.forEach((m) => routeIds.add(m.route.id));
6397 }
6398 });
6399 let initialRoutes = [...routeIds].reduce(
6400 (acc, id) => Object.assign(acc, { [id]: manifest.routes[id] }),
6401 {}
6402 );
6403 return {
6404 ...manifest,
6405 routes: initialRoutes
6406 };
6407}
6408function getPatchRoutesOnNavigationFunction(manifest, routeModules, isSpaMode, basename) {
6409 if (!isFogOfWarEnabled(isSpaMode)) {
6410 return void 0;
6411 }
6412 return async ({ path, patch }) => {
6413 if (discoveredPaths.has(path)) {
6414 return;
6415 }
6416 await fetchAndApplyManifestPatches(
6417 [path],
6418 manifest,
6419 routeModules,
6420 isSpaMode,
6421 basename,
6422 patch
6423 );
6424 };
6425}
6426function useFogOFWarDiscovery(router, manifest, routeModules, isSpaMode) {
6427 React8.useEffect(() => {
6428 if (!isFogOfWarEnabled(isSpaMode) || navigator.connection?.saveData === true) {
6429 return;
6430 }
6431 function registerElement(el) {
6432 let path = el.tagName === "FORM" ? el.getAttribute("action") : el.getAttribute("href");
6433 if (!path) {
6434 return;
6435 }
6436 let url = new URL(path, window.location.origin);
6437 if (!discoveredPaths.has(url.pathname)) {
6438 nextPaths.add(url.pathname);
6439 }
6440 }
6441 async function fetchPatches() {
6442 let lazyPaths = Array.from(nextPaths.keys()).filter((path) => {
6443 if (discoveredPaths.has(path)) {
6444 nextPaths.delete(path);
6445 return false;
6446 }
6447 return true;
6448 });
6449 if (lazyPaths.length === 0) {
6450 return;
6451 }
6452 try {
6453 await fetchAndApplyManifestPatches(
6454 lazyPaths,
6455 manifest,
6456 routeModules,
6457 isSpaMode,
6458 router.basename,
6459 router.patchRoutes
6460 );
6461 } catch (e) {
6462 console.error("Failed to fetch manifest patches", e);
6463 }
6464 }
6465 document.body.querySelectorAll("a[data-discover], form[data-discover]").forEach((el) => registerElement(el));
6466 fetchPatches();
6467 let debouncedFetchPatches = debounce(fetchPatches, 100);
6468 function isElement(node) {
6469 return node.nodeType === Node.ELEMENT_NODE;
6470 }
6471 let observer = new MutationObserver((records) => {
6472 let elements = /* @__PURE__ */ new Set();
6473 records.forEach((r) => {
6474 [r.target, ...r.addedNodes].forEach((node) => {
6475 if (!isElement(node)) return;
6476 if (node.tagName === "A" && node.getAttribute("data-discover")) {
6477 elements.add(node);
6478 } else if (node.tagName === "FORM" && node.getAttribute("data-discover")) {
6479 elements.add(node);
6480 }
6481 if (node.tagName !== "A") {
6482 node.querySelectorAll("a[data-discover], form[data-discover]").forEach((el) => elements.add(el));
6483 }
6484 });
6485 });
6486 elements.forEach((el) => registerElement(el));
6487 debouncedFetchPatches();
6488 });
6489 observer.observe(document.documentElement, {
6490 subtree: true,
6491 childList: true,
6492 attributes: true,
6493 attributeFilter: ["data-discover", "href", "action"]
6494 });
6495 return () => observer.disconnect();
6496 }, [isSpaMode, manifest, routeModules, router]);
6497}
6498async function fetchAndApplyManifestPatches(paths, manifest, routeModules, isSpaMode, basename, patchRoutes) {
6499 let manifestPath = `${basename != null ? basename : "/"}/__manifest`.replace(
6500 /\/+/g,
6501 "/"
6502 );
6503 let url = new URL(manifestPath, window.location.origin);
6504 paths.sort().forEach((path) => url.searchParams.append("p", path));
6505 url.searchParams.set("version", manifest.version);
6506 if (url.toString().length > URL_LIMIT) {
6507 nextPaths.clear();
6508 return;
6509 }
6510 let res = await fetch(url);
6511 if (!res.ok) {
6512 throw new Error(`${res.status} ${res.statusText}`);
6513 } else if (res.status >= 400) {
6514 throw new Error(await res.text());
6515 }
6516 let serverPatches = await res.json();
6517 let knownRoutes = new Set(Object.keys(manifest.routes));
6518 let patches = Object.values(serverPatches).reduce((acc, route) => {
6519 if (route && !knownRoutes.has(route.id)) {
6520 acc[route.id] = route;
6521 }
6522 return acc;
6523 }, {});
6524 Object.assign(manifest.routes, patches);
6525 paths.forEach((p) => addToFifoQueue(p, discoveredPaths));
6526 let parentIds = /* @__PURE__ */ new Set();
6527 Object.values(patches).forEach((patch) => {
6528 if (patch && (!patch.parentId || !patches[patch.parentId])) {
6529 parentIds.add(patch.parentId);
6530 }
6531 });
6532 parentIds.forEach(
6533 (parentId) => patchRoutes(
6534 parentId || null,
6535 createClientRoutes(patches, routeModules, null, isSpaMode, parentId)
6536 )
6537 );
6538}
6539function addToFifoQueue(path, queue) {
6540 if (queue.size >= discoveredPathsMaxSize) {
6541 let first = queue.values().next().value;
6542 queue.delete(first);
6543 }
6544 queue.add(path);
6545}
6546function debounce(callback, wait) {
6547 let timeoutId;
6548 return (...args) => {
6549 window.clearTimeout(timeoutId);
6550 timeoutId = window.setTimeout(() => callback(...args), wait);
6551 };
6552}
6553
6554// lib/dom/ssr/components.tsx
6555function useDataRouterContext2() {
6556 let context = React9.useContext(DataRouterContext);
6557 invariant2(
6558 context,
6559 "You must render this element inside a <DataRouterContext.Provider> element"
6560 );
6561 return context;
6562}
6563function useDataRouterStateContext() {
6564 let context = React9.useContext(DataRouterStateContext);
6565 invariant2(
6566 context,
6567 "You must render this element inside a <DataRouterStateContext.Provider> element"
6568 );
6569 return context;
6570}
6571var FrameworkContext = React9.createContext(void 0);
6572FrameworkContext.displayName = "FrameworkContext";
6573function useFrameworkContext() {
6574 let context = React9.useContext(FrameworkContext);
6575 invariant2(
6576 context,
6577 "You must render this element inside a <HydratedRouter> element"
6578 );
6579 return context;
6580}
6581function usePrefetchBehavior(prefetch, theirElementProps) {
6582 let frameworkContext = React9.useContext(FrameworkContext);
6583 let [maybePrefetch, setMaybePrefetch] = React9.useState(false);
6584 let [shouldPrefetch, setShouldPrefetch] = React9.useState(false);
6585 let { onFocus, onBlur, onMouseEnter, onMouseLeave, onTouchStart } = theirElementProps;
6586 let ref = React9.useRef(null);
6587 React9.useEffect(() => {
6588 if (prefetch === "render") {
6589 setShouldPrefetch(true);
6590 }
6591 if (prefetch === "viewport") {
6592 let callback = (entries) => {
6593 entries.forEach((entry) => {
6594 setShouldPrefetch(entry.isIntersecting);
6595 });
6596 };
6597 let observer = new IntersectionObserver(callback, { threshold: 0.5 });
6598 if (ref.current) observer.observe(ref.current);
6599 return () => {
6600 observer.disconnect();
6601 };
6602 }
6603 }, [prefetch]);
6604 React9.useEffect(() => {
6605 if (maybePrefetch) {
6606 let id = setTimeout(() => {
6607 setShouldPrefetch(true);
6608 }, 100);
6609 return () => {
6610 clearTimeout(id);
6611 };
6612 }
6613 }, [maybePrefetch]);
6614 let setIntent = () => {
6615 setMaybePrefetch(true);
6616 };
6617 let cancelIntent = () => {
6618 setMaybePrefetch(false);
6619 setShouldPrefetch(false);
6620 };
6621 if (!frameworkContext) {
6622 return [false, ref, {}];
6623 }
6624 if (prefetch !== "intent") {
6625 return [shouldPrefetch, ref, {}];
6626 }
6627 return [
6628 shouldPrefetch,
6629 ref,
6630 {
6631 onFocus: composeEventHandlers(onFocus, setIntent),
6632 onBlur: composeEventHandlers(onBlur, cancelIntent),
6633 onMouseEnter: composeEventHandlers(onMouseEnter, setIntent),
6634 onMouseLeave: composeEventHandlers(onMouseLeave, cancelIntent),
6635 onTouchStart: composeEventHandlers(onTouchStart, setIntent)
6636 }
6637 ];
6638}
6639function composeEventHandlers(theirHandler, ourHandler) {
6640 return (event) => {
6641 theirHandler && theirHandler(event);
6642 if (!event.defaultPrevented) {
6643 ourHandler(event);
6644 }
6645 };
6646}
6647function getActiveMatches(matches, errors, isSpaMode) {
6648 if (isSpaMode && !isHydrated) {
6649 return [matches[0]];
6650 }
6651 if (errors) {
6652 let errorIdx = matches.findIndex((m) => errors[m.route.id] !== void 0);
6653 return matches.slice(0, errorIdx + 1);
6654 }
6655 return matches;
6656}
6657function Links() {
6658 let { isSpaMode, manifest, routeModules, criticalCss } = useFrameworkContext();
6659 let { errors, matches: routerMatches } = useDataRouterStateContext();
6660 let matches = getActiveMatches(routerMatches, errors, isSpaMode);
6661 let keyedLinks = React9.useMemo(
6662 () => getKeyedLinksForMatches(matches, routeModules, manifest),
6663 [matches, routeModules, manifest]
6664 );
6665 return /* @__PURE__ */ React9.createElement(React9.Fragment, null, criticalCss ? /* @__PURE__ */ React9.createElement("style", { dangerouslySetInnerHTML: { __html: criticalCss } }) : null, keyedLinks.map(
6666 ({ key, link }) => isPageLinkDescriptor(link) ? /* @__PURE__ */ React9.createElement(PrefetchPageLinks, { key, ...link }) : /* @__PURE__ */ React9.createElement("link", { key, ...link })
6667 ));
6668}
6669function PrefetchPageLinks({
6670 page,
6671 ...dataLinkProps
6672}) {
6673 let { router } = useDataRouterContext2();
6674 let matches = React9.useMemo(
6675 () => matchRoutes(router.routes, page, router.basename),
6676 [router.routes, page, router.basename]
6677 );
6678 if (!matches) {
6679 console.warn(`Tried to prefetch ${page} but no routes matched.`);
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.0.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 abortDelay,
8063 nonce
8064}) {
8065 if (typeof url === "string") {
8066 url = new URL(url);
8067 }
8068 let { manifest, routeModules, criticalCss, serverHandoffString } = context;
8069 let routes = createServerRoutes(
8070 manifest.routes,
8071 routeModules,
8072 context.future,
8073 context.isSpaMode
8074 );
8075 context.staticHandlerContext.loaderData = {
8076 ...context.staticHandlerContext.loaderData
8077 };
8078 for (let match of context.staticHandlerContext.matches) {
8079 let routeId = match.route.id;
8080 let route = routeModules[routeId];
8081 let manifestRoute = context.manifest.routes[routeId];
8082 if (route && manifestRoute && shouldHydrateRouteLoader(manifestRoute, route, context.isSpaMode) && (route.HydrateFallback || !manifestRoute.hasLoader)) {
8083 delete context.staticHandlerContext.loaderData[routeId];
8084 }
8085 }
8086 let router = createStaticRouter(routes, context.staticHandlerContext);
8087 return /* @__PURE__ */ React12.createElement(React12.Fragment, null, /* @__PURE__ */ React12.createElement(
8088 FrameworkContext.Provider,
8089 {
8090 value: {
8091 manifest,
8092 routeModules,
8093 criticalCss,
8094 serverHandoffString,
8095 future: context.future,
8096 isSpaMode: context.isSpaMode,
8097 serializeError: context.serializeError,
8098 abortDelay,
8099 renderMeta: context.renderMeta
8100 }
8101 },
8102 /* @__PURE__ */ React12.createElement(RemixErrorBoundary, { location: router.state.location }, /* @__PURE__ */ React12.createElement(
8103 StaticRouterProvider,
8104 {
8105 router,
8106 context: context.staticHandlerContext,
8107 hydrate: false
8108 }
8109 ))
8110 ), context.serverHandoffStream ? /* @__PURE__ */ React12.createElement(React12.Suspense, null, /* @__PURE__ */ React12.createElement(
8111 StreamTransfer,
8112 {
8113 context,
8114 identifier: 0,
8115 reader: context.serverHandoffStream.getReader(),
8116 textDecoder: new TextDecoder(),
8117 nonce
8118 }
8119 )) : null);
8120}
8121
8122// lib/dom/ssr/routes-test-stub.tsx
8123import * as React13 from "react";
8124function createRoutesStub(routes, context = {}) {
8125 return function RoutesTestStub({
8126 initialEntries,
8127 initialIndex,
8128 hydrationData,
8129 future
8130 }) {
8131 let routerRef = React13.useRef();
8132 let remixContextRef = React13.useRef();
8133 if (routerRef.current == null) {
8134 remixContextRef.current = {
8135 future: {},
8136 manifest: {
8137 routes: {},
8138 entry: { imports: [], module: "" },
8139 url: "",
8140 version: ""
8141 },
8142 routeModules: {},
8143 isSpaMode: false
8144 };
8145 let patched = processRoutes(
8146 // @ts-expect-error loader/action context types don't match :/
8147 convertRoutesToDataRoutes(routes, (r) => r),
8148 context,
8149 remixContextRef.current.manifest,
8150 remixContextRef.current.routeModules
8151 );
8152 routerRef.current = createMemoryRouter(patched, {
8153 initialEntries,
8154 initialIndex,
8155 hydrationData
8156 });
8157 }
8158 return /* @__PURE__ */ React13.createElement(FrameworkContext.Provider, { value: remixContextRef.current }, /* @__PURE__ */ React13.createElement(RouterProvider, { router: routerRef.current }));
8159 };
8160}
8161function processRoutes(routes, context, manifest, routeModules, parentId) {
8162 return routes.map((route) => {
8163 if (!route.id) {
8164 throw new Error(
8165 "Expected a route.id in @remix-run/testing processRoutes() function"
8166 );
8167 }
8168 let { loader, action } = route;
8169 let newRoute = {
8170 id: route.id,
8171 path: route.path,
8172 index: route.index,
8173 Component: route.Component,
8174 HydrateFallback: route.HydrateFallback,
8175 ErrorBoundary: route.ErrorBoundary,
8176 action: action ? (args) => action({ ...args, context }) : void 0,
8177 loader: loader ? (args) => loader({ ...args, context }) : void 0,
8178 handle: route.handle,
8179 shouldRevalidate: route.shouldRevalidate
8180 };
8181 let entryRoute = {
8182 id: route.id,
8183 path: route.path,
8184 index: route.index,
8185 parentId,
8186 hasAction: route.action != null,
8187 hasLoader: route.loader != null,
8188 // When testing routes, you should just be stubbing loader/action, not
8189 // trying to re-implement the full loader/clientLoader/SSR/hydration flow.
8190 // That is better tested via E2E tests.
8191 hasClientAction: false,
8192 hasClientLoader: false,
8193 hasErrorBoundary: route.ErrorBoundary != null,
8194 module: "build/stub-path-to-module.js"
8195 // any need for this?
8196 };
8197 manifest.routes[newRoute.id] = entryRoute;
8198 routeModules[route.id] = {
8199 default: route.Component || Outlet,
8200 ErrorBoundary: route.ErrorBoundary || void 0,
8201 handle: route.handle,
8202 links: route.links,
8203 meta: route.meta,
8204 shouldRevalidate: route.shouldRevalidate
8205 };
8206 if (route.children) {
8207 newRoute.children = processRoutes(
8208 route.children,
8209 context,
8210 manifest,
8211 routeModules,
8212 newRoute.id
8213 );
8214 }
8215 return newRoute;
8216 });
8217}
8218
8219// lib/server-runtime/cookies.ts
8220import { parse, serialize } from "cookie";
8221
8222// lib/server-runtime/crypto.ts
8223var encoder = new TextEncoder();
8224var sign = async (value, secret) => {
8225 let data2 = encoder.encode(value);
8226 let key = await createKey2(secret, ["sign"]);
8227 let signature = await crypto.subtle.sign("HMAC", key, data2);
8228 let hash = btoa(String.fromCharCode(...new Uint8Array(signature))).replace(
8229 /=+$/,
8230 ""
8231 );
8232 return value + "." + hash;
8233};
8234var unsign = async (cookie, secret) => {
8235 let index = cookie.lastIndexOf(".");
8236 let value = cookie.slice(0, index);
8237 let hash = cookie.slice(index + 1);
8238 let data2 = encoder.encode(value);
8239 let key = await createKey2(secret, ["verify"]);
8240 let signature = byteStringToUint8Array(atob(hash));
8241 let valid = await crypto.subtle.verify("HMAC", key, signature, data2);
8242 return valid ? value : false;
8243};
8244var createKey2 = async (secret, usages) => crypto.subtle.importKey(
8245 "raw",
8246 encoder.encode(secret),
8247 { name: "HMAC", hash: "SHA-256" },
8248 false,
8249 usages
8250);
8251function byteStringToUint8Array(byteString) {
8252 let array = new Uint8Array(byteString.length);
8253 for (let i = 0; i < byteString.length; i++) {
8254 array[i] = byteString.charCodeAt(i);
8255 }
8256 return array;
8257}
8258
8259// lib/server-runtime/cookies.ts
8260var createCookie = (name, cookieOptions = {}) => {
8261 let { secrets = [], ...options } = {
8262 path: "/",
8263 sameSite: "lax",
8264 ...cookieOptions
8265 };
8266 warnOnceAboutExpiresCookie(name, options.expires);
8267 return {
8268 get name() {
8269 return name;
8270 },
8271 get isSigned() {
8272 return secrets.length > 0;
8273 },
8274 get expires() {
8275 return typeof options.maxAge !== "undefined" ? new Date(Date.now() + options.maxAge * 1e3) : options.expires;
8276 },
8277 async parse(cookieHeader, parseOptions) {
8278 if (!cookieHeader) return null;
8279 let cookies = parse(cookieHeader, { ...options, ...parseOptions });
8280 if (name in cookies) {
8281 let value = cookies[name];
8282 if (typeof value === "string" && value !== "") {
8283 let decoded = await decodeCookieValue(value, secrets);
8284 return decoded;
8285 } else {
8286 return "";
8287 }
8288 } else {
8289 return null;
8290 }
8291 },
8292 async serialize(value, serializeOptions) {
8293 return serialize(
8294 name,
8295 value === "" ? "" : await encodeCookieValue(value, secrets),
8296 {
8297 ...options,
8298 ...serializeOptions
8299 }
8300 );
8301 }
8302 };
8303};
8304var isCookie = (object) => {
8305 return object != null && typeof object.name === "string" && typeof object.isSigned === "boolean" && typeof object.parse === "function" && typeof object.serialize === "function";
8306};
8307async function encodeCookieValue(value, secrets) {
8308 let encoded = encodeData(value);
8309 if (secrets.length > 0) {
8310 encoded = await sign(encoded, secrets[0]);
8311 }
8312 return encoded;
8313}
8314async function decodeCookieValue(value, secrets) {
8315 if (secrets.length > 0) {
8316 for (let secret of secrets) {
8317 let unsignedValue = await unsign(value, secret);
8318 if (unsignedValue !== false) {
8319 return decodeData(unsignedValue);
8320 }
8321 }
8322 return null;
8323 }
8324 return decodeData(value);
8325}
8326function encodeData(value) {
8327 return btoa(myUnescape(encodeURIComponent(JSON.stringify(value))));
8328}
8329function decodeData(value) {
8330 try {
8331 return JSON.parse(decodeURIComponent(myEscape(atob(value))));
8332 } catch (error) {
8333 return {};
8334 }
8335}
8336function myEscape(value) {
8337 let str = value.toString();
8338 let result = "";
8339 let index = 0;
8340 let chr, code;
8341 while (index < str.length) {
8342 chr = str.charAt(index++);
8343 if (/[\w*+\-./@]/.exec(chr)) {
8344 result += chr;
8345 } else {
8346 code = chr.charCodeAt(0);
8347 if (code < 256) {
8348 result += "%" + hex(code, 2);
8349 } else {
8350 result += "%u" + hex(code, 4).toUpperCase();
8351 }
8352 }
8353 }
8354 return result;
8355}
8356function hex(code, length) {
8357 let result = code.toString(16);
8358 while (result.length < length) result = "0" + result;
8359 return result;
8360}
8361function myUnescape(value) {
8362 let str = value.toString();
8363 let result = "";
8364 let index = 0;
8365 let chr, part;
8366 while (index < str.length) {
8367 chr = str.charAt(index++);
8368 if (chr === "%") {
8369 if (str.charAt(index) === "u") {
8370 part = str.slice(index + 1, index + 5);
8371 if (/^[\da-f]{4}$/i.exec(part)) {
8372 result += String.fromCharCode(parseInt(part, 16));
8373 index += 5;
8374 continue;
8375 }
8376 } else {
8377 part = str.slice(index, index + 2);
8378 if (/^[\da-f]{2}$/i.exec(part)) {
8379 result += String.fromCharCode(parseInt(part, 16));
8380 index += 2;
8381 continue;
8382 }
8383 }
8384 }
8385 result += chr;
8386 }
8387 return result;
8388}
8389function warnOnceAboutExpiresCookie(name, expires) {
8390 warnOnce(
8391 !expires,
8392 `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.`
8393 );
8394}
8395
8396// lib/server-runtime/entry.ts
8397function createEntryRouteModules(manifest) {
8398 return Object.keys(manifest).reduce((memo2, routeId) => {
8399 let route = manifest[routeId];
8400 if (route) {
8401 memo2[routeId] = route.module;
8402 }
8403 return memo2;
8404 }, {});
8405}
8406
8407// lib/server-runtime/mode.ts
8408var ServerMode = /* @__PURE__ */ ((ServerMode2) => {
8409 ServerMode2["Development"] = "development";
8410 ServerMode2["Production"] = "production";
8411 ServerMode2["Test"] = "test";
8412 return ServerMode2;
8413})(ServerMode || {});
8414function isServerMode(value) {
8415 return value === "development" /* Development */ || value === "production" /* Production */ || value === "test" /* Test */;
8416}
8417
8418// lib/server-runtime/errors.ts
8419function sanitizeError(error, serverMode) {
8420 if (error instanceof Error && serverMode !== "development" /* Development */) {
8421 let sanitized = new Error("Unexpected Server Error");
8422 sanitized.stack = void 0;
8423 return sanitized;
8424 }
8425 return error;
8426}
8427function sanitizeErrors(errors, serverMode) {
8428 return Object.entries(errors).reduce((acc, [routeId, error]) => {
8429 return Object.assign(acc, { [routeId]: sanitizeError(error, serverMode) });
8430 }, {});
8431}
8432function serializeError(error, serverMode) {
8433 let sanitized = sanitizeError(error, serverMode);
8434 return {
8435 message: sanitized.message,
8436 stack: sanitized.stack
8437 };
8438}
8439function serializeErrors2(errors, serverMode) {
8440 if (!errors) return null;
8441 let entries = Object.entries(errors);
8442 let serialized = {};
8443 for (let [key, val] of entries) {
8444 if (isRouteErrorResponse(val)) {
8445 serialized[key] = { ...val, __type: "RouteErrorResponse" };
8446 } else if (val instanceof Error) {
8447 let sanitized = sanitizeError(val, serverMode);
8448 serialized[key] = {
8449 message: sanitized.message,
8450 stack: sanitized.stack,
8451 __type: "Error",
8452 // If this is a subclass (i.e., ReferenceError), send up the type so we
8453 // can re-create the same type during hydration. This will only apply
8454 // in dev mode since all production errors are sanitized to normal
8455 // Error instances
8456 ...sanitized.name !== "Error" ? {
8457 __subType: sanitized.name
8458 } : {}
8459 };
8460 } else {
8461 serialized[key] = val;
8462 }
8463 }
8464 return serialized;
8465}
8466
8467// lib/server-runtime/routeMatching.ts
8468function matchServerRoutes(routes, pathname, basename) {
8469 let matches = matchRoutes(
8470 routes,
8471 pathname,
8472 basename
8473 );
8474 if (!matches) return null;
8475 return matches.map((match) => ({
8476 params: match.params,
8477 pathname: match.pathname,
8478 route: match.route
8479 }));
8480}
8481
8482// lib/server-runtime/data.ts
8483async function callRouteHandler(handler, args) {
8484 let result = await handler({
8485 request: stripRoutesParam(stripIndexParam2(args.request)),
8486 params: args.params,
8487 context: args.context
8488 });
8489 if (isDataWithResponseInit(result) && result.init && result.init.status && isRedirectStatusCode(result.init.status)) {
8490 throw new Response(null, result.init);
8491 }
8492 return result;
8493}
8494function stripIndexParam2(request) {
8495 let url = new URL(request.url);
8496 let indexValues = url.searchParams.getAll("index");
8497 url.searchParams.delete("index");
8498 let indexValuesToKeep = [];
8499 for (let indexValue of indexValues) {
8500 if (indexValue) {
8501 indexValuesToKeep.push(indexValue);
8502 }
8503 }
8504 for (let toKeep of indexValuesToKeep) {
8505 url.searchParams.append("index", toKeep);
8506 }
8507 let init = {
8508 method: request.method,
8509 body: request.body,
8510 headers: request.headers,
8511 signal: request.signal
8512 };
8513 if (init.body) {
8514 init.duplex = "half";
8515 }
8516 return new Request(url.href, init);
8517}
8518function stripRoutesParam(request) {
8519 let url = new URL(request.url);
8520 url.searchParams.delete("_routes");
8521 let init = {
8522 method: request.method,
8523 body: request.body,
8524 headers: request.headers,
8525 signal: request.signal
8526 };
8527 if (init.body) {
8528 init.duplex = "half";
8529 }
8530 return new Request(url.href, init);
8531}
8532
8533// lib/server-runtime/invariant.ts
8534function invariant3(value, message) {
8535 if (value === false || value === null || typeof value === "undefined") {
8536 console.error(
8537 "The following error is a bug in React Router; please open an issue! https://github.com/remix-run/react-router/issues/new/choose"
8538 );
8539 throw new Error(message);
8540 }
8541}
8542
8543// lib/server-runtime/routes.ts
8544function groupRoutesByParentId2(manifest) {
8545 let routes = {};
8546 Object.values(manifest).forEach((route) => {
8547 if (route) {
8548 let parentId = route.parentId || "";
8549 if (!routes[parentId]) {
8550 routes[parentId] = [];
8551 }
8552 routes[parentId].push(route);
8553 }
8554 });
8555 return routes;
8556}
8557function createRoutes(manifest, parentId = "", routesByParentId = groupRoutesByParentId2(manifest)) {
8558 return (routesByParentId[parentId] || []).map((route) => ({
8559 ...route,
8560 children: createRoutes(manifest, route.id, routesByParentId)
8561 }));
8562}
8563function createStaticHandlerDataRoutes(manifest, future, parentId = "", routesByParentId = groupRoutesByParentId2(manifest)) {
8564 return (routesByParentId[parentId] || []).map((route) => {
8565 let commonRoute = {
8566 // Always include root due to default boundaries
8567 hasErrorBoundary: route.id === "root" || route.module.ErrorBoundary != null,
8568 id: route.id,
8569 path: route.path,
8570 // Need to use RR's version in the param typed here to permit the optional
8571 // context even though we know it'll always be provided in remix
8572 loader: route.module.loader ? async (args) => {
8573 if (args.request.headers.has("X-React-Router-Prerender-Data")) {
8574 const preRenderedData = args.request.headers.get(
8575 "X-React-Router-Prerender-Data"
8576 );
8577 let encoded = preRenderedData ? decodeURI(preRenderedData) : preRenderedData;
8578 invariant3(encoded, "Missing prerendered data for route");
8579 let uint8array = new TextEncoder().encode(encoded);
8580 let stream = new ReadableStream({
8581 start(controller) {
8582 controller.enqueue(uint8array);
8583 controller.close();
8584 }
8585 });
8586 let decoded = await decodeViaTurboStream(stream, global);
8587 let data2 = decoded.value;
8588 invariant3(
8589 data2 && route.id in data2,
8590 "Unable to decode prerendered data"
8591 );
8592 let result = data2[route.id];
8593 invariant3("data" in result, "Unable to process prerendered data");
8594 return result.data;
8595 }
8596 let val = await callRouteHandler(route.module.loader, args);
8597 return val;
8598 } : void 0,
8599 action: route.module.action ? (args) => callRouteHandler(route.module.action, args) : void 0,
8600 handle: route.module.handle
8601 };
8602 return route.index ? {
8603 index: true,
8604 ...commonRoute
8605 } : {
8606 caseSensitive: route.caseSensitive,
8607 children: createStaticHandlerDataRoutes(
8608 manifest,
8609 future,
8610 route.id,
8611 routesByParentId
8612 ),
8613 ...commonRoute
8614 };
8615 });
8616}
8617
8618// lib/server-runtime/markup.ts
8619var ESCAPE_LOOKUP3 = {
8620 "&": "\\u0026",
8621 ">": "\\u003e",
8622 "<": "\\u003c",
8623 "\u2028": "\\u2028",
8624 "\u2029": "\\u2029"
8625};
8626var ESCAPE_REGEX3 = /[&><\u2028\u2029]/g;
8627function escapeHtml2(html) {
8628 return html.replace(ESCAPE_REGEX3, (match) => ESCAPE_LOOKUP3[match]);
8629}
8630
8631// lib/server-runtime/serverHandoff.ts
8632function createServerHandoffString(serverHandoff) {
8633 return escapeHtml2(JSON.stringify(serverHandoff));
8634}
8635
8636// lib/server-runtime/dev.ts
8637var globalDevServerHooksKey = "__reactRouterDevServerHooks";
8638function setDevServerHooks(devServerHooks) {
8639 globalThis[globalDevServerHooksKey] = devServerHooks;
8640}
8641function getDevServerHooks() {
8642 return globalThis[globalDevServerHooksKey];
8643}
8644
8645// lib/server-runtime/single-fetch.ts
8646import { encode } from "turbo-stream";
8647
8648// lib/server-runtime/headers.ts
8649import { splitCookiesString } from "set-cookie-parser";
8650function getDocumentHeaders(build, context) {
8651 let boundaryIdx = context.errors ? context.matches.findIndex((m) => context.errors[m.route.id]) : -1;
8652 let matches = boundaryIdx >= 0 ? context.matches.slice(0, boundaryIdx + 1) : context.matches;
8653 let errorHeaders;
8654 if (boundaryIdx >= 0) {
8655 let { actionHeaders, actionData, loaderHeaders, loaderData } = context;
8656 context.matches.slice(boundaryIdx).some((match) => {
8657 let id = match.route.id;
8658 if (actionHeaders[id] && (!actionData || !actionData.hasOwnProperty(id))) {
8659 errorHeaders = actionHeaders[id];
8660 } else if (loaderHeaders[id] && !loaderData.hasOwnProperty(id)) {
8661 errorHeaders = loaderHeaders[id];
8662 }
8663 return errorHeaders != null;
8664 });
8665 }
8666 return matches.reduce((parentHeaders, match, idx) => {
8667 let { id } = match.route;
8668 let route = build.routes[id];
8669 invariant3(route, `Route with id "${id}" not found in build`);
8670 let routeModule = route.module;
8671 let loaderHeaders = context.loaderHeaders[id] || new Headers();
8672 let actionHeaders = context.actionHeaders[id] || new Headers();
8673 let includeErrorHeaders = errorHeaders != null && idx === matches.length - 1;
8674 let includeErrorCookies = includeErrorHeaders && errorHeaders !== loaderHeaders && errorHeaders !== actionHeaders;
8675 if (routeModule.headers == null) {
8676 let headers2 = new Headers(parentHeaders);
8677 if (includeErrorCookies) {
8678 prependCookies(errorHeaders, headers2);
8679 }
8680 prependCookies(actionHeaders, headers2);
8681 prependCookies(loaderHeaders, headers2);
8682 return headers2;
8683 }
8684 let headers = new Headers(
8685 routeModule.headers ? typeof routeModule.headers === "function" ? routeModule.headers({
8686 loaderHeaders,
8687 parentHeaders,
8688 actionHeaders,
8689 errorHeaders: includeErrorHeaders ? errorHeaders : void 0
8690 }) : routeModule.headers : void 0
8691 );
8692 if (includeErrorCookies) {
8693 prependCookies(errorHeaders, headers);
8694 }
8695 prependCookies(actionHeaders, headers);
8696 prependCookies(loaderHeaders, headers);
8697 prependCookies(parentHeaders, headers);
8698 return headers;
8699 }, new Headers());
8700}
8701function prependCookies(parentHeaders, childHeaders) {
8702 let parentSetCookieString = parentHeaders.get("Set-Cookie");
8703 if (parentSetCookieString) {
8704 let cookies = splitCookiesString(parentSetCookieString);
8705 cookies.forEach((cookie) => {
8706 childHeaders.append("Set-Cookie", cookie);
8707 });
8708 }
8709}
8710
8711// lib/server-runtime/single-fetch.ts
8712var SINGLE_FETCH_REDIRECT_STATUS = 202;
8713function getSingleFetchDataStrategy2({
8714 isActionDataRequest,
8715 loadRouteIds
8716} = {}) {
8717 return async ({ request, matches }) => {
8718 if (isActionDataRequest && request.method === "GET") {
8719 return {};
8720 }
8721 let matchesToLoad = loadRouteIds ? matches.filter((m) => loadRouteIds.includes(m.route.id)) : matches;
8722 let results = await Promise.all(
8723 matchesToLoad.map((match) => match.resolve())
8724 );
8725 return results.reduce(
8726 (acc, result, i) => Object.assign(acc, { [matchesToLoad[i].route.id]: result }),
8727 {}
8728 );
8729 };
8730}
8731async function singleFetchAction(build, serverMode, staticHandler, request, handlerUrl, loadContext, handleError) {
8732 try {
8733 let handlerRequest = new Request(handlerUrl, {
8734 method: request.method,
8735 body: request.body,
8736 headers: request.headers,
8737 signal: request.signal,
8738 ...request.body ? { duplex: "half" } : void 0
8739 });
8740 let result = await staticHandler.query(handlerRequest, {
8741 requestContext: loadContext,
8742 skipLoaderErrorBubbling: true,
8743 dataStrategy: getSingleFetchDataStrategy2({
8744 isActionDataRequest: true
8745 })
8746 });
8747 if (isResponse(result)) {
8748 return {
8749 result: getSingleFetchRedirect(
8750 result.status,
8751 result.headers,
8752 build.basename
8753 ),
8754 headers: result.headers,
8755 status: SINGLE_FETCH_REDIRECT_STATUS
8756 };
8757 }
8758 let context = result;
8759 let headers = getDocumentHeaders(build, context);
8760 if (isRedirectStatusCode(context.statusCode) && headers.has("Location")) {
8761 return {
8762 result: getSingleFetchRedirect(
8763 context.statusCode,
8764 headers,
8765 build.basename
8766 ),
8767 headers,
8768 status: SINGLE_FETCH_REDIRECT_STATUS
8769 };
8770 }
8771 if (context.errors) {
8772 Object.values(context.errors).forEach((err) => {
8773 if (!isRouteErrorResponse(err) || err.error) {
8774 handleError(err);
8775 }
8776 });
8777 context.errors = sanitizeErrors(context.errors, serverMode);
8778 }
8779 let singleFetchResult;
8780 if (context.errors) {
8781 singleFetchResult = { error: Object.values(context.errors)[0] };
8782 } else {
8783 singleFetchResult = { data: Object.values(context.actionData || {})[0] };
8784 }
8785 return {
8786 result: singleFetchResult,
8787 headers,
8788 status: context.statusCode
8789 };
8790 } catch (error) {
8791 handleError(error);
8792 return {
8793 result: { error },
8794 headers: new Headers(),
8795 status: 500
8796 };
8797 }
8798}
8799async function singleFetchLoaders(build, serverMode, staticHandler, request, handlerUrl, loadContext, handleError) {
8800 try {
8801 let handlerRequest = new Request(handlerUrl, {
8802 headers: request.headers,
8803 signal: request.signal
8804 });
8805 let loadRouteIds = new URL(request.url).searchParams.get("_routes")?.split(",") || void 0;
8806 let result = await staticHandler.query(handlerRequest, {
8807 requestContext: loadContext,
8808 skipLoaderErrorBubbling: true,
8809 dataStrategy: getSingleFetchDataStrategy2({
8810 loadRouteIds
8811 })
8812 });
8813 if (isResponse(result)) {
8814 return {
8815 result: {
8816 [SingleFetchRedirectSymbol]: getSingleFetchRedirect(
8817 result.status,
8818 result.headers,
8819 build.basename
8820 )
8821 },
8822 headers: result.headers,
8823 status: SINGLE_FETCH_REDIRECT_STATUS
8824 };
8825 }
8826 let context = result;
8827 let headers = getDocumentHeaders(build, context);
8828 if (isRedirectStatusCode(context.statusCode) && headers.has("Location")) {
8829 return {
8830 result: {
8831 [SingleFetchRedirectSymbol]: getSingleFetchRedirect(
8832 context.statusCode,
8833 headers,
8834 build.basename
8835 )
8836 },
8837 headers,
8838 status: SINGLE_FETCH_REDIRECT_STATUS
8839 };
8840 }
8841 if (context.errors) {
8842 Object.values(context.errors).forEach((err) => {
8843 if (!isRouteErrorResponse(err) || err.error) {
8844 handleError(err);
8845 }
8846 });
8847 context.errors = sanitizeErrors(context.errors, serverMode);
8848 }
8849 let results = {};
8850 let loadedMatches = loadRouteIds ? context.matches.filter(
8851 (m) => m.route.loader && loadRouteIds.includes(m.route.id)
8852 ) : context.matches;
8853 loadedMatches.forEach((m) => {
8854 let { id } = m.route;
8855 if (context.errors && context.errors.hasOwnProperty(id)) {
8856 results[id] = { error: context.errors[id] };
8857 } else if (context.loaderData.hasOwnProperty(id)) {
8858 results[id] = { data: context.loaderData[id] };
8859 }
8860 });
8861 return {
8862 result: results,
8863 headers,
8864 status: context.statusCode
8865 };
8866 } catch (error) {
8867 handleError(error);
8868 return {
8869 result: { root: { error } },
8870 headers: new Headers(),
8871 status: 500
8872 };
8873 }
8874}
8875function getSingleFetchRedirect(status, headers, basename) {
8876 let redirect2 = headers.get("Location");
8877 if (basename) {
8878 redirect2 = stripBasename(redirect2, basename) || redirect2;
8879 }
8880 return {
8881 redirect: redirect2,
8882 status,
8883 revalidate: (
8884 // Technically X-Remix-Revalidate isn't needed here - that was an implementation
8885 // detail of ?_data requests as our way to tell the front end to revalidate when
8886 // we didn't have a response body to include that information in.
8887 // With single fetch, we tell the front end via this revalidate boolean field.
8888 // However, we're respecting it for now because it may be something folks have
8889 // used in their own responses
8890 // TODO(v3): Consider removing or making this official public API
8891 headers.has("X-Remix-Revalidate") || headers.has("Set-Cookie")
8892 ),
8893 reload: headers.has("X-Remix-Reload-Document"),
8894 replace: headers.has("X-Remix-Replace")
8895 };
8896}
8897function encodeViaTurboStream(data2, requestSignal, streamTimeout, serverMode) {
8898 let controller = new AbortController();
8899 let timeoutId = setTimeout(
8900 () => controller.abort(new Error("Server Timeout")),
8901 typeof streamTimeout === "number" ? streamTimeout : 4950
8902 );
8903 requestSignal.addEventListener("abort", () => clearTimeout(timeoutId));
8904 return encode(data2, {
8905 signal: controller.signal,
8906 plugins: [
8907 (value) => {
8908 if (value instanceof Error) {
8909 let { name, message, stack } = serverMode === "production" /* Production */ ? sanitizeError(value, serverMode) : value;
8910 return ["SanitizedError", name, message, stack];
8911 }
8912 if (value instanceof ErrorResponseImpl) {
8913 let { data: data3, status, statusText } = value;
8914 return ["ErrorResponse", data3, status, statusText];
8915 }
8916 if (value && typeof value === "object" && SingleFetchRedirectSymbol in value) {
8917 return ["SingleFetchRedirect", value[SingleFetchRedirectSymbol]];
8918 }
8919 }
8920 ],
8921 postPlugins: [
8922 (value) => {
8923 if (!value) return;
8924 if (typeof value !== "object") return;
8925 return [
8926 "SingleFetchClassInstance",
8927 Object.fromEntries(Object.entries(value))
8928 ];
8929 },
8930 () => ["SingleFetchFallback"]
8931 ]
8932 });
8933}
8934
8935// lib/server-runtime/server.ts
8936function derive(build, mode) {
8937 let routes = createRoutes(build.routes);
8938 let dataRoutes = createStaticHandlerDataRoutes(build.routes, build.future);
8939 let serverMode = isServerMode(mode) ? mode : "production" /* Production */;
8940 let staticHandler = createStaticHandler(dataRoutes, {
8941 basename: build.basename
8942 });
8943 let errorHandler = build.entry.module.handleError || ((error, { request }) => {
8944 if (serverMode !== "test" /* Test */ && !request.signal.aborted) {
8945 console.error(
8946 // @ts-expect-error This is "private" from users but intended for internal use
8947 isRouteErrorResponse(error) && error.error ? error.error : error
8948 );
8949 }
8950 });
8951 return {
8952 routes,
8953 dataRoutes,
8954 serverMode,
8955 staticHandler,
8956 errorHandler
8957 };
8958}
8959var createRequestHandler = (build, mode) => {
8960 let _build;
8961 let routes;
8962 let serverMode;
8963 let staticHandler;
8964 let errorHandler;
8965 return async function requestHandler(request, loadContext = {}) {
8966 _build = typeof build === "function" ? await build() : build;
8967 if (typeof build === "function") {
8968 let derived = derive(_build, mode);
8969 routes = derived.routes;
8970 serverMode = derived.serverMode;
8971 staticHandler = derived.staticHandler;
8972 errorHandler = derived.errorHandler;
8973 } else if (!routes || !serverMode || !staticHandler || !errorHandler) {
8974 let derived = derive(_build, mode);
8975 routes = derived.routes;
8976 serverMode = derived.serverMode;
8977 staticHandler = derived.staticHandler;
8978 errorHandler = derived.errorHandler;
8979 }
8980 let url = new URL(request.url);
8981 let params = {};
8982 let handleError = (error) => {
8983 if (mode === "development" /* Development */) {
8984 getDevServerHooks()?.processRequestError?.(error);
8985 }
8986 errorHandler(error, {
8987 context: loadContext,
8988 params,
8989 request
8990 });
8991 };
8992 let manifestUrl = `${_build.basename ?? "/"}/__manifest`.replace(
8993 /\/+/g,
8994 "/"
8995 );
8996 if (url.pathname === manifestUrl) {
8997 try {
8998 let res = await handleManifestRequest(_build, routes, url);
8999 return res;
9000 } catch (e) {
9001 handleError(e);
9002 return new Response("Unknown Server Error", { status: 500 });
9003 }
9004 }
9005 let matches = matchServerRoutes(routes, url.pathname, _build.basename);
9006 if (matches && matches.length > 0) {
9007 Object.assign(params, matches[0].params);
9008 }
9009 let response;
9010 if (url.pathname.endsWith(".data")) {
9011 let handlerUrl = new URL(request.url);
9012 handlerUrl.pathname = handlerUrl.pathname.replace(/\.data$/, "").replace(/^\/_root$/, "/");
9013 let singleFetchMatches = matchServerRoutes(
9014 routes,
9015 handlerUrl.pathname,
9016 _build.basename
9017 );
9018 response = await handleSingleFetchRequest(
9019 serverMode,
9020 _build,
9021 staticHandler,
9022 request,
9023 handlerUrl,
9024 loadContext,
9025 handleError
9026 );
9027 if (_build.entry.module.handleDataRequest) {
9028 response = await _build.entry.module.handleDataRequest(response, {
9029 context: loadContext,
9030 params: singleFetchMatches ? singleFetchMatches[0].params : {},
9031 request
9032 });
9033 if (isRedirectResponse(response)) {
9034 let result = getSingleFetchRedirect(
9035 response.status,
9036 response.headers,
9037 _build.basename
9038 );
9039 if (request.method === "GET") {
9040 result = {
9041 [SingleFetchRedirectSymbol]: result
9042 };
9043 }
9044 let headers = new Headers(response.headers);
9045 headers.set("Content-Type", "text/x-script");
9046 return new Response(
9047 encodeViaTurboStream(
9048 result,
9049 request.signal,
9050 _build.entry.module.streamTimeout,
9051 serverMode
9052 ),
9053 {
9054 status: SINGLE_FETCH_REDIRECT_STATUS,
9055 headers
9056 }
9057 );
9058 }
9059 }
9060 } else if (matches && matches[matches.length - 1].route.module.default == null && matches[matches.length - 1].route.module.ErrorBoundary == null) {
9061 response = await handleResourceRequest(
9062 serverMode,
9063 staticHandler,
9064 matches.slice(-1)[0].route.id,
9065 request,
9066 loadContext,
9067 handleError
9068 );
9069 } else {
9070 let criticalCss = mode === "development" /* Development */ ? await getDevServerHooks()?.getCriticalCss?.(_build, url.pathname) : void 0;
9071 response = await handleDocumentRequest(
9072 serverMode,
9073 _build,
9074 staticHandler,
9075 request,
9076 loadContext,
9077 handleError,
9078 criticalCss
9079 );
9080 }
9081 if (request.method === "HEAD") {
9082 return new Response(null, {
9083 headers: response.headers,
9084 status: response.status,
9085 statusText: response.statusText
9086 });
9087 }
9088 return response;
9089 };
9090};
9091async function handleManifestRequest(build, routes, url) {
9092 let patches = {};
9093 if (url.searchParams.has("p")) {
9094 for (let path of url.searchParams.getAll("p")) {
9095 let matches = matchServerRoutes(routes, path, build.basename);
9096 if (matches) {
9097 for (let match of matches) {
9098 let routeId = match.route.id;
9099 let route = build.assets.routes[routeId];
9100 if (route) {
9101 patches[routeId] = route;
9102 }
9103 }
9104 }
9105 }
9106 return Response.json(patches, {
9107 headers: {
9108 "Cache-Control": "public, max-age=31536000, immutable"
9109 }
9110 });
9111 }
9112 return new Response("Invalid Request", { status: 400 });
9113}
9114async function handleSingleFetchRequest(serverMode, build, staticHandler, request, handlerUrl, loadContext, handleError) {
9115 let { result, headers, status } = request.method !== "GET" ? await singleFetchAction(
9116 build,
9117 serverMode,
9118 staticHandler,
9119 request,
9120 handlerUrl,
9121 loadContext,
9122 handleError
9123 ) : await singleFetchLoaders(
9124 build,
9125 serverMode,
9126 staticHandler,
9127 request,
9128 handlerUrl,
9129 loadContext,
9130 handleError
9131 );
9132 let resultHeaders = new Headers(headers);
9133 resultHeaders.set("X-Remix-Response", "yes");
9134 if (status === 304) {
9135 return new Response(null, { status: 304, headers: resultHeaders });
9136 }
9137 resultHeaders.set("Content-Type", "text/x-script");
9138 return new Response(
9139 encodeViaTurboStream(
9140 result,
9141 request.signal,
9142 build.entry.module.streamTimeout,
9143 serverMode
9144 ),
9145 {
9146 status: status || 200,
9147 headers: resultHeaders
9148 }
9149 );
9150}
9151async function handleDocumentRequest(serverMode, build, staticHandler, request, loadContext, handleError, criticalCss) {
9152 let context;
9153 try {
9154 context = await staticHandler.query(request, {
9155 requestContext: loadContext
9156 });
9157 } catch (error) {
9158 handleError(error);
9159 return new Response(null, { status: 500 });
9160 }
9161 if (isResponse(context)) {
9162 return context;
9163 }
9164 let headers = getDocumentHeaders(build, context);
9165 if (context.statusCode === 304) {
9166 return new Response(null, { status: 304, headers });
9167 }
9168 if (context.errors) {
9169 Object.values(context.errors).forEach((err) => {
9170 if (!isRouteErrorResponse(err) || err.error) {
9171 handleError(err);
9172 }
9173 });
9174 context.errors = sanitizeErrors(context.errors, serverMode);
9175 }
9176 let state = {
9177 loaderData: context.loaderData,
9178 actionData: context.actionData,
9179 errors: serializeErrors2(context.errors, serverMode)
9180 };
9181 let entryContext = {
9182 manifest: build.assets,
9183 routeModules: createEntryRouteModules(build.routes),
9184 staticHandlerContext: context,
9185 criticalCss,
9186 serverHandoffString: createServerHandoffString({
9187 basename: build.basename,
9188 criticalCss,
9189 future: build.future,
9190 isSpaMode: build.isSpaMode
9191 }),
9192 serverHandoffStream: encodeViaTurboStream(
9193 state,
9194 request.signal,
9195 build.entry.module.streamTimeout,
9196 serverMode
9197 ),
9198 renderMeta: {},
9199 future: build.future,
9200 isSpaMode: build.isSpaMode,
9201 serializeError: (err) => serializeError(err, serverMode)
9202 };
9203 let handleDocumentRequestFunction = build.entry.module.default;
9204 try {
9205 return await handleDocumentRequestFunction(
9206 request,
9207 context.statusCode,
9208 headers,
9209 entryContext,
9210 loadContext
9211 );
9212 } catch (error) {
9213 handleError(error);
9214 let errorForSecondRender = error;
9215 if (isResponse(error)) {
9216 try {
9217 let data2 = await unwrapResponse(error);
9218 errorForSecondRender = new ErrorResponseImpl(
9219 error.status,
9220 error.statusText,
9221 data2
9222 );
9223 } catch (e) {
9224 }
9225 }
9226 context = getStaticContextFromError(
9227 staticHandler.dataRoutes,
9228 context,
9229 errorForSecondRender
9230 );
9231 if (context.errors) {
9232 context.errors = sanitizeErrors(context.errors, serverMode);
9233 }
9234 let state2 = {
9235 loaderData: context.loaderData,
9236 actionData: context.actionData,
9237 errors: serializeErrors2(context.errors, serverMode)
9238 };
9239 entryContext = {
9240 ...entryContext,
9241 staticHandlerContext: context,
9242 serverHandoffString: createServerHandoffString({
9243 basename: build.basename,
9244 future: build.future,
9245 isSpaMode: build.isSpaMode
9246 }),
9247 serverHandoffStream: encodeViaTurboStream(
9248 state2,
9249 request.signal,
9250 build.entry.module.streamTimeout,
9251 serverMode
9252 ),
9253 renderMeta: {}
9254 };
9255 try {
9256 return await handleDocumentRequestFunction(
9257 request,
9258 context.statusCode,
9259 headers,
9260 entryContext,
9261 loadContext
9262 );
9263 } catch (error2) {
9264 handleError(error2);
9265 return returnLastResortErrorResponse(error2, serverMode);
9266 }
9267 }
9268}
9269async function handleResourceRequest(serverMode, staticHandler, routeId, request, loadContext, handleError) {
9270 try {
9271 let response = await staticHandler.queryRoute(request, {
9272 routeId,
9273 requestContext: loadContext
9274 });
9275 invariant3(
9276 isResponse(response),
9277 "Expected a Response to be returned from resource route handler"
9278 );
9279 return response;
9280 } catch (error) {
9281 if (isResponse(error)) {
9282 error.headers.set("X-Remix-Catch", "yes");
9283 return error;
9284 }
9285 if (isRouteErrorResponse(error)) {
9286 if (error) {
9287 handleError(error);
9288 }
9289 return errorResponseToJson(error, serverMode);
9290 }
9291 handleError(error);
9292 return returnLastResortErrorResponse(error, serverMode);
9293 }
9294}
9295function errorResponseToJson(errorResponse, serverMode) {
9296 return Response.json(
9297 serializeError(
9298 // @ts-expect-error This is "private" from users but intended for internal use
9299 errorResponse.error || new Error("Unexpected Server Error"),
9300 serverMode
9301 ),
9302 {
9303 status: errorResponse.status,
9304 statusText: errorResponse.statusText,
9305 headers: {
9306 "X-Remix-Error": "yes"
9307 }
9308 }
9309 );
9310}
9311function returnLastResortErrorResponse(error, serverMode) {
9312 let message = "Unexpected Server Error";
9313 if (serverMode !== "production" /* Production */) {
9314 message += `
9315
9316${String(error)}`;
9317 }
9318 return new Response(message, {
9319 status: 500,
9320 headers: {
9321 "Content-Type": "text/plain"
9322 }
9323 });
9324}
9325function unwrapResponse(response) {
9326 let contentType = response.headers.get("Content-Type");
9327 return contentType && /\bapplication\/json\b/.test(contentType) ? response.body == null ? null : response.json() : response.text();
9328}
9329
9330// lib/server-runtime/sessions.ts
9331function flash(name) {
9332 return `__flash_${name}__`;
9333}
9334var createSession = (initialData = {}, id = "") => {
9335 let map = new Map(Object.entries(initialData));
9336 return {
9337 get id() {
9338 return id;
9339 },
9340 get data() {
9341 return Object.fromEntries(map);
9342 },
9343 has(name) {
9344 return map.has(name) || map.has(flash(name));
9345 },
9346 get(name) {
9347 if (map.has(name)) return map.get(name);
9348 let flashName = flash(name);
9349 if (map.has(flashName)) {
9350 let value = map.get(flashName);
9351 map.delete(flashName);
9352 return value;
9353 }
9354 return void 0;
9355 },
9356 set(name, value) {
9357 map.set(name, value);
9358 },
9359 flash(name, value) {
9360 map.set(flash(name), value);
9361 },
9362 unset(name) {
9363 map.delete(name);
9364 }
9365 };
9366};
9367var isSession = (object) => {
9368 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";
9369};
9370function createSessionStorage({
9371 cookie: cookieArg,
9372 createData,
9373 readData,
9374 updateData,
9375 deleteData
9376}) {
9377 let cookie = isCookie(cookieArg) ? cookieArg : createCookie(cookieArg?.name || "__session", cookieArg);
9378 warnOnceAboutSigningSessionCookie(cookie);
9379 return {
9380 async getSession(cookieHeader, options) {
9381 let id = cookieHeader && await cookie.parse(cookieHeader, options);
9382 let data2 = id && await readData(id);
9383 return createSession(data2 || {}, id || "");
9384 },
9385 async commitSession(session, options) {
9386 let { id, data: data2 } = session;
9387 let expires = options?.maxAge != null ? new Date(Date.now() + options.maxAge * 1e3) : options?.expires != null ? options.expires : cookie.expires;
9388 if (id) {
9389 await updateData(id, data2, expires);
9390 } else {
9391 id = await createData(data2, expires);
9392 }
9393 return cookie.serialize(id, options);
9394 },
9395 async destroySession(session, options) {
9396 await deleteData(session.id);
9397 return cookie.serialize("", {
9398 ...options,
9399 maxAge: void 0,
9400 expires: /* @__PURE__ */ new Date(0)
9401 });
9402 }
9403 };
9404}
9405function warnOnceAboutSigningSessionCookie(cookie) {
9406 warnOnce(
9407 cookie.isSigned,
9408 `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.`
9409 );
9410}
9411
9412// lib/server-runtime/sessions/cookieStorage.ts
9413function createCookieSessionStorage({ cookie: cookieArg } = {}) {
9414 let cookie = isCookie(cookieArg) ? cookieArg : createCookie(cookieArg?.name || "__session", cookieArg);
9415 warnOnceAboutSigningSessionCookie(cookie);
9416 return {
9417 async getSession(cookieHeader, options) {
9418 return createSession(
9419 cookieHeader && await cookie.parse(cookieHeader, options) || {}
9420 );
9421 },
9422 async commitSession(session, options) {
9423 let serializedCookie = await cookie.serialize(session.data, options);
9424 if (serializedCookie.length > 4096) {
9425 throw new Error(
9426 "Cookie length will exceed browser maximum. Length: " + serializedCookie.length
9427 );
9428 }
9429 return serializedCookie;
9430 },
9431 async destroySession(_session, options) {
9432 return cookie.serialize("", {
9433 ...options,
9434 maxAge: void 0,
9435 expires: /* @__PURE__ */ new Date(0)
9436 });
9437 }
9438 };
9439}
9440
9441// lib/server-runtime/sessions/memoryStorage.ts
9442function createMemorySessionStorage({ cookie } = {}) {
9443 let map = /* @__PURE__ */ new Map();
9444 return createSessionStorage({
9445 cookie,
9446 async createData(data2, expires) {
9447 let id = Math.random().toString(36).substring(2, 10);
9448 map.set(id, { data: data2, expires });
9449 return id;
9450 },
9451 async readData(id) {
9452 if (map.has(id)) {
9453 let { data: data2, expires } = map.get(id);
9454 if (!expires || expires > /* @__PURE__ */ new Date()) {
9455 return data2;
9456 }
9457 if (expires) map.delete(id);
9458 }
9459 return null;
9460 },
9461 async updateData(id, data2, expires) {
9462 map.set(id, { data: data2, expires });
9463 },
9464 async deleteData(id) {
9465 map.delete(id);
9466 }
9467 });
9468}
9469
9470// lib/dom/ssr/errors.ts
9471function deserializeErrors2(errors) {
9472 if (!errors) return null;
9473 let entries = Object.entries(errors);
9474 let serialized = {};
9475 for (let [key, val] of entries) {
9476 if (val && val.__type === "RouteErrorResponse") {
9477 serialized[key] = new ErrorResponseImpl(
9478 val.status,
9479 val.statusText,
9480 val.data,
9481 val.internal === true
9482 );
9483 } else if (val && val.__type === "Error") {
9484 if (val.__subType) {
9485 let ErrorConstructor = window[val.__subType];
9486 if (typeof ErrorConstructor === "function") {
9487 try {
9488 let error = new ErrorConstructor(val.message);
9489 error.stack = val.stack;
9490 serialized[key] = error;
9491 } catch (e) {
9492 }
9493 }
9494 }
9495 if (serialized[key] == null) {
9496 let error = new Error(val.message);
9497 error.stack = val.stack;
9498 serialized[key] = error;
9499 }
9500 } else {
9501 serialized[key] = val;
9502 }
9503 }
9504 return serialized;
9505}
9506
9507export {
9508 Action,
9509 createBrowserHistory,
9510 invariant,
9511 createPath,
9512 parsePath,
9513 matchRoutes,
9514 generatePath,
9515 matchPath,
9516 resolvePath,
9517 data,
9518 redirect,
9519 redirectDocument,
9520 replace,
9521 ErrorResponseImpl,
9522 isRouteErrorResponse,
9523 IDLE_NAVIGATION,
9524 IDLE_FETCHER,
9525 IDLE_BLOCKER,
9526 createRouter,
9527 DataRouterContext,
9528 DataRouterStateContext,
9529 ViewTransitionContext,
9530 FetchersContext,
9531 NavigationContext,
9532 LocationContext,
9533 RouteContext,
9534 useHref,
9535 useInRouterContext,
9536 useLocation,
9537 useNavigationType,
9538 useMatch,
9539 useNavigate,
9540 useOutletContext,
9541 useOutlet,
9542 useParams,
9543 useResolvedPath,
9544 useRoutes,
9545 useNavigation,
9546 useRevalidator,
9547 useMatches,
9548 useLoaderData,
9549 useRouteLoaderData,
9550 useActionData,
9551 useRouteError,
9552 useAsyncValue,
9553 useAsyncError,
9554 useBlocker,
9555 mapRouteProperties,
9556 createMemoryRouter,
9557 RouterProvider,
9558 MemoryRouter,
9559 Navigate,
9560 Outlet,
9561 Route,
9562 Router,
9563 Routes,
9564 Await,
9565 createRoutesFromChildren,
9566 renderMatches,
9567 createSearchParams,
9568 SingleFetchRedirectSymbol,
9569 getSingleFetchDataStrategy,
9570 decodeViaTurboStream,
9571 RemixErrorBoundary,
9572 createClientRoutesWithHMRRevalidationOptOut,
9573 createClientRoutes,
9574 shouldHydrateRouteLoader,
9575 getPatchRoutesOnNavigationFunction,
9576 useFogOFWarDiscovery,
9577 FrameworkContext,
9578 Links,
9579 PrefetchPageLinks,
9580 Meta,
9581 Scripts,
9582 createBrowserRouter,
9583 createHashRouter,
9584 BrowserRouter,
9585 HashRouter,
9586 HistoryRouter,
9587 Link,
9588 NavLink,
9589 Form,
9590 ScrollRestoration,
9591 useLinkClickHandler,
9592 useSearchParams,
9593 useSubmit,
9594 useFormAction,
9595 useFetcher,
9596 useFetchers,
9597 useScrollRestoration,
9598 useBeforeUnload,
9599 usePrompt,
9600 useViewTransitionState,
9601 StaticRouter,
9602 StaticRouterProvider,
9603 createStaticHandler2 as createStaticHandler,
9604 createStaticRouter,
9605 ServerRouter,
9606 createRoutesStub,
9607 createCookie,
9608 isCookie,
9609 ServerMode,
9610 setDevServerHooks,
9611 createRequestHandler,
9612 createSession,
9613 isSession,
9614 createSessionStorage,
9615 createCookieSessionStorage,
9616 createMemorySessionStorage,
9617 deserializeErrors2 as deserializeErrors
9618};