UNPKG

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