UNPKG

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