UNPKG

182 kBJavaScriptView Raw
1/**
2 * react-router v7.0.1
3 *
4 * Copyright (c) Remix Software Inc.
5 *
6 * This source code is licensed under the MIT license found in the
7 * LICENSE.md file in the root directory of this source tree.
8 *
9 * @license MIT
10 */
11"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// dom-export.ts
41var dom_export_exports = {};
42__export(dom_export_exports, {
43 HydratedRouter: () => HydratedRouter,
44 RouterProvider: () => RouterProvider2
45});
46module.exports = __toCommonJS(dom_export_exports);
47
48// lib/dom-export/dom-router-provider.tsx
49var React10 = __toESM(require("react"));
50var ReactDOM = __toESM(require("react-dom"));
51
52// lib/router/history.ts
53var PopStateEventType = "popstate";
54function createBrowserHistory(options = {}) {
55 function createBrowserLocation(window2, globalHistory) {
56 let { pathname, search, hash } = window2.location;
57 return createLocation(
58 "",
59 { pathname, search, hash },
60 // state defaults to `null` because `window.history.state` does
61 globalHistory.state && globalHistory.state.usr || null,
62 globalHistory.state && globalHistory.state.key || "default"
63 );
64 }
65 function createBrowserHref(window2, to) {
66 return typeof to === "string" ? to : createPath(to);
67 }
68 return getUrlBasedHistory(
69 createBrowserLocation,
70 createBrowserHref,
71 null,
72 options
73 );
74}
75function invariant(value, message) {
76 if (value === false || value === null || typeof value === "undefined") {
77 throw new Error(message);
78 }
79}
80function warning(cond, message) {
81 if (!cond) {
82 if (typeof console !== "undefined") console.warn(message);
83 try {
84 throw new Error(message);
85 } catch (e) {
86 }
87 }
88}
89function createKey() {
90 return Math.random().toString(36).substring(2, 10);
91}
92function getHistoryState(location, index) {
93 return {
94 usr: location.state,
95 key: location.key,
96 idx: index
97 };
98}
99function createLocation(current, to, state = null, key) {
100 let location = {
101 pathname: typeof current === "string" ? current : current.pathname,
102 search: "",
103 hash: "",
104 ...typeof to === "string" ? parsePath(to) : to,
105 state,
106 // TODO: This could be cleaned up. push/replace should probably just take
107 // full Locations now and avoid the need to run through this flow at all
108 // But that's a pretty big refactor to the current test suite so going to
109 // keep as is for the time being and just let any incoming keys take precedence
110 key: to && to.key || key || createKey()
111 };
112 return location;
113}
114function createPath({
115 pathname = "/",
116 search = "",
117 hash = ""
118}) {
119 if (search && search !== "?")
120 pathname += search.charAt(0) === "?" ? search : "?" + search;
121 if (hash && hash !== "#")
122 pathname += hash.charAt(0) === "#" ? hash : "#" + hash;
123 return pathname;
124}
125function parsePath(path) {
126 let parsedPath = {};
127 if (path) {
128 let hashIndex = path.indexOf("#");
129 if (hashIndex >= 0) {
130 parsedPath.hash = path.substring(hashIndex);
131 path = path.substring(0, hashIndex);
132 }
133 let searchIndex = path.indexOf("?");
134 if (searchIndex >= 0) {
135 parsedPath.search = path.substring(searchIndex);
136 path = path.substring(0, searchIndex);
137 }
138 if (path) {
139 parsedPath.pathname = path;
140 }
141 }
142 return parsedPath;
143}
144function getUrlBasedHistory(getLocation, createHref, validateLocation, options = {}) {
145 let { window: window2 = document.defaultView, v5Compat = false } = options;
146 let globalHistory = window2.history;
147 let action = "POP" /* Pop */;
148 let listener = null;
149 let index = getIndex();
150 if (index == null) {
151 index = 0;
152 globalHistory.replaceState({ ...globalHistory.state, idx: index }, "");
153 }
154 function getIndex() {
155 let state = globalHistory.state || { idx: null };
156 return state.idx;
157 }
158 function handlePop() {
159 action = "POP" /* Pop */;
160 let nextIndex = getIndex();
161 let delta = nextIndex == null ? null : nextIndex - index;
162 index = nextIndex;
163 if (listener) {
164 listener({ action, location: history.location, delta });
165 }
166 }
167 function push(to, state) {
168 action = "PUSH" /* Push */;
169 let location = createLocation(history.location, to, state);
170 if (validateLocation) validateLocation(location, to);
171 index = getIndex() + 1;
172 let historyState = getHistoryState(location, index);
173 let url = history.createHref(location);
174 try {
175 globalHistory.pushState(historyState, "", url);
176 } catch (error) {
177 if (error instanceof DOMException && error.name === "DataCloneError") {
178 throw error;
179 }
180 window2.location.assign(url);
181 }
182 if (v5Compat && listener) {
183 listener({ action, location: history.location, delta: 1 });
184 }
185 }
186 function replace2(to, state) {
187 action = "REPLACE" /* Replace */;
188 let location = createLocation(history.location, to, state);
189 if (validateLocation) validateLocation(location, to);
190 index = getIndex();
191 let historyState = getHistoryState(location, index);
192 let url = history.createHref(location);
193 globalHistory.replaceState(historyState, "", url);
194 if (v5Compat && listener) {
195 listener({ action, location: history.location, delta: 0 });
196 }
197 }
198 function createURL(to) {
199 let base = window2.location.origin !== "null" ? window2.location.origin : window2.location.href;
200 let href = typeof to === "string" ? to : createPath(to);
201 href = href.replace(/ $/, "%20");
202 invariant(
203 base,
204 `No window.location.(origin|href) available to create URL for href: ${href}`
205 );
206 return new URL(href, base);
207 }
208 let history = {
209 get action() {
210 return action;
211 },
212 get location() {
213 return getLocation(window2, globalHistory);
214 },
215 listen(fn) {
216 if (listener) {
217 throw new Error("A history only accepts one active listener");
218 }
219 window2.addEventListener(PopStateEventType, handlePop);
220 listener = fn;
221 return () => {
222 window2.removeEventListener(PopStateEventType, handlePop);
223 listener = null;
224 };
225 },
226 createHref(to) {
227 return createHref(window2, to);
228 },
229 createURL,
230 encodeLocation(to) {
231 let url = createURL(to);
232 return {
233 pathname: url.pathname,
234 search: url.search,
235 hash: url.hash
236 };
237 },
238 push,
239 replace: replace2,
240 go(n) {
241 return globalHistory.go(n);
242 }
243 };
244 return history;
245}
246
247// lib/router/utils.ts
248var immutableRouteKeys = /* @__PURE__ */ new Set([
249 "lazy",
250 "caseSensitive",
251 "path",
252 "id",
253 "index",
254 "children"
255]);
256function isIndexRoute(route) {
257 return route.index === true;
258}
259function convertRoutesToDataRoutes(routes, mapRouteProperties2, parentPath = [], manifest = {}) {
260 return routes.map((route, index) => {
261 let treePath = [...parentPath, String(index)];
262 let id = typeof route.id === "string" ? route.id : treePath.join("-");
263 invariant(
264 route.index !== true || !route.children,
265 `Cannot specify children on an index route`
266 );
267 invariant(
268 !manifest[id],
269 `Found a route id collision on id "${id}". Route id's must be globally unique within Data Router usages`
270 );
271 if (isIndexRoute(route)) {
272 let indexRoute = {
273 ...route,
274 ...mapRouteProperties2(route),
275 id
276 };
277 manifest[id] = indexRoute;
278 return indexRoute;
279 } else {
280 let pathOrLayoutRoute = {
281 ...route,
282 ...mapRouteProperties2(route),
283 id,
284 children: void 0
285 };
286 manifest[id] = pathOrLayoutRoute;
287 if (route.children) {
288 pathOrLayoutRoute.children = convertRoutesToDataRoutes(
289 route.children,
290 mapRouteProperties2,
291 treePath,
292 manifest
293 );
294 }
295 return pathOrLayoutRoute;
296 }
297 });
298}
299function matchRoutes(routes, locationArg, basename = "/") {
300 return matchRoutesImpl(routes, locationArg, basename, false);
301}
302function matchRoutesImpl(routes, locationArg, basename, allowPartial) {
303 let location = typeof locationArg === "string" ? parsePath(locationArg) : locationArg;
304 let pathname = stripBasename(location.pathname || "/", basename);
305 if (pathname == null) {
306 return null;
307 }
308 let branches = flattenRoutes(routes);
309 rankRouteBranches(branches);
310 let matches = null;
311 for (let i = 0; matches == null && i < branches.length; ++i) {
312 let decoded = decodePath(pathname);
313 matches = matchRouteBranch(
314 branches[i],
315 decoded,
316 allowPartial
317 );
318 }
319 return matches;
320}
321function convertRouteMatchToUiMatch(match, loaderData) {
322 let { route, pathname, params } = match;
323 return {
324 id: route.id,
325 pathname,
326 params,
327 data: loaderData[route.id],
328 handle: route.handle
329 };
330}
331function flattenRoutes(routes, branches = [], parentsMeta = [], parentPath = "") {
332 let flattenRoute = (route, index, relativePath) => {
333 let meta = {
334 relativePath: relativePath === void 0 ? route.path || "" : relativePath,
335 caseSensitive: route.caseSensitive === true,
336 childrenIndex: index,
337 route
338 };
339 if (meta.relativePath.startsWith("/")) {
340 invariant(
341 meta.relativePath.startsWith(parentPath),
342 `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.`
343 );
344 meta.relativePath = meta.relativePath.slice(parentPath.length);
345 }
346 let path = joinPaths([parentPath, meta.relativePath]);
347 let routesMeta = parentsMeta.concat(meta);
348 if (route.children && route.children.length > 0) {
349 invariant(
350 // Our types know better, but runtime JS may not!
351 // @ts-expect-error
352 route.index !== true,
353 `Index routes must not have child routes. Please remove all child routes from route path "${path}".`
354 );
355 flattenRoutes(route.children, branches, routesMeta, path);
356 }
357 if (route.path == null && !route.index) {
358 return;
359 }
360 branches.push({
361 path,
362 score: computeScore(path, route.index),
363 routesMeta
364 });
365 };
366 routes.forEach((route, index) => {
367 if (route.path === "" || !route.path?.includes("?")) {
368 flattenRoute(route, index);
369 } else {
370 for (let exploded of explodeOptionalSegments(route.path)) {
371 flattenRoute(route, index, exploded);
372 }
373 }
374 });
375 return branches;
376}
377function explodeOptionalSegments(path) {
378 let segments = path.split("/");
379 if (segments.length === 0) return [];
380 let [first, ...rest] = segments;
381 let isOptional = first.endsWith("?");
382 let required = first.replace(/\?$/, "");
383 if (rest.length === 0) {
384 return isOptional ? [required, ""] : [required];
385 }
386 let restExploded = explodeOptionalSegments(rest.join("/"));
387 let result = [];
388 result.push(
389 ...restExploded.map(
390 (subpath) => subpath === "" ? required : [required, subpath].join("/")
391 )
392 );
393 if (isOptional) {
394 result.push(...restExploded);
395 }
396 return result.map(
397 (exploded) => path.startsWith("/") && exploded === "" ? "/" : exploded
398 );
399}
400function rankRouteBranches(branches) {
401 branches.sort(
402 (a, b) => a.score !== b.score ? b.score - a.score : compareIndexes(
403 a.routesMeta.map((meta) => meta.childrenIndex),
404 b.routesMeta.map((meta) => meta.childrenIndex)
405 )
406 );
407}
408var paramRe = /^:[\w-]+$/;
409var dynamicSegmentValue = 3;
410var indexRouteValue = 2;
411var emptySegmentValue = 1;
412var staticSegmentValue = 10;
413var splatPenalty = -2;
414var isSplat = (s) => s === "*";
415function computeScore(path, index) {
416 let segments = path.split("/");
417 let initialScore = segments.length;
418 if (segments.some(isSplat)) {
419 initialScore += splatPenalty;
420 }
421 if (index) {
422 initialScore += indexRouteValue;
423 }
424 return segments.filter((s) => !isSplat(s)).reduce(
425 (score, segment) => score + (paramRe.test(segment) ? dynamicSegmentValue : segment === "" ? emptySegmentValue : staticSegmentValue),
426 initialScore
427 );
428}
429function compareIndexes(a, b) {
430 let siblings = a.length === b.length && a.slice(0, -1).every((n, i) => n === b[i]);
431 return siblings ? (
432 // If two routes are siblings, we should try to match the earlier sibling
433 // first. This allows people to have fine-grained control over the matching
434 // behavior by simply putting routes with identical paths in the order they
435 // want them tried.
436 a[a.length - 1] - b[b.length - 1]
437 ) : (
438 // Otherwise, it doesn't really make sense to rank non-siblings by index,
439 // so they sort equally.
440 0
441 );
442}
443function matchRouteBranch(branch, pathname, allowPartial = false) {
444 let { routesMeta } = branch;
445 let matchedParams = {};
446 let matchedPathname = "/";
447 let matches = [];
448 for (let i = 0; i < routesMeta.length; ++i) {
449 let meta = routesMeta[i];
450 let end = i === routesMeta.length - 1;
451 let remainingPathname = matchedPathname === "/" ? pathname : pathname.slice(matchedPathname.length) || "/";
452 let match = matchPath(
453 { path: meta.relativePath, caseSensitive: meta.caseSensitive, end },
454 remainingPathname
455 );
456 let route = meta.route;
457 if (!match && end && allowPartial && !routesMeta[routesMeta.length - 1].route.index) {
458 match = matchPath(
459 {
460 path: meta.relativePath,
461 caseSensitive: meta.caseSensitive,
462 end: false
463 },
464 remainingPathname
465 );
466 }
467 if (!match) {
468 return null;
469 }
470 Object.assign(matchedParams, match.params);
471 matches.push({
472 // TODO: Can this as be avoided?
473 params: matchedParams,
474 pathname: joinPaths([matchedPathname, match.pathname]),
475 pathnameBase: normalizePathname(
476 joinPaths([matchedPathname, match.pathnameBase])
477 ),
478 route
479 });
480 if (match.pathnameBase !== "/") {
481 matchedPathname = joinPaths([matchedPathname, match.pathnameBase]);
482 }
483 }
484 return matches;
485}
486function matchPath(pattern, pathname) {
487 if (typeof pattern === "string") {
488 pattern = { path: pattern, caseSensitive: false, end: true };
489 }
490 let [matcher, compiledParams] = compilePath(
491 pattern.path,
492 pattern.caseSensitive,
493 pattern.end
494 );
495 let match = pathname.match(matcher);
496 if (!match) return null;
497 let matchedPathname = match[0];
498 let pathnameBase = matchedPathname.replace(/(.)\/+$/, "$1");
499 let captureGroups = match.slice(1);
500 let params = compiledParams.reduce(
501 (memo2, { paramName, isOptional }, index) => {
502 if (paramName === "*") {
503 let splatValue = captureGroups[index] || "";
504 pathnameBase = matchedPathname.slice(0, matchedPathname.length - splatValue.length).replace(/(.)\/+$/, "$1");
505 }
506 const value = captureGroups[index];
507 if (isOptional && !value) {
508 memo2[paramName] = void 0;
509 } else {
510 memo2[paramName] = (value || "").replace(/%2F/g, "/");
511 }
512 return memo2;
513 },
514 {}
515 );
516 return {
517 params,
518 pathname: matchedPathname,
519 pathnameBase,
520 pattern
521 };
522}
523function compilePath(path, caseSensitive = false, end = true) {
524 warning(
525 path === "*" || !path.endsWith("*") || path.endsWith("/*"),
526 `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(/\*$/, "/*")}".`
527 );
528 let params = [];
529 let regexpSource = "^" + path.replace(/\/*\*?$/, "").replace(/^\/*/, "/").replace(/[\\.*+^${}|()[\]]/g, "\\$&").replace(
530 /\/:([\w-]+)(\?)?/g,
531 (_, paramName, isOptional) => {
532 params.push({ paramName, isOptional: isOptional != null });
533 return isOptional ? "/?([^\\/]+)?" : "/([^\\/]+)";
534 }
535 );
536 if (path.endsWith("*")) {
537 params.push({ paramName: "*" });
538 regexpSource += path === "*" || path === "/*" ? "(.*)$" : "(?:\\/(.+)|\\/*)$";
539 } else if (end) {
540 regexpSource += "\\/*$";
541 } else if (path !== "" && path !== "/") {
542 regexpSource += "(?:(?=\\/|$))";
543 } else {
544 }
545 let matcher = new RegExp(regexpSource, caseSensitive ? void 0 : "i");
546 return [matcher, params];
547}
548function decodePath(value) {
549 try {
550 return value.split("/").map((v) => decodeURIComponent(v).replace(/\//g, "%2F")).join("/");
551 } catch (error) {
552 warning(
553 false,
554 `The URL path "${value}" could not be decoded because it is is a malformed URL segment. This is probably due to a bad percent encoding (${error}).`
555 );
556 return value;
557 }
558}
559function stripBasename(pathname, basename) {
560 if (basename === "/") return pathname;
561 if (!pathname.toLowerCase().startsWith(basename.toLowerCase())) {
562 return null;
563 }
564 let startIndex = basename.endsWith("/") ? basename.length - 1 : basename.length;
565 let nextChar = pathname.charAt(startIndex);
566 if (nextChar && nextChar !== "/") {
567 return null;
568 }
569 return pathname.slice(startIndex) || "/";
570}
571function resolvePath(to, fromPathname = "/") {
572 let {
573 pathname: toPathname,
574 search = "",
575 hash = ""
576 } = typeof to === "string" ? parsePath(to) : to;
577 let pathname = toPathname ? toPathname.startsWith("/") ? toPathname : resolvePathname(toPathname, fromPathname) : fromPathname;
578 return {
579 pathname,
580 search: normalizeSearch(search),
581 hash: normalizeHash(hash)
582 };
583}
584function resolvePathname(relativePath, fromPathname) {
585 let segments = fromPathname.replace(/\/+$/, "").split("/");
586 let relativeSegments = relativePath.split("/");
587 relativeSegments.forEach((segment) => {
588 if (segment === "..") {
589 if (segments.length > 1) segments.pop();
590 } else if (segment !== ".") {
591 segments.push(segment);
592 }
593 });
594 return segments.length > 1 ? segments.join("/") : "/";
595}
596function getInvalidPathError(char, field, dest, path) {
597 return `Cannot include a '${char}' character in a manually specified \`to.${field}\` field [${JSON.stringify(
598 path
599 )}]. 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.`;
600}
601function getPathContributingMatches(matches) {
602 return matches.filter(
603 (match, index) => index === 0 || match.route.path && match.route.path.length > 0
604 );
605}
606function getResolveToMatches(matches) {
607 let pathMatches = getPathContributingMatches(matches);
608 return pathMatches.map(
609 (match, idx) => idx === pathMatches.length - 1 ? match.pathname : match.pathnameBase
610 );
611}
612function resolveTo(toArg, routePathnames, locationPathname, isPathRelative = false) {
613 let to;
614 if (typeof toArg === "string") {
615 to = parsePath(toArg);
616 } else {
617 to = { ...toArg };
618 invariant(
619 !to.pathname || !to.pathname.includes("?"),
620 getInvalidPathError("?", "pathname", "search", to)
621 );
622 invariant(
623 !to.pathname || !to.pathname.includes("#"),
624 getInvalidPathError("#", "pathname", "hash", to)
625 );
626 invariant(
627 !to.search || !to.search.includes("#"),
628 getInvalidPathError("#", "search", "hash", to)
629 );
630 }
631 let isEmptyPath = toArg === "" || to.pathname === "";
632 let toPathname = isEmptyPath ? "/" : to.pathname;
633 let from;
634 if (toPathname == null) {
635 from = locationPathname;
636 } else {
637 let routePathnameIndex = routePathnames.length - 1;
638 if (!isPathRelative && toPathname.startsWith("..")) {
639 let toSegments = toPathname.split("/");
640 while (toSegments[0] === "..") {
641 toSegments.shift();
642 routePathnameIndex -= 1;
643 }
644 to.pathname = toSegments.join("/");
645 }
646 from = routePathnameIndex >= 0 ? routePathnames[routePathnameIndex] : "/";
647 }
648 let path = resolvePath(to, from);
649 let hasExplicitTrailingSlash = toPathname && toPathname !== "/" && toPathname.endsWith("/");
650 let hasCurrentTrailingSlash = (isEmptyPath || toPathname === ".") && locationPathname.endsWith("/");
651 if (!path.pathname.endsWith("/") && (hasExplicitTrailingSlash || hasCurrentTrailingSlash)) {
652 path.pathname += "/";
653 }
654 return path;
655}
656var joinPaths = (paths) => paths.join("/").replace(/\/\/+/g, "/");
657var normalizePathname = (pathname) => pathname.replace(/\/+$/, "").replace(/^\/*/, "/");
658var normalizeSearch = (search) => !search || search === "?" ? "" : search.startsWith("?") ? search : "?" + search;
659var normalizeHash = (hash) => !hash || hash === "#" ? "" : hash.startsWith("#") ? hash : "#" + hash;
660var DataWithResponseInit = class {
661 constructor(data2, init) {
662 this.type = "DataWithResponseInit";
663 this.data = data2;
664 this.init = init || null;
665 }
666};
667function data(data2, init) {
668 return new DataWithResponseInit(
669 data2,
670 typeof init === "number" ? { status: init } : init
671 );
672}
673var redirect = (url, init = 302) => {
674 let responseInit = init;
675 if (typeof responseInit === "number") {
676 responseInit = { status: responseInit };
677 } else if (typeof responseInit.status === "undefined") {
678 responseInit.status = 302;
679 }
680 let headers = new Headers(responseInit.headers);
681 headers.set("Location", url);
682 return new Response(null, {
683 ...responseInit,
684 headers
685 });
686};
687var ErrorResponseImpl = class {
688 constructor(status, statusText, data2, internal = false) {
689 this.status = status;
690 this.statusText = statusText || "";
691 this.internal = internal;
692 if (data2 instanceof Error) {
693 this.data = data2.toString();
694 this.error = data2;
695 } else {
696 this.data = data2;
697 }
698 }
699};
700function isRouteErrorResponse(error) {
701 return error != null && typeof error.status === "number" && typeof error.statusText === "string" && typeof error.internal === "boolean" && "data" in error;
702}
703
704// lib/router/router.ts
705var validMutationMethodsArr = [
706 "POST",
707 "PUT",
708 "PATCH",
709 "DELETE"
710];
711var validMutationMethods = new Set(
712 validMutationMethodsArr
713);
714var validRequestMethodsArr = [
715 "GET",
716 ...validMutationMethodsArr
717];
718var validRequestMethods = new Set(validRequestMethodsArr);
719var redirectStatusCodes = /* @__PURE__ */ new Set([301, 302, 303, 307, 308]);
720var redirectPreserveMethodStatusCodes = /* @__PURE__ */ new Set([307, 308]);
721var IDLE_NAVIGATION = {
722 state: "idle",
723 location: void 0,
724 formMethod: void 0,
725 formAction: void 0,
726 formEncType: void 0,
727 formData: void 0,
728 json: void 0,
729 text: void 0
730};
731var IDLE_FETCHER = {
732 state: "idle",
733 data: void 0,
734 formMethod: void 0,
735 formAction: void 0,
736 formEncType: void 0,
737 formData: void 0,
738 json: void 0,
739 text: void 0
740};
741var IDLE_BLOCKER = {
742 state: "unblocked",
743 proceed: void 0,
744 reset: void 0,
745 location: void 0
746};
747var ABSOLUTE_URL_REGEX = /^(?:[a-z][a-z0-9+.-]*:|\/\/)/i;
748var defaultMapRouteProperties = (route) => ({
749 hasErrorBoundary: Boolean(route.hasErrorBoundary)
750});
751var TRANSITIONS_STORAGE_KEY = "remix-router-transitions";
752var ResetLoaderDataSymbol = Symbol("ResetLoaderData");
753function createRouter(init) {
754 const routerWindow = init.window ? init.window : typeof window !== "undefined" ? window : void 0;
755 const isBrowser = typeof routerWindow !== "undefined" && typeof routerWindow.document !== "undefined" && typeof routerWindow.document.createElement !== "undefined";
756 invariant(
757 init.routes.length > 0,
758 "You must provide a non-empty routes array to createRouter"
759 );
760 let mapRouteProperties2 = init.mapRouteProperties || defaultMapRouteProperties;
761 let manifest = {};
762 let dataRoutes = convertRoutesToDataRoutes(
763 init.routes,
764 mapRouteProperties2,
765 void 0,
766 manifest
767 );
768 let inFlightDataRoutes;
769 let basename = init.basename || "/";
770 let dataStrategyImpl = init.dataStrategy || defaultDataStrategy;
771 let patchRoutesOnNavigationImpl = init.patchRoutesOnNavigation;
772 let future = {
773 ...init.future
774 };
775 let unlistenHistory = null;
776 let subscribers = /* @__PURE__ */ new Set();
777 let savedScrollPositions = null;
778 let getScrollRestorationKey = null;
779 let getScrollPosition = null;
780 let initialScrollRestored = init.hydrationData != null;
781 let initialMatches = matchRoutes(dataRoutes, init.history.location, basename);
782 let initialErrors = null;
783 if (initialMatches == null && !patchRoutesOnNavigationImpl) {
784 let error = getInternalRouterError(404, {
785 pathname: init.history.location.pathname
786 });
787 let { matches, route } = getShortCircuitMatches(dataRoutes);
788 initialMatches = matches;
789 initialErrors = { [route.id]: error };
790 }
791 if (initialMatches && !init.hydrationData) {
792 let fogOfWar = checkFogOfWar(
793 initialMatches,
794 dataRoutes,
795 init.history.location.pathname
796 );
797 if (fogOfWar.active) {
798 initialMatches = null;
799 }
800 }
801 let initialized;
802 if (!initialMatches) {
803 initialized = false;
804 initialMatches = [];
805 let fogOfWar = checkFogOfWar(
806 null,
807 dataRoutes,
808 init.history.location.pathname
809 );
810 if (fogOfWar.active && fogOfWar.matches) {
811 initialMatches = fogOfWar.matches;
812 }
813 } else if (initialMatches.some((m) => m.route.lazy)) {
814 initialized = false;
815 } else if (!initialMatches.some((m) => m.route.loader)) {
816 initialized = true;
817 } else {
818 let loaderData = init.hydrationData ? init.hydrationData.loaderData : null;
819 let errors = init.hydrationData ? init.hydrationData.errors : null;
820 if (errors) {
821 let idx = initialMatches.findIndex(
822 (m) => errors[m.route.id] !== void 0
823 );
824 initialized = initialMatches.slice(0, idx + 1).every((m) => !shouldLoadRouteOnHydration(m.route, loaderData, errors));
825 } else {
826 initialized = initialMatches.every(
827 (m) => !shouldLoadRouteOnHydration(m.route, loaderData, errors)
828 );
829 }
830 }
831 let router2;
832 let state = {
833 historyAction: init.history.action,
834 location: init.history.location,
835 matches: initialMatches,
836 initialized,
837 navigation: IDLE_NAVIGATION,
838 // Don't restore on initial updateState() if we were SSR'd
839 restoreScrollPosition: init.hydrationData != null ? false : null,
840 preventScrollReset: false,
841 revalidation: "idle",
842 loaderData: init.hydrationData && init.hydrationData.loaderData || {},
843 actionData: init.hydrationData && init.hydrationData.actionData || null,
844 errors: init.hydrationData && init.hydrationData.errors || initialErrors,
845 fetchers: /* @__PURE__ */ new Map(),
846 blockers: /* @__PURE__ */ new Map()
847 };
848 let pendingAction = "POP" /* Pop */;
849 let pendingPreventScrollReset = false;
850 let pendingNavigationController;
851 let pendingViewTransitionEnabled = false;
852 let appliedViewTransitions = /* @__PURE__ */ new Map();
853 let removePageHideEventListener = null;
854 let isUninterruptedRevalidation = false;
855 let isRevalidationRequired = false;
856 let cancelledFetcherLoads = /* @__PURE__ */ new Set();
857 let fetchControllers = /* @__PURE__ */ new Map();
858 let incrementingLoadId = 0;
859 let pendingNavigationLoadId = -1;
860 let fetchReloadIds = /* @__PURE__ */ new Map();
861 let fetchRedirectIds = /* @__PURE__ */ new Set();
862 let fetchLoadMatches = /* @__PURE__ */ new Map();
863 let activeFetchers = /* @__PURE__ */ new Map();
864 let fetchersQueuedForDeletion = /* @__PURE__ */ new Set();
865 let blockerFunctions = /* @__PURE__ */ new Map();
866 let unblockBlockerHistoryUpdate = void 0;
867 let pendingRevalidationDfd = null;
868 function initialize() {
869 unlistenHistory = init.history.listen(
870 ({ action: historyAction, location, delta }) => {
871 if (unblockBlockerHistoryUpdate) {
872 unblockBlockerHistoryUpdate();
873 unblockBlockerHistoryUpdate = void 0;
874 return;
875 }
876 warning(
877 blockerFunctions.size === 0 || delta != null,
878 "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."
879 );
880 let blockerKey = shouldBlockNavigation({
881 currentLocation: state.location,
882 nextLocation: location,
883 historyAction
884 });
885 if (blockerKey && delta != null) {
886 let nextHistoryUpdatePromise = new Promise((resolve) => {
887 unblockBlockerHistoryUpdate = resolve;
888 });
889 init.history.go(delta * -1);
890 updateBlocker(blockerKey, {
891 state: "blocked",
892 location,
893 proceed() {
894 updateBlocker(blockerKey, {
895 state: "proceeding",
896 proceed: void 0,
897 reset: void 0,
898 location
899 });
900 nextHistoryUpdatePromise.then(() => init.history.go(delta));
901 },
902 reset() {
903 let blockers = new Map(state.blockers);
904 blockers.set(blockerKey, IDLE_BLOCKER);
905 updateState({ blockers });
906 }
907 });
908 return;
909 }
910 return startNavigation(historyAction, location);
911 }
912 );
913 if (isBrowser) {
914 restoreAppliedTransitions(routerWindow, appliedViewTransitions);
915 let _saveAppliedTransitions = () => persistAppliedTransitions(routerWindow, appliedViewTransitions);
916 routerWindow.addEventListener("pagehide", _saveAppliedTransitions);
917 removePageHideEventListener = () => routerWindow.removeEventListener("pagehide", _saveAppliedTransitions);
918 }
919 if (!state.initialized) {
920 startNavigation("POP" /* Pop */, state.location, {
921 initialHydration: true
922 });
923 }
924 return router2;
925 }
926 function dispose() {
927 if (unlistenHistory) {
928 unlistenHistory();
929 }
930 if (removePageHideEventListener) {
931 removePageHideEventListener();
932 }
933 subscribers.clear();
934 pendingNavigationController && pendingNavigationController.abort();
935 state.fetchers.forEach((_, key) => deleteFetcher(key));
936 state.blockers.forEach((_, key) => deleteBlocker(key));
937 }
938 function subscribe(fn) {
939 subscribers.add(fn);
940 return () => subscribers.delete(fn);
941 }
942 function updateState(newState, opts = {}) {
943 state = {
944 ...state,
945 ...newState
946 };
947 let unmountedFetchers = [];
948 let mountedFetchers = [];
949 state.fetchers.forEach((fetcher, key) => {
950 if (fetcher.state === "idle") {
951 if (fetchersQueuedForDeletion.has(key)) {
952 unmountedFetchers.push(key);
953 } else {
954 mountedFetchers.push(key);
955 }
956 }
957 });
958 [...subscribers].forEach(
959 (subscriber) => subscriber(state, {
960 deletedFetchers: unmountedFetchers,
961 viewTransitionOpts: opts.viewTransitionOpts,
962 flushSync: opts.flushSync === true
963 })
964 );
965 unmountedFetchers.forEach((key) => deleteFetcher(key));
966 mountedFetchers.forEach((key) => state.fetchers.delete(key));
967 }
968 function completeNavigation(location, newState, { flushSync: flushSync2 } = {}) {
969 let isActionReload = state.actionData != null && state.navigation.formMethod != null && isMutationMethod(state.navigation.formMethod) && state.navigation.state === "loading" && location.state?._isRedirect !== true;
970 let actionData;
971 if (newState.actionData) {
972 if (Object.keys(newState.actionData).length > 0) {
973 actionData = newState.actionData;
974 } else {
975 actionData = null;
976 }
977 } else if (isActionReload) {
978 actionData = state.actionData;
979 } else {
980 actionData = null;
981 }
982 let loaderData = newState.loaderData ? mergeLoaderData(
983 state.loaderData,
984 newState.loaderData,
985 newState.matches || [],
986 newState.errors
987 ) : state.loaderData;
988 let blockers = state.blockers;
989 if (blockers.size > 0) {
990 blockers = new Map(blockers);
991 blockers.forEach((_, k) => blockers.set(k, IDLE_BLOCKER));
992 }
993 let preventScrollReset = pendingPreventScrollReset === true || state.navigation.formMethod != null && isMutationMethod(state.navigation.formMethod) && location.state?._isRedirect !== true;
994 if (inFlightDataRoutes) {
995 dataRoutes = inFlightDataRoutes;
996 inFlightDataRoutes = void 0;
997 }
998 if (isUninterruptedRevalidation) {
999 } else if (pendingAction === "POP" /* Pop */) {
1000 } else if (pendingAction === "PUSH" /* Push */) {
1001 init.history.push(location, location.state);
1002 } else if (pendingAction === "REPLACE" /* Replace */) {
1003 init.history.replace(location, location.state);
1004 }
1005 let viewTransitionOpts;
1006 if (pendingAction === "POP" /* Pop */) {
1007 let priorPaths = appliedViewTransitions.get(state.location.pathname);
1008 if (priorPaths && priorPaths.has(location.pathname)) {
1009 viewTransitionOpts = {
1010 currentLocation: state.location,
1011 nextLocation: location
1012 };
1013 } else if (appliedViewTransitions.has(location.pathname)) {
1014 viewTransitionOpts = {
1015 currentLocation: location,
1016 nextLocation: state.location
1017 };
1018 }
1019 } else if (pendingViewTransitionEnabled) {
1020 let toPaths = appliedViewTransitions.get(state.location.pathname);
1021 if (toPaths) {
1022 toPaths.add(location.pathname);
1023 } else {
1024 toPaths = /* @__PURE__ */ new Set([location.pathname]);
1025 appliedViewTransitions.set(state.location.pathname, toPaths);
1026 }
1027 viewTransitionOpts = {
1028 currentLocation: state.location,
1029 nextLocation: location
1030 };
1031 }
1032 updateState(
1033 {
1034 ...newState,
1035 // matches, errors, fetchers go through as-is
1036 actionData,
1037 loaderData,
1038 historyAction: pendingAction,
1039 location,
1040 initialized: true,
1041 navigation: IDLE_NAVIGATION,
1042 revalidation: "idle",
1043 restoreScrollPosition: getSavedScrollPosition(
1044 location,
1045 newState.matches || state.matches
1046 ),
1047 preventScrollReset,
1048 blockers
1049 },
1050 {
1051 viewTransitionOpts,
1052 flushSync: flushSync2 === true
1053 }
1054 );
1055 pendingAction = "POP" /* Pop */;
1056 pendingPreventScrollReset = false;
1057 pendingViewTransitionEnabled = false;
1058 isUninterruptedRevalidation = false;
1059 isRevalidationRequired = false;
1060 pendingRevalidationDfd?.resolve();
1061 pendingRevalidationDfd = null;
1062 }
1063 async function navigate(to, opts) {
1064 if (typeof to === "number") {
1065 init.history.go(to);
1066 return;
1067 }
1068 let normalizedPath = normalizeTo(
1069 state.location,
1070 state.matches,
1071 basename,
1072 to,
1073 opts?.fromRouteId,
1074 opts?.relative
1075 );
1076 let { path, submission, error } = normalizeNavigateOptions(
1077 false,
1078 normalizedPath,
1079 opts
1080 );
1081 let currentLocation = state.location;
1082 let nextLocation = createLocation(state.location, path, opts && opts.state);
1083 nextLocation = {
1084 ...nextLocation,
1085 ...init.history.encodeLocation(nextLocation)
1086 };
1087 let userReplace = opts && opts.replace != null ? opts.replace : void 0;
1088 let historyAction = "PUSH" /* Push */;
1089 if (userReplace === true) {
1090 historyAction = "REPLACE" /* Replace */;
1091 } else if (userReplace === false) {
1092 } else if (submission != null && isMutationMethod(submission.formMethod) && submission.formAction === state.location.pathname + state.location.search) {
1093 historyAction = "REPLACE" /* Replace */;
1094 }
1095 let preventScrollReset = opts && "preventScrollReset" in opts ? opts.preventScrollReset === true : void 0;
1096 let flushSync2 = (opts && opts.flushSync) === true;
1097 let blockerKey = shouldBlockNavigation({
1098 currentLocation,
1099 nextLocation,
1100 historyAction
1101 });
1102 if (blockerKey) {
1103 updateBlocker(blockerKey, {
1104 state: "blocked",
1105 location: nextLocation,
1106 proceed() {
1107 updateBlocker(blockerKey, {
1108 state: "proceeding",
1109 proceed: void 0,
1110 reset: void 0,
1111 location: nextLocation
1112 });
1113 navigate(to, opts);
1114 },
1115 reset() {
1116 let blockers = new Map(state.blockers);
1117 blockers.set(blockerKey, IDLE_BLOCKER);
1118 updateState({ blockers });
1119 }
1120 });
1121 return;
1122 }
1123 await startNavigation(historyAction, nextLocation, {
1124 submission,
1125 // Send through the formData serialization error if we have one so we can
1126 // render at the right error boundary after we match routes
1127 pendingError: error,
1128 preventScrollReset,
1129 replace: opts && opts.replace,
1130 enableViewTransition: opts && opts.viewTransition,
1131 flushSync: flushSync2
1132 });
1133 }
1134 function revalidate() {
1135 if (!pendingRevalidationDfd) {
1136 pendingRevalidationDfd = createDeferred();
1137 }
1138 interruptActiveLoads();
1139 updateState({ revalidation: "loading" });
1140 let promise = pendingRevalidationDfd.promise;
1141 if (state.navigation.state === "submitting") {
1142 return promise;
1143 }
1144 if (state.navigation.state === "idle") {
1145 startNavigation(state.historyAction, state.location, {
1146 startUninterruptedRevalidation: true
1147 });
1148 return promise;
1149 }
1150 startNavigation(
1151 pendingAction || state.historyAction,
1152 state.navigation.location,
1153 {
1154 overrideNavigation: state.navigation,
1155 // Proxy through any rending view transition
1156 enableViewTransition: pendingViewTransitionEnabled === true
1157 }
1158 );
1159 return promise;
1160 }
1161 async function startNavigation(historyAction, location, opts) {
1162 pendingNavigationController && pendingNavigationController.abort();
1163 pendingNavigationController = null;
1164 pendingAction = historyAction;
1165 isUninterruptedRevalidation = (opts && opts.startUninterruptedRevalidation) === true;
1166 saveScrollPosition(state.location, state.matches);
1167 pendingPreventScrollReset = (opts && opts.preventScrollReset) === true;
1168 pendingViewTransitionEnabled = (opts && opts.enableViewTransition) === true;
1169 let routesToUse = inFlightDataRoutes || dataRoutes;
1170 let loadingNavigation = opts && opts.overrideNavigation;
1171 let matches = matchRoutes(routesToUse, location, basename);
1172 let flushSync2 = (opts && opts.flushSync) === true;
1173 let fogOfWar = checkFogOfWar(matches, routesToUse, location.pathname);
1174 if (fogOfWar.active && fogOfWar.matches) {
1175 matches = fogOfWar.matches;
1176 }
1177 if (!matches) {
1178 let { error, notFoundMatches, route } = handleNavigational404(
1179 location.pathname
1180 );
1181 completeNavigation(
1182 location,
1183 {
1184 matches: notFoundMatches,
1185 loaderData: {},
1186 errors: {
1187 [route.id]: error
1188 }
1189 },
1190 { flushSync: flushSync2 }
1191 );
1192 return;
1193 }
1194 if (state.initialized && !isRevalidationRequired && isHashChangeOnly(state.location, location) && !(opts && opts.submission && isMutationMethod(opts.submission.formMethod))) {
1195 completeNavigation(location, { matches }, { flushSync: flushSync2 });
1196 return;
1197 }
1198 pendingNavigationController = new AbortController();
1199 let request = createClientSideRequest(
1200 init.history,
1201 location,
1202 pendingNavigationController.signal,
1203 opts && opts.submission
1204 );
1205 let pendingActionResult;
1206 if (opts && opts.pendingError) {
1207 pendingActionResult = [
1208 findNearestBoundary(matches).route.id,
1209 { type: "error" /* error */, error: opts.pendingError }
1210 ];
1211 } else if (opts && opts.submission && isMutationMethod(opts.submission.formMethod)) {
1212 let actionResult = await handleAction(
1213 request,
1214 location,
1215 opts.submission,
1216 matches,
1217 fogOfWar.active,
1218 { replace: opts.replace, flushSync: flushSync2 }
1219 );
1220 if (actionResult.shortCircuited) {
1221 return;
1222 }
1223 if (actionResult.pendingActionResult) {
1224 let [routeId, result] = actionResult.pendingActionResult;
1225 if (isErrorResult(result) && isRouteErrorResponse(result.error) && result.error.status === 404) {
1226 pendingNavigationController = null;
1227 completeNavigation(location, {
1228 matches: actionResult.matches,
1229 loaderData: {},
1230 errors: {
1231 [routeId]: result.error
1232 }
1233 });
1234 return;
1235 }
1236 }
1237 matches = actionResult.matches || matches;
1238 pendingActionResult = actionResult.pendingActionResult;
1239 loadingNavigation = getLoadingNavigation(location, opts.submission);
1240 flushSync2 = false;
1241 fogOfWar.active = false;
1242 request = createClientSideRequest(
1243 init.history,
1244 request.url,
1245 request.signal
1246 );
1247 }
1248 let {
1249 shortCircuited,
1250 matches: updatedMatches,
1251 loaderData,
1252 errors
1253 } = await handleLoaders(
1254 request,
1255 location,
1256 matches,
1257 fogOfWar.active,
1258 loadingNavigation,
1259 opts && opts.submission,
1260 opts && opts.fetcherSubmission,
1261 opts && opts.replace,
1262 opts && opts.initialHydration === true,
1263 flushSync2,
1264 pendingActionResult
1265 );
1266 if (shortCircuited) {
1267 return;
1268 }
1269 pendingNavigationController = null;
1270 completeNavigation(location, {
1271 matches: updatedMatches || matches,
1272 ...getActionDataForCommit(pendingActionResult),
1273 loaderData,
1274 errors
1275 });
1276 }
1277 async function handleAction(request, location, submission, matches, isFogOfWar, opts = {}) {
1278 interruptActiveLoads();
1279 let navigation = getSubmittingNavigation(location, submission);
1280 updateState({ navigation }, { flushSync: opts.flushSync === true });
1281 if (isFogOfWar) {
1282 let discoverResult = await discoverRoutes(
1283 matches,
1284 location.pathname,
1285 request.signal
1286 );
1287 if (discoverResult.type === "aborted") {
1288 return { shortCircuited: true };
1289 } else if (discoverResult.type === "error") {
1290 let boundaryId = findNearestBoundary(discoverResult.partialMatches).route.id;
1291 return {
1292 matches: discoverResult.partialMatches,
1293 pendingActionResult: [
1294 boundaryId,
1295 {
1296 type: "error" /* error */,
1297 error: discoverResult.error
1298 }
1299 ]
1300 };
1301 } else if (!discoverResult.matches) {
1302 let { notFoundMatches, error, route } = handleNavigational404(
1303 location.pathname
1304 );
1305 return {
1306 matches: notFoundMatches,
1307 pendingActionResult: [
1308 route.id,
1309 {
1310 type: "error" /* error */,
1311 error
1312 }
1313 ]
1314 };
1315 } else {
1316 matches = discoverResult.matches;
1317 }
1318 }
1319 let result;
1320 let actionMatch = getTargetMatch(matches, location);
1321 if (!actionMatch.route.action && !actionMatch.route.lazy) {
1322 result = {
1323 type: "error" /* error */,
1324 error: getInternalRouterError(405, {
1325 method: request.method,
1326 pathname: location.pathname,
1327 routeId: actionMatch.route.id
1328 })
1329 };
1330 } else {
1331 let results = await callDataStrategy(
1332 "action",
1333 state,
1334 request,
1335 [actionMatch],
1336 matches,
1337 null
1338 );
1339 result = results[actionMatch.route.id];
1340 if (request.signal.aborted) {
1341 return { shortCircuited: true };
1342 }
1343 }
1344 if (isRedirectResult(result)) {
1345 let replace2;
1346 if (opts && opts.replace != null) {
1347 replace2 = opts.replace;
1348 } else {
1349 let location2 = normalizeRedirectLocation(
1350 result.response.headers.get("Location"),
1351 new URL(request.url),
1352 basename
1353 );
1354 replace2 = location2 === state.location.pathname + state.location.search;
1355 }
1356 await startRedirectNavigation(request, result, true, {
1357 submission,
1358 replace: replace2
1359 });
1360 return { shortCircuited: true };
1361 }
1362 if (isErrorResult(result)) {
1363 let boundaryMatch = findNearestBoundary(matches, actionMatch.route.id);
1364 if ((opts && opts.replace) !== true) {
1365 pendingAction = "PUSH" /* Push */;
1366 }
1367 return {
1368 matches,
1369 pendingActionResult: [boundaryMatch.route.id, result]
1370 };
1371 }
1372 return {
1373 matches,
1374 pendingActionResult: [actionMatch.route.id, result]
1375 };
1376 }
1377 async function handleLoaders(request, location, matches, isFogOfWar, overrideNavigation, submission, fetcherSubmission, replace2, initialHydration, flushSync2, pendingActionResult) {
1378 let loadingNavigation = overrideNavigation || getLoadingNavigation(location, submission);
1379 let activeSubmission = submission || fetcherSubmission || getSubmissionFromNavigation(loadingNavigation);
1380 let shouldUpdateNavigationState = !isUninterruptedRevalidation && !initialHydration;
1381 if (isFogOfWar) {
1382 if (shouldUpdateNavigationState) {
1383 let actionData = getUpdatedActionData(pendingActionResult);
1384 updateState(
1385 {
1386 navigation: loadingNavigation,
1387 ...actionData !== void 0 ? { actionData } : {}
1388 },
1389 {
1390 flushSync: flushSync2
1391 }
1392 );
1393 }
1394 let discoverResult = await discoverRoutes(
1395 matches,
1396 location.pathname,
1397 request.signal
1398 );
1399 if (discoverResult.type === "aborted") {
1400 return { shortCircuited: true };
1401 } else if (discoverResult.type === "error") {
1402 let boundaryId = findNearestBoundary(discoverResult.partialMatches).route.id;
1403 return {
1404 matches: discoverResult.partialMatches,
1405 loaderData: {},
1406 errors: {
1407 [boundaryId]: discoverResult.error
1408 }
1409 };
1410 } else if (!discoverResult.matches) {
1411 let { error, notFoundMatches, route } = handleNavigational404(
1412 location.pathname
1413 );
1414 return {
1415 matches: notFoundMatches,
1416 loaderData: {},
1417 errors: {
1418 [route.id]: error
1419 }
1420 };
1421 } else {
1422 matches = discoverResult.matches;
1423 }
1424 }
1425 let routesToUse = inFlightDataRoutes || dataRoutes;
1426 let [matchesToLoad, revalidatingFetchers] = getMatchesToLoad(
1427 init.history,
1428 state,
1429 matches,
1430 activeSubmission,
1431 location,
1432 initialHydration === true,
1433 isRevalidationRequired,
1434 cancelledFetcherLoads,
1435 fetchersQueuedForDeletion,
1436 fetchLoadMatches,
1437 fetchRedirectIds,
1438 routesToUse,
1439 basename,
1440 pendingActionResult
1441 );
1442 pendingNavigationLoadId = ++incrementingLoadId;
1443 if (matchesToLoad.length === 0 && revalidatingFetchers.length === 0) {
1444 let updatedFetchers2 = markFetchRedirectsDone();
1445 completeNavigation(
1446 location,
1447 {
1448 matches,
1449 loaderData: {},
1450 // Commit pending error if we're short circuiting
1451 errors: pendingActionResult && isErrorResult(pendingActionResult[1]) ? { [pendingActionResult[0]]: pendingActionResult[1].error } : null,
1452 ...getActionDataForCommit(pendingActionResult),
1453 ...updatedFetchers2 ? { fetchers: new Map(state.fetchers) } : {}
1454 },
1455 { flushSync: flushSync2 }
1456 );
1457 return { shortCircuited: true };
1458 }
1459 if (shouldUpdateNavigationState) {
1460 let updates = {};
1461 if (!isFogOfWar) {
1462 updates.navigation = loadingNavigation;
1463 let actionData = getUpdatedActionData(pendingActionResult);
1464 if (actionData !== void 0) {
1465 updates.actionData = actionData;
1466 }
1467 }
1468 if (revalidatingFetchers.length > 0) {
1469 updates.fetchers = getUpdatedRevalidatingFetchers(revalidatingFetchers);
1470 }
1471 updateState(updates, { flushSync: flushSync2 });
1472 }
1473 revalidatingFetchers.forEach((rf) => {
1474 abortFetcher(rf.key);
1475 if (rf.controller) {
1476 fetchControllers.set(rf.key, rf.controller);
1477 }
1478 });
1479 let abortPendingFetchRevalidations = () => revalidatingFetchers.forEach((f) => abortFetcher(f.key));
1480 if (pendingNavigationController) {
1481 pendingNavigationController.signal.addEventListener(
1482 "abort",
1483 abortPendingFetchRevalidations
1484 );
1485 }
1486 let { loaderResults, fetcherResults } = await callLoadersAndMaybeResolveData(
1487 state,
1488 matches,
1489 matchesToLoad,
1490 revalidatingFetchers,
1491 request
1492 );
1493 if (request.signal.aborted) {
1494 return { shortCircuited: true };
1495 }
1496 if (pendingNavigationController) {
1497 pendingNavigationController.signal.removeEventListener(
1498 "abort",
1499 abortPendingFetchRevalidations
1500 );
1501 }
1502 revalidatingFetchers.forEach((rf) => fetchControllers.delete(rf.key));
1503 let redirect2 = findRedirect(loaderResults);
1504 if (redirect2) {
1505 await startRedirectNavigation(request, redirect2.result, true, {
1506 replace: replace2
1507 });
1508 return { shortCircuited: true };
1509 }
1510 redirect2 = findRedirect(fetcherResults);
1511 if (redirect2) {
1512 fetchRedirectIds.add(redirect2.key);
1513 await startRedirectNavigation(request, redirect2.result, true, {
1514 replace: replace2
1515 });
1516 return { shortCircuited: true };
1517 }
1518 let { loaderData, errors } = processLoaderData(
1519 state,
1520 matches,
1521 loaderResults,
1522 pendingActionResult,
1523 revalidatingFetchers,
1524 fetcherResults
1525 );
1526 if (initialHydration && state.errors) {
1527 errors = { ...state.errors, ...errors };
1528 }
1529 let updatedFetchers = markFetchRedirectsDone();
1530 let didAbortFetchLoads = abortStaleFetchLoads(pendingNavigationLoadId);
1531 let shouldUpdateFetchers = updatedFetchers || didAbortFetchLoads || revalidatingFetchers.length > 0;
1532 return {
1533 matches,
1534 loaderData,
1535 errors,
1536 ...shouldUpdateFetchers ? { fetchers: new Map(state.fetchers) } : {}
1537 };
1538 }
1539 function getUpdatedActionData(pendingActionResult) {
1540 if (pendingActionResult && !isErrorResult(pendingActionResult[1])) {
1541 return {
1542 [pendingActionResult[0]]: pendingActionResult[1].data
1543 };
1544 } else if (state.actionData) {
1545 if (Object.keys(state.actionData).length === 0) {
1546 return null;
1547 } else {
1548 return state.actionData;
1549 }
1550 }
1551 }
1552 function getUpdatedRevalidatingFetchers(revalidatingFetchers) {
1553 revalidatingFetchers.forEach((rf) => {
1554 let fetcher = state.fetchers.get(rf.key);
1555 let revalidatingFetcher = getLoadingFetcher(
1556 void 0,
1557 fetcher ? fetcher.data : void 0
1558 );
1559 state.fetchers.set(rf.key, revalidatingFetcher);
1560 });
1561 return new Map(state.fetchers);
1562 }
1563 async function fetch2(key, routeId, href, opts) {
1564 abortFetcher(key);
1565 let flushSync2 = (opts && opts.flushSync) === true;
1566 let routesToUse = inFlightDataRoutes || dataRoutes;
1567 let normalizedPath = normalizeTo(
1568 state.location,
1569 state.matches,
1570 basename,
1571 href,
1572 routeId,
1573 opts?.relative
1574 );
1575 let matches = matchRoutes(routesToUse, normalizedPath, basename);
1576 let fogOfWar = checkFogOfWar(matches, routesToUse, normalizedPath);
1577 if (fogOfWar.active && fogOfWar.matches) {
1578 matches = fogOfWar.matches;
1579 }
1580 if (!matches) {
1581 setFetcherError(
1582 key,
1583 routeId,
1584 getInternalRouterError(404, { pathname: normalizedPath }),
1585 { flushSync: flushSync2 }
1586 );
1587 return;
1588 }
1589 let { path, submission, error } = normalizeNavigateOptions(
1590 true,
1591 normalizedPath,
1592 opts
1593 );
1594 if (error) {
1595 setFetcherError(key, routeId, error, { flushSync: flushSync2 });
1596 return;
1597 }
1598 let match = getTargetMatch(matches, path);
1599 let preventScrollReset = (opts && opts.preventScrollReset) === true;
1600 if (submission && isMutationMethod(submission.formMethod)) {
1601 await handleFetcherAction(
1602 key,
1603 routeId,
1604 path,
1605 match,
1606 matches,
1607 fogOfWar.active,
1608 flushSync2,
1609 preventScrollReset,
1610 submission
1611 );
1612 return;
1613 }
1614 fetchLoadMatches.set(key, { routeId, path });
1615 await handleFetcherLoader(
1616 key,
1617 routeId,
1618 path,
1619 match,
1620 matches,
1621 fogOfWar.active,
1622 flushSync2,
1623 preventScrollReset,
1624 submission
1625 );
1626 }
1627 async function handleFetcherAction(key, routeId, path, match, requestMatches, isFogOfWar, flushSync2, preventScrollReset, submission) {
1628 interruptActiveLoads();
1629 fetchLoadMatches.delete(key);
1630 function detectAndHandle405Error(m) {
1631 if (!m.route.action && !m.route.lazy) {
1632 let error = getInternalRouterError(405, {
1633 method: submission.formMethod,
1634 pathname: path,
1635 routeId
1636 });
1637 setFetcherError(key, routeId, error, { flushSync: flushSync2 });
1638 return true;
1639 }
1640 return false;
1641 }
1642 if (!isFogOfWar && detectAndHandle405Error(match)) {
1643 return;
1644 }
1645 let existingFetcher = state.fetchers.get(key);
1646 updateFetcherState(key, getSubmittingFetcher(submission, existingFetcher), {
1647 flushSync: flushSync2
1648 });
1649 let abortController = new AbortController();
1650 let fetchRequest = createClientSideRequest(
1651 init.history,
1652 path,
1653 abortController.signal,
1654 submission
1655 );
1656 if (isFogOfWar) {
1657 let discoverResult = await discoverRoutes(
1658 requestMatches,
1659 path,
1660 fetchRequest.signal
1661 );
1662 if (discoverResult.type === "aborted") {
1663 return;
1664 } else if (discoverResult.type === "error") {
1665 setFetcherError(key, routeId, discoverResult.error, { flushSync: flushSync2 });
1666 return;
1667 } else if (!discoverResult.matches) {
1668 setFetcherError(
1669 key,
1670 routeId,
1671 getInternalRouterError(404, { pathname: path }),
1672 { flushSync: flushSync2 }
1673 );
1674 return;
1675 } else {
1676 requestMatches = discoverResult.matches;
1677 match = getTargetMatch(requestMatches, path);
1678 if (detectAndHandle405Error(match)) {
1679 return;
1680 }
1681 }
1682 }
1683 fetchControllers.set(key, abortController);
1684 let originatingLoadId = incrementingLoadId;
1685 let actionResults = await callDataStrategy(
1686 "action",
1687 state,
1688 fetchRequest,
1689 [match],
1690 requestMatches,
1691 key
1692 );
1693 let actionResult = actionResults[match.route.id];
1694 if (fetchRequest.signal.aborted) {
1695 if (fetchControllers.get(key) === abortController) {
1696 fetchControllers.delete(key);
1697 }
1698 return;
1699 }
1700 if (fetchersQueuedForDeletion.has(key)) {
1701 if (isRedirectResult(actionResult) || isErrorResult(actionResult)) {
1702 updateFetcherState(key, getDoneFetcher(void 0));
1703 return;
1704 }
1705 } else {
1706 if (isRedirectResult(actionResult)) {
1707 fetchControllers.delete(key);
1708 if (pendingNavigationLoadId > originatingLoadId) {
1709 updateFetcherState(key, getDoneFetcher(void 0));
1710 return;
1711 } else {
1712 fetchRedirectIds.add(key);
1713 updateFetcherState(key, getLoadingFetcher(submission));
1714 return startRedirectNavigation(fetchRequest, actionResult, false, {
1715 fetcherSubmission: submission,
1716 preventScrollReset
1717 });
1718 }
1719 }
1720 if (isErrorResult(actionResult)) {
1721 setFetcherError(key, routeId, actionResult.error);
1722 return;
1723 }
1724 }
1725 let nextLocation = state.navigation.location || state.location;
1726 let revalidationRequest = createClientSideRequest(
1727 init.history,
1728 nextLocation,
1729 abortController.signal
1730 );
1731 let routesToUse = inFlightDataRoutes || dataRoutes;
1732 let matches = state.navigation.state !== "idle" ? matchRoutes(routesToUse, state.navigation.location, basename) : state.matches;
1733 invariant(matches, "Didn't find any matches after fetcher action");
1734 let loadId = ++incrementingLoadId;
1735 fetchReloadIds.set(key, loadId);
1736 let loadFetcher = getLoadingFetcher(submission, actionResult.data);
1737 state.fetchers.set(key, loadFetcher);
1738 let [matchesToLoad, revalidatingFetchers] = getMatchesToLoad(
1739 init.history,
1740 state,
1741 matches,
1742 submission,
1743 nextLocation,
1744 false,
1745 isRevalidationRequired,
1746 cancelledFetcherLoads,
1747 fetchersQueuedForDeletion,
1748 fetchLoadMatches,
1749 fetchRedirectIds,
1750 routesToUse,
1751 basename,
1752 [match.route.id, actionResult]
1753 );
1754 revalidatingFetchers.filter((rf) => rf.key !== key).forEach((rf) => {
1755 let staleKey = rf.key;
1756 let existingFetcher2 = state.fetchers.get(staleKey);
1757 let revalidatingFetcher = getLoadingFetcher(
1758 void 0,
1759 existingFetcher2 ? existingFetcher2.data : void 0
1760 );
1761 state.fetchers.set(staleKey, revalidatingFetcher);
1762 abortFetcher(staleKey);
1763 if (rf.controller) {
1764 fetchControllers.set(staleKey, rf.controller);
1765 }
1766 });
1767 updateState({ fetchers: new Map(state.fetchers) });
1768 let abortPendingFetchRevalidations = () => revalidatingFetchers.forEach((rf) => abortFetcher(rf.key));
1769 abortController.signal.addEventListener(
1770 "abort",
1771 abortPendingFetchRevalidations
1772 );
1773 let { loaderResults, fetcherResults } = await callLoadersAndMaybeResolveData(
1774 state,
1775 matches,
1776 matchesToLoad,
1777 revalidatingFetchers,
1778 revalidationRequest
1779 );
1780 if (abortController.signal.aborted) {
1781 return;
1782 }
1783 abortController.signal.removeEventListener(
1784 "abort",
1785 abortPendingFetchRevalidations
1786 );
1787 fetchReloadIds.delete(key);
1788 fetchControllers.delete(key);
1789 revalidatingFetchers.forEach((r) => fetchControllers.delete(r.key));
1790 let redirect2 = findRedirect(loaderResults);
1791 if (redirect2) {
1792 return startRedirectNavigation(
1793 revalidationRequest,
1794 redirect2.result,
1795 false,
1796 { preventScrollReset }
1797 );
1798 }
1799 redirect2 = findRedirect(fetcherResults);
1800 if (redirect2) {
1801 fetchRedirectIds.add(redirect2.key);
1802 return startRedirectNavigation(
1803 revalidationRequest,
1804 redirect2.result,
1805 false,
1806 { preventScrollReset }
1807 );
1808 }
1809 let { loaderData, errors } = processLoaderData(
1810 state,
1811 matches,
1812 loaderResults,
1813 void 0,
1814 revalidatingFetchers,
1815 fetcherResults
1816 );
1817 if (state.fetchers.has(key)) {
1818 let doneFetcher = getDoneFetcher(actionResult.data);
1819 state.fetchers.set(key, doneFetcher);
1820 }
1821 abortStaleFetchLoads(loadId);
1822 if (state.navigation.state === "loading" && loadId > pendingNavigationLoadId) {
1823 invariant(pendingAction, "Expected pending action");
1824 pendingNavigationController && pendingNavigationController.abort();
1825 completeNavigation(state.navigation.location, {
1826 matches,
1827 loaderData,
1828 errors,
1829 fetchers: new Map(state.fetchers)
1830 });
1831 } else {
1832 updateState({
1833 errors,
1834 loaderData: mergeLoaderData(
1835 state.loaderData,
1836 loaderData,
1837 matches,
1838 errors
1839 ),
1840 fetchers: new Map(state.fetchers)
1841 });
1842 isRevalidationRequired = false;
1843 }
1844 }
1845 async function handleFetcherLoader(key, routeId, path, match, matches, isFogOfWar, flushSync2, preventScrollReset, submission) {
1846 let existingFetcher = state.fetchers.get(key);
1847 updateFetcherState(
1848 key,
1849 getLoadingFetcher(
1850 submission,
1851 existingFetcher ? existingFetcher.data : void 0
1852 ),
1853 { flushSync: flushSync2 }
1854 );
1855 let abortController = new AbortController();
1856 let fetchRequest = createClientSideRequest(
1857 init.history,
1858 path,
1859 abortController.signal
1860 );
1861 if (isFogOfWar) {
1862 let discoverResult = await discoverRoutes(
1863 matches,
1864 path,
1865 fetchRequest.signal
1866 );
1867 if (discoverResult.type === "aborted") {
1868 return;
1869 } else if (discoverResult.type === "error") {
1870 setFetcherError(key, routeId, discoverResult.error, { flushSync: flushSync2 });
1871 return;
1872 } else if (!discoverResult.matches) {
1873 setFetcherError(
1874 key,
1875 routeId,
1876 getInternalRouterError(404, { pathname: path }),
1877 { flushSync: flushSync2 }
1878 );
1879 return;
1880 } else {
1881 matches = discoverResult.matches;
1882 match = getTargetMatch(matches, path);
1883 }
1884 }
1885 fetchControllers.set(key, abortController);
1886 let originatingLoadId = incrementingLoadId;
1887 let results = await callDataStrategy(
1888 "loader",
1889 state,
1890 fetchRequest,
1891 [match],
1892 matches,
1893 key
1894 );
1895 let result = results[match.route.id];
1896 if (fetchControllers.get(key) === abortController) {
1897 fetchControllers.delete(key);
1898 }
1899 if (fetchRequest.signal.aborted) {
1900 return;
1901 }
1902 if (fetchersQueuedForDeletion.has(key)) {
1903 updateFetcherState(key, getDoneFetcher(void 0));
1904 return;
1905 }
1906 if (isRedirectResult(result)) {
1907 if (pendingNavigationLoadId > originatingLoadId) {
1908 updateFetcherState(key, getDoneFetcher(void 0));
1909 return;
1910 } else {
1911 fetchRedirectIds.add(key);
1912 await startRedirectNavigation(fetchRequest, result, false, {
1913 preventScrollReset
1914 });
1915 return;
1916 }
1917 }
1918 if (isErrorResult(result)) {
1919 setFetcherError(key, routeId, result.error);
1920 return;
1921 }
1922 updateFetcherState(key, getDoneFetcher(result.data));
1923 }
1924 async function startRedirectNavigation(request, redirect2, isNavigation, {
1925 submission,
1926 fetcherSubmission,
1927 preventScrollReset,
1928 replace: replace2
1929 } = {}) {
1930 if (redirect2.response.headers.has("X-Remix-Revalidate")) {
1931 isRevalidationRequired = true;
1932 }
1933 let location = redirect2.response.headers.get("Location");
1934 invariant(location, "Expected a Location header on the redirect Response");
1935 location = normalizeRedirectLocation(
1936 location,
1937 new URL(request.url),
1938 basename
1939 );
1940 let redirectLocation = createLocation(state.location, location, {
1941 _isRedirect: true
1942 });
1943 if (isBrowser) {
1944 let isDocumentReload = false;
1945 if (redirect2.response.headers.has("X-Remix-Reload-Document")) {
1946 isDocumentReload = true;
1947 } else if (ABSOLUTE_URL_REGEX.test(location)) {
1948 const url = init.history.createURL(location);
1949 isDocumentReload = // Hard reload if it's an absolute URL to a new origin
1950 url.origin !== routerWindow.location.origin || // Hard reload if it's an absolute URL that does not match our basename
1951 stripBasename(url.pathname, basename) == null;
1952 }
1953 if (isDocumentReload) {
1954 if (replace2) {
1955 routerWindow.location.replace(location);
1956 } else {
1957 routerWindow.location.assign(location);
1958 }
1959 return;
1960 }
1961 }
1962 pendingNavigationController = null;
1963 let redirectNavigationType = replace2 === true || redirect2.response.headers.has("X-Remix-Replace") ? "REPLACE" /* Replace */ : "PUSH" /* Push */;
1964 let { formMethod, formAction, formEncType } = state.navigation;
1965 if (!submission && !fetcherSubmission && formMethod && formAction && formEncType) {
1966 submission = getSubmissionFromNavigation(state.navigation);
1967 }
1968 let activeSubmission = submission || fetcherSubmission;
1969 if (redirectPreserveMethodStatusCodes.has(redirect2.response.status) && activeSubmission && isMutationMethod(activeSubmission.formMethod)) {
1970 await startNavigation(redirectNavigationType, redirectLocation, {
1971 submission: {
1972 ...activeSubmission,
1973 formAction: location
1974 },
1975 // Preserve these flags across redirects
1976 preventScrollReset: preventScrollReset || pendingPreventScrollReset,
1977 enableViewTransition: isNavigation ? pendingViewTransitionEnabled : void 0
1978 });
1979 } else {
1980 let overrideNavigation = getLoadingNavigation(
1981 redirectLocation,
1982 submission
1983 );
1984 await startNavigation(redirectNavigationType, redirectLocation, {
1985 overrideNavigation,
1986 // Send fetcher submissions through for shouldRevalidate
1987 fetcherSubmission,
1988 // Preserve these flags across redirects
1989 preventScrollReset: preventScrollReset || pendingPreventScrollReset,
1990 enableViewTransition: isNavigation ? pendingViewTransitionEnabled : void 0
1991 });
1992 }
1993 }
1994 async function callDataStrategy(type, state2, request, matchesToLoad, matches, fetcherKey) {
1995 let results;
1996 let dataResults = {};
1997 try {
1998 results = await callDataStrategyImpl(
1999 dataStrategyImpl,
2000 type,
2001 state2,
2002 request,
2003 matchesToLoad,
2004 matches,
2005 fetcherKey,
2006 manifest,
2007 mapRouteProperties2
2008 );
2009 } catch (e) {
2010 matchesToLoad.forEach((m) => {
2011 dataResults[m.route.id] = {
2012 type: "error" /* error */,
2013 error: e
2014 };
2015 });
2016 return dataResults;
2017 }
2018 for (let [routeId, result] of Object.entries(results)) {
2019 if (isRedirectDataStrategyResult(result)) {
2020 let response = result.result;
2021 dataResults[routeId] = {
2022 type: "redirect" /* redirect */,
2023 response: normalizeRelativeRoutingRedirectResponse(
2024 response,
2025 request,
2026 routeId,
2027 matches,
2028 basename
2029 )
2030 };
2031 } else {
2032 dataResults[routeId] = await convertDataStrategyResultToDataResult(
2033 result
2034 );
2035 }
2036 }
2037 return dataResults;
2038 }
2039 async function callLoadersAndMaybeResolveData(state2, matches, matchesToLoad, fetchersToLoad, request) {
2040 let loaderResultsPromise = callDataStrategy(
2041 "loader",
2042 state2,
2043 request,
2044 matchesToLoad,
2045 matches,
2046 null
2047 );
2048 let fetcherResultsPromise = Promise.all(
2049 fetchersToLoad.map(async (f) => {
2050 if (f.matches && f.match && f.controller) {
2051 let results = await callDataStrategy(
2052 "loader",
2053 state2,
2054 createClientSideRequest(init.history, f.path, f.controller.signal),
2055 [f.match],
2056 f.matches,
2057 f.key
2058 );
2059 let result = results[f.match.route.id];
2060 return { [f.key]: result };
2061 } else {
2062 return Promise.resolve({
2063 [f.key]: {
2064 type: "error" /* error */,
2065 error: getInternalRouterError(404, {
2066 pathname: f.path
2067 })
2068 }
2069 });
2070 }
2071 })
2072 );
2073 let loaderResults = await loaderResultsPromise;
2074 let fetcherResults = (await fetcherResultsPromise).reduce(
2075 (acc, r) => Object.assign(acc, r),
2076 {}
2077 );
2078 return {
2079 loaderResults,
2080 fetcherResults
2081 };
2082 }
2083 function interruptActiveLoads() {
2084 isRevalidationRequired = true;
2085 fetchLoadMatches.forEach((_, key) => {
2086 if (fetchControllers.has(key)) {
2087 cancelledFetcherLoads.add(key);
2088 }
2089 abortFetcher(key);
2090 });
2091 }
2092 function updateFetcherState(key, fetcher, opts = {}) {
2093 state.fetchers.set(key, fetcher);
2094 updateState(
2095 { fetchers: new Map(state.fetchers) },
2096 { flushSync: (opts && opts.flushSync) === true }
2097 );
2098 }
2099 function setFetcherError(key, routeId, error, opts = {}) {
2100 let boundaryMatch = findNearestBoundary(state.matches, routeId);
2101 deleteFetcher(key);
2102 updateState(
2103 {
2104 errors: {
2105 [boundaryMatch.route.id]: error
2106 },
2107 fetchers: new Map(state.fetchers)
2108 },
2109 { flushSync: (opts && opts.flushSync) === true }
2110 );
2111 }
2112 function getFetcher(key) {
2113 activeFetchers.set(key, (activeFetchers.get(key) || 0) + 1);
2114 if (fetchersQueuedForDeletion.has(key)) {
2115 fetchersQueuedForDeletion.delete(key);
2116 }
2117 return state.fetchers.get(key) || IDLE_FETCHER;
2118 }
2119 function deleteFetcher(key) {
2120 let fetcher = state.fetchers.get(key);
2121 if (fetchControllers.has(key) && !(fetcher && fetcher.state === "loading" && fetchReloadIds.has(key))) {
2122 abortFetcher(key);
2123 }
2124 fetchLoadMatches.delete(key);
2125 fetchReloadIds.delete(key);
2126 fetchRedirectIds.delete(key);
2127 fetchersQueuedForDeletion.delete(key);
2128 cancelledFetcherLoads.delete(key);
2129 state.fetchers.delete(key);
2130 }
2131 function queueFetcherForDeletion(key) {
2132 let count = (activeFetchers.get(key) || 0) - 1;
2133 if (count <= 0) {
2134 activeFetchers.delete(key);
2135 fetchersQueuedForDeletion.add(key);
2136 } else {
2137 activeFetchers.set(key, count);
2138 }
2139 updateState({ fetchers: new Map(state.fetchers) });
2140 }
2141 function abortFetcher(key) {
2142 let controller = fetchControllers.get(key);
2143 if (controller) {
2144 controller.abort();
2145 fetchControllers.delete(key);
2146 }
2147 }
2148 function markFetchersDone(keys) {
2149 for (let key of keys) {
2150 let fetcher = getFetcher(key);
2151 let doneFetcher = getDoneFetcher(fetcher.data);
2152 state.fetchers.set(key, doneFetcher);
2153 }
2154 }
2155 function markFetchRedirectsDone() {
2156 let doneKeys = [];
2157 let updatedFetchers = false;
2158 for (let key of fetchRedirectIds) {
2159 let fetcher = state.fetchers.get(key);
2160 invariant(fetcher, `Expected fetcher: ${key}`);
2161 if (fetcher.state === "loading") {
2162 fetchRedirectIds.delete(key);
2163 doneKeys.push(key);
2164 updatedFetchers = true;
2165 }
2166 }
2167 markFetchersDone(doneKeys);
2168 return updatedFetchers;
2169 }
2170 function abortStaleFetchLoads(landedId) {
2171 let yeetedKeys = [];
2172 for (let [key, id] of fetchReloadIds) {
2173 if (id < landedId) {
2174 let fetcher = state.fetchers.get(key);
2175 invariant(fetcher, `Expected fetcher: ${key}`);
2176 if (fetcher.state === "loading") {
2177 abortFetcher(key);
2178 fetchReloadIds.delete(key);
2179 yeetedKeys.push(key);
2180 }
2181 }
2182 }
2183 markFetchersDone(yeetedKeys);
2184 return yeetedKeys.length > 0;
2185 }
2186 function getBlocker(key, fn) {
2187 let blocker = state.blockers.get(key) || IDLE_BLOCKER;
2188 if (blockerFunctions.get(key) !== fn) {
2189 blockerFunctions.set(key, fn);
2190 }
2191 return blocker;
2192 }
2193 function deleteBlocker(key) {
2194 state.blockers.delete(key);
2195 blockerFunctions.delete(key);
2196 }
2197 function updateBlocker(key, newBlocker) {
2198 let blocker = state.blockers.get(key) || IDLE_BLOCKER;
2199 invariant(
2200 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",
2201 `Invalid blocker state transition: ${blocker.state} -> ${newBlocker.state}`
2202 );
2203 let blockers = new Map(state.blockers);
2204 blockers.set(key, newBlocker);
2205 updateState({ blockers });
2206 }
2207 function shouldBlockNavigation({
2208 currentLocation,
2209 nextLocation,
2210 historyAction
2211 }) {
2212 if (blockerFunctions.size === 0) {
2213 return;
2214 }
2215 if (blockerFunctions.size > 1) {
2216 warning(false, "A router only supports one blocker at a time");
2217 }
2218 let entries = Array.from(blockerFunctions.entries());
2219 let [blockerKey, blockerFunction] = entries[entries.length - 1];
2220 let blocker = state.blockers.get(blockerKey);
2221 if (blocker && blocker.state === "proceeding") {
2222 return;
2223 }
2224 if (blockerFunction({ currentLocation, nextLocation, historyAction })) {
2225 return blockerKey;
2226 }
2227 }
2228 function handleNavigational404(pathname) {
2229 let error = getInternalRouterError(404, { pathname });
2230 let routesToUse = inFlightDataRoutes || dataRoutes;
2231 let { matches, route } = getShortCircuitMatches(routesToUse);
2232 return { notFoundMatches: matches, route, error };
2233 }
2234 function enableScrollRestoration(positions, getPosition, getKey) {
2235 savedScrollPositions = positions;
2236 getScrollPosition = getPosition;
2237 getScrollRestorationKey = getKey || null;
2238 if (!initialScrollRestored && state.navigation === IDLE_NAVIGATION) {
2239 initialScrollRestored = true;
2240 let y = getSavedScrollPosition(state.location, state.matches);
2241 if (y != null) {
2242 updateState({ restoreScrollPosition: y });
2243 }
2244 }
2245 return () => {
2246 savedScrollPositions = null;
2247 getScrollPosition = null;
2248 getScrollRestorationKey = null;
2249 };
2250 }
2251 function getScrollKey(location, matches) {
2252 if (getScrollRestorationKey) {
2253 let key = getScrollRestorationKey(
2254 location,
2255 matches.map((m) => convertRouteMatchToUiMatch(m, state.loaderData))
2256 );
2257 return key || location.key;
2258 }
2259 return location.key;
2260 }
2261 function saveScrollPosition(location, matches) {
2262 if (savedScrollPositions && getScrollPosition) {
2263 let key = getScrollKey(location, matches);
2264 savedScrollPositions[key] = getScrollPosition();
2265 }
2266 }
2267 function getSavedScrollPosition(location, matches) {
2268 if (savedScrollPositions) {
2269 let key = getScrollKey(location, matches);
2270 let y = savedScrollPositions[key];
2271 if (typeof y === "number") {
2272 return y;
2273 }
2274 }
2275 return null;
2276 }
2277 function checkFogOfWar(matches, routesToUse, pathname) {
2278 if (patchRoutesOnNavigationImpl) {
2279 if (!matches) {
2280 let fogMatches = matchRoutesImpl(
2281 routesToUse,
2282 pathname,
2283 basename,
2284 true
2285 );
2286 return { active: true, matches: fogMatches || [] };
2287 } else {
2288 if (Object.keys(matches[0].params).length > 0) {
2289 let partialMatches = matchRoutesImpl(
2290 routesToUse,
2291 pathname,
2292 basename,
2293 true
2294 );
2295 return { active: true, matches: partialMatches };
2296 }
2297 }
2298 }
2299 return { active: false, matches: null };
2300 }
2301 async function discoverRoutes(matches, pathname, signal) {
2302 if (!patchRoutesOnNavigationImpl) {
2303 return { type: "success", matches };
2304 }
2305 let partialMatches = matches;
2306 while (true) {
2307 let isNonHMR = inFlightDataRoutes == null;
2308 let routesToUse = inFlightDataRoutes || dataRoutes;
2309 let localManifest = manifest;
2310 try {
2311 await patchRoutesOnNavigationImpl({
2312 path: pathname,
2313 matches: partialMatches,
2314 patch: (routeId, children) => {
2315 if (signal.aborted) return;
2316 patchRoutesImpl(
2317 routeId,
2318 children,
2319 routesToUse,
2320 localManifest,
2321 mapRouteProperties2
2322 );
2323 }
2324 });
2325 } catch (e) {
2326 return { type: "error", error: e, partialMatches };
2327 } finally {
2328 if (isNonHMR && !signal.aborted) {
2329 dataRoutes = [...dataRoutes];
2330 }
2331 }
2332 if (signal.aborted) {
2333 return { type: "aborted" };
2334 }
2335 let newMatches = matchRoutes(routesToUse, pathname, basename);
2336 if (newMatches) {
2337 return { type: "success", matches: newMatches };
2338 }
2339 let newPartialMatches = matchRoutesImpl(
2340 routesToUse,
2341 pathname,
2342 basename,
2343 true
2344 );
2345 if (!newPartialMatches || partialMatches.length === newPartialMatches.length && partialMatches.every(
2346 (m, i) => m.route.id === newPartialMatches[i].route.id
2347 )) {
2348 return { type: "success", matches: null };
2349 }
2350 partialMatches = newPartialMatches;
2351 }
2352 }
2353 function _internalSetRoutes(newRoutes) {
2354 manifest = {};
2355 inFlightDataRoutes = convertRoutesToDataRoutes(
2356 newRoutes,
2357 mapRouteProperties2,
2358 void 0,
2359 manifest
2360 );
2361 }
2362 function patchRoutes(routeId, children) {
2363 let isNonHMR = inFlightDataRoutes == null;
2364 let routesToUse = inFlightDataRoutes || dataRoutes;
2365 patchRoutesImpl(
2366 routeId,
2367 children,
2368 routesToUse,
2369 manifest,
2370 mapRouteProperties2
2371 );
2372 if (isNonHMR) {
2373 dataRoutes = [...dataRoutes];
2374 updateState({});
2375 }
2376 }
2377 router2 = {
2378 get basename() {
2379 return basename;
2380 },
2381 get future() {
2382 return future;
2383 },
2384 get state() {
2385 return state;
2386 },
2387 get routes() {
2388 return dataRoutes;
2389 },
2390 get window() {
2391 return routerWindow;
2392 },
2393 initialize,
2394 subscribe,
2395 enableScrollRestoration,
2396 navigate,
2397 fetch: fetch2,
2398 revalidate,
2399 // Passthrough to history-aware createHref used by useHref so we get proper
2400 // hash-aware URLs in DOM paths
2401 createHref: (to) => init.history.createHref(to),
2402 encodeLocation: (to) => init.history.encodeLocation(to),
2403 getFetcher,
2404 deleteFetcher: queueFetcherForDeletion,
2405 dispose,
2406 getBlocker,
2407 deleteBlocker,
2408 patchRoutes,
2409 _internalFetchControllers: fetchControllers,
2410 // TODO: Remove setRoutes, it's temporary to avoid dealing with
2411 // updating the tree while validating the update algorithm.
2412 _internalSetRoutes
2413 };
2414 return router2;
2415}
2416function isSubmissionNavigation(opts) {
2417 return opts != null && ("formData" in opts && opts.formData != null || "body" in opts && opts.body !== void 0);
2418}
2419function normalizeTo(location, matches, basename, to, fromRouteId, relative) {
2420 let contextualMatches;
2421 let activeRouteMatch;
2422 if (fromRouteId) {
2423 contextualMatches = [];
2424 for (let match of matches) {
2425 contextualMatches.push(match);
2426 if (match.route.id === fromRouteId) {
2427 activeRouteMatch = match;
2428 break;
2429 }
2430 }
2431 } else {
2432 contextualMatches = matches;
2433 activeRouteMatch = matches[matches.length - 1];
2434 }
2435 let path = resolveTo(
2436 to ? to : ".",
2437 getResolveToMatches(contextualMatches),
2438 stripBasename(location.pathname, basename) || location.pathname,
2439 relative === "path"
2440 );
2441 if (to == null) {
2442 path.search = location.search;
2443 path.hash = location.hash;
2444 }
2445 if ((to == null || to === "" || to === ".") && activeRouteMatch) {
2446 let nakedIndex = hasNakedIndexQuery(path.search);
2447 if (activeRouteMatch.route.index && !nakedIndex) {
2448 path.search = path.search ? path.search.replace(/^\?/, "?index&") : "?index";
2449 } else if (!activeRouteMatch.route.index && nakedIndex) {
2450 let params = new URLSearchParams(path.search);
2451 let indexValues = params.getAll("index");
2452 params.delete("index");
2453 indexValues.filter((v) => v).forEach((v) => params.append("index", v));
2454 let qs = params.toString();
2455 path.search = qs ? `?${qs}` : "";
2456 }
2457 }
2458 if (basename !== "/") {
2459 path.pathname = path.pathname === "/" ? basename : joinPaths([basename, path.pathname]);
2460 }
2461 return createPath(path);
2462}
2463function normalizeNavigateOptions(isFetcher, path, opts) {
2464 if (!opts || !isSubmissionNavigation(opts)) {
2465 return { path };
2466 }
2467 if (opts.formMethod && !isValidMethod(opts.formMethod)) {
2468 return {
2469 path,
2470 error: getInternalRouterError(405, { method: opts.formMethod })
2471 };
2472 }
2473 let getInvalidBodyError = () => ({
2474 path,
2475 error: getInternalRouterError(400, { type: "invalid-body" })
2476 });
2477 let rawFormMethod = opts.formMethod || "get";
2478 let formMethod = rawFormMethod.toUpperCase();
2479 let formAction = stripHashFromPath(path);
2480 if (opts.body !== void 0) {
2481 if (opts.formEncType === "text/plain") {
2482 if (!isMutationMethod(formMethod)) {
2483 return getInvalidBodyError();
2484 }
2485 let text = typeof opts.body === "string" ? opts.body : opts.body instanceof FormData || opts.body instanceof URLSearchParams ? (
2486 // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#plain-text-form-data
2487 Array.from(opts.body.entries()).reduce(
2488 (acc, [name, value]) => `${acc}${name}=${value}
2489`,
2490 ""
2491 )
2492 ) : String(opts.body);
2493 return {
2494 path,
2495 submission: {
2496 formMethod,
2497 formAction,
2498 formEncType: opts.formEncType,
2499 formData: void 0,
2500 json: void 0,
2501 text
2502 }
2503 };
2504 } else if (opts.formEncType === "application/json") {
2505 if (!isMutationMethod(formMethod)) {
2506 return getInvalidBodyError();
2507 }
2508 try {
2509 let json = typeof opts.body === "string" ? JSON.parse(opts.body) : opts.body;
2510 return {
2511 path,
2512 submission: {
2513 formMethod,
2514 formAction,
2515 formEncType: opts.formEncType,
2516 formData: void 0,
2517 json,
2518 text: void 0
2519 }
2520 };
2521 } catch (e) {
2522 return getInvalidBodyError();
2523 }
2524 }
2525 }
2526 invariant(
2527 typeof FormData === "function",
2528 "FormData is not available in this environment"
2529 );
2530 let searchParams;
2531 let formData;
2532 if (opts.formData) {
2533 searchParams = convertFormDataToSearchParams(opts.formData);
2534 formData = opts.formData;
2535 } else if (opts.body instanceof FormData) {
2536 searchParams = convertFormDataToSearchParams(opts.body);
2537 formData = opts.body;
2538 } else if (opts.body instanceof URLSearchParams) {
2539 searchParams = opts.body;
2540 formData = convertSearchParamsToFormData(searchParams);
2541 } else if (opts.body == null) {
2542 searchParams = new URLSearchParams();
2543 formData = new FormData();
2544 } else {
2545 try {
2546 searchParams = new URLSearchParams(opts.body);
2547 formData = convertSearchParamsToFormData(searchParams);
2548 } catch (e) {
2549 return getInvalidBodyError();
2550 }
2551 }
2552 let submission = {
2553 formMethod,
2554 formAction,
2555 formEncType: opts && opts.formEncType || "application/x-www-form-urlencoded",
2556 formData,
2557 json: void 0,
2558 text: void 0
2559 };
2560 if (isMutationMethod(submission.formMethod)) {
2561 return { path, submission };
2562 }
2563 let parsedPath = parsePath(path);
2564 if (isFetcher && parsedPath.search && hasNakedIndexQuery(parsedPath.search)) {
2565 searchParams.append("index", "");
2566 }
2567 parsedPath.search = `?${searchParams}`;
2568 return { path: createPath(parsedPath), submission };
2569}
2570function getLoaderMatchesUntilBoundary(matches, boundaryId, includeBoundary = false) {
2571 let index = matches.findIndex((m) => m.route.id === boundaryId);
2572 if (index >= 0) {
2573 return matches.slice(0, includeBoundary ? index + 1 : index);
2574 }
2575 return matches;
2576}
2577function getMatchesToLoad(history, state, matches, submission, location, initialHydration, isRevalidationRequired, cancelledFetcherLoads, fetchersQueuedForDeletion, fetchLoadMatches, fetchRedirectIds, routesToUse, basename, pendingActionResult) {
2578 let actionResult = pendingActionResult ? isErrorResult(pendingActionResult[1]) ? pendingActionResult[1].error : pendingActionResult[1].data : void 0;
2579 let currentUrl = history.createURL(state.location);
2580 let nextUrl = history.createURL(location);
2581 let boundaryMatches = matches;
2582 if (initialHydration && state.errors) {
2583 boundaryMatches = getLoaderMatchesUntilBoundary(
2584 matches,
2585 Object.keys(state.errors)[0],
2586 true
2587 );
2588 } else if (pendingActionResult && isErrorResult(pendingActionResult[1])) {
2589 boundaryMatches = getLoaderMatchesUntilBoundary(
2590 matches,
2591 pendingActionResult[0]
2592 );
2593 }
2594 let actionStatus = pendingActionResult ? pendingActionResult[1].statusCode : void 0;
2595 let shouldSkipRevalidation = actionStatus && actionStatus >= 400;
2596 let navigationMatches = boundaryMatches.filter((match, index) => {
2597 let { route } = match;
2598 if (route.lazy) {
2599 return true;
2600 }
2601 if (route.loader == null) {
2602 return false;
2603 }
2604 if (initialHydration) {
2605 return shouldLoadRouteOnHydration(route, state.loaderData, state.errors);
2606 }
2607 if (isNewLoader(state.loaderData, state.matches[index], match)) {
2608 return true;
2609 }
2610 let currentRouteMatch = state.matches[index];
2611 let nextRouteMatch = match;
2612 return shouldRevalidateLoader(match, {
2613 currentUrl,
2614 currentParams: currentRouteMatch.params,
2615 nextUrl,
2616 nextParams: nextRouteMatch.params,
2617 ...submission,
2618 actionResult,
2619 actionStatus,
2620 defaultShouldRevalidate: shouldSkipRevalidation ? false : (
2621 // Forced revalidation due to submission, useRevalidator, or X-Remix-Revalidate
2622 isRevalidationRequired || currentUrl.pathname + currentUrl.search === nextUrl.pathname + nextUrl.search || // Search params affect all loaders
2623 currentUrl.search !== nextUrl.search || isNewRouteInstance(currentRouteMatch, nextRouteMatch)
2624 )
2625 });
2626 });
2627 let revalidatingFetchers = [];
2628 fetchLoadMatches.forEach((f, key) => {
2629 if (initialHydration || !matches.some((m) => m.route.id === f.routeId) || fetchersQueuedForDeletion.has(key)) {
2630 return;
2631 }
2632 let fetcherMatches = matchRoutes(routesToUse, f.path, basename);
2633 if (!fetcherMatches) {
2634 revalidatingFetchers.push({
2635 key,
2636 routeId: f.routeId,
2637 path: f.path,
2638 matches: null,
2639 match: null,
2640 controller: null
2641 });
2642 return;
2643 }
2644 let fetcher = state.fetchers.get(key);
2645 let fetcherMatch = getTargetMatch(fetcherMatches, f.path);
2646 let shouldRevalidate = false;
2647 if (fetchRedirectIds.has(key)) {
2648 shouldRevalidate = false;
2649 } else if (cancelledFetcherLoads.has(key)) {
2650 cancelledFetcherLoads.delete(key);
2651 shouldRevalidate = true;
2652 } else if (fetcher && fetcher.state !== "idle" && fetcher.data === void 0) {
2653 shouldRevalidate = isRevalidationRequired;
2654 } else {
2655 shouldRevalidate = shouldRevalidateLoader(fetcherMatch, {
2656 currentUrl,
2657 currentParams: state.matches[state.matches.length - 1].params,
2658 nextUrl,
2659 nextParams: matches[matches.length - 1].params,
2660 ...submission,
2661 actionResult,
2662 actionStatus,
2663 defaultShouldRevalidate: shouldSkipRevalidation ? false : isRevalidationRequired
2664 });
2665 }
2666 if (shouldRevalidate) {
2667 revalidatingFetchers.push({
2668 key,
2669 routeId: f.routeId,
2670 path: f.path,
2671 matches: fetcherMatches,
2672 match: fetcherMatch,
2673 controller: new AbortController()
2674 });
2675 }
2676 });
2677 return [navigationMatches, revalidatingFetchers];
2678}
2679function shouldLoadRouteOnHydration(route, loaderData, errors) {
2680 if (route.lazy) {
2681 return true;
2682 }
2683 if (!route.loader) {
2684 return false;
2685 }
2686 let hasData = loaderData != null && loaderData[route.id] !== void 0;
2687 let hasError = errors != null && errors[route.id] !== void 0;
2688 if (!hasData && hasError) {
2689 return false;
2690 }
2691 if (typeof route.loader === "function" && route.loader.hydrate === true) {
2692 return true;
2693 }
2694 return !hasData && !hasError;
2695}
2696function isNewLoader(currentLoaderData, currentMatch, match) {
2697 let isNew = (
2698 // [a] -> [a, b]
2699 !currentMatch || // [a, b] -> [a, c]
2700 match.route.id !== currentMatch.route.id
2701 );
2702 let isMissingData = !currentLoaderData.hasOwnProperty(match.route.id);
2703 return isNew || isMissingData;
2704}
2705function isNewRouteInstance(currentMatch, match) {
2706 let currentPath = currentMatch.route.path;
2707 return (
2708 // param change for this match, /users/123 -> /users/456
2709 currentMatch.pathname !== match.pathname || // splat param changed, which is not present in match.path
2710 // e.g. /files/images/avatar.jpg -> files/finances.xls
2711 currentPath != null && currentPath.endsWith("*") && currentMatch.params["*"] !== match.params["*"]
2712 );
2713}
2714function shouldRevalidateLoader(loaderMatch, arg) {
2715 if (loaderMatch.route.shouldRevalidate) {
2716 let routeChoice = loaderMatch.route.shouldRevalidate(arg);
2717 if (typeof routeChoice === "boolean") {
2718 return routeChoice;
2719 }
2720 }
2721 return arg.defaultShouldRevalidate;
2722}
2723function patchRoutesImpl(routeId, children, routesToUse, manifest, mapRouteProperties2) {
2724 let childrenToPatch;
2725 if (routeId) {
2726 let route = manifest[routeId];
2727 invariant(
2728 route,
2729 `No route found to patch children into: routeId = ${routeId}`
2730 );
2731 if (!route.children) {
2732 route.children = [];
2733 }
2734 childrenToPatch = route.children;
2735 } else {
2736 childrenToPatch = routesToUse;
2737 }
2738 let uniqueChildren = children.filter(
2739 (newRoute) => !childrenToPatch.some(
2740 (existingRoute) => isSameRoute(newRoute, existingRoute)
2741 )
2742 );
2743 let newRoutes = convertRoutesToDataRoutes(
2744 uniqueChildren,
2745 mapRouteProperties2,
2746 [routeId || "_", "patch", String(childrenToPatch?.length || "0")],
2747 manifest
2748 );
2749 childrenToPatch.push(...newRoutes);
2750}
2751function isSameRoute(newRoute, existingRoute) {
2752 if ("id" in newRoute && "id" in existingRoute && newRoute.id === existingRoute.id) {
2753 return true;
2754 }
2755 if (!(newRoute.index === existingRoute.index && newRoute.path === existingRoute.path && newRoute.caseSensitive === existingRoute.caseSensitive)) {
2756 return false;
2757 }
2758 if ((!newRoute.children || newRoute.children.length === 0) && (!existingRoute.children || existingRoute.children.length === 0)) {
2759 return true;
2760 }
2761 return newRoute.children.every(
2762 (aChild, i) => existingRoute.children?.some((bChild) => isSameRoute(aChild, bChild))
2763 );
2764}
2765async function loadLazyRouteModule(route, mapRouteProperties2, manifest) {
2766 if (!route.lazy) {
2767 return;
2768 }
2769 let lazyRoute = await route.lazy();
2770 if (!route.lazy) {
2771 return;
2772 }
2773 let routeToUpdate = manifest[route.id];
2774 invariant(routeToUpdate, "No route found in manifest");
2775 let routeUpdates = {};
2776 for (let lazyRouteProperty in lazyRoute) {
2777 let staticRouteValue = routeToUpdate[lazyRouteProperty];
2778 let isPropertyStaticallyDefined = staticRouteValue !== void 0 && // This property isn't static since it should always be updated based
2779 // on the route updates
2780 lazyRouteProperty !== "hasErrorBoundary";
2781 warning(
2782 !isPropertyStaticallyDefined,
2783 `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.`
2784 );
2785 if (!isPropertyStaticallyDefined && !immutableRouteKeys.has(lazyRouteProperty)) {
2786 routeUpdates[lazyRouteProperty] = lazyRoute[lazyRouteProperty];
2787 }
2788 }
2789 Object.assign(routeToUpdate, routeUpdates);
2790 Object.assign(routeToUpdate, {
2791 // To keep things framework agnostic, we use the provided `mapRouteProperties`
2792 // function to set the framework-aware properties (`element`/`hasErrorBoundary`)
2793 // since the logic will differ between frameworks.
2794 ...mapRouteProperties2(routeToUpdate),
2795 lazy: void 0
2796 });
2797}
2798async function defaultDataStrategy({
2799 matches
2800}) {
2801 let matchesToLoad = matches.filter((m) => m.shouldLoad);
2802 let results = await Promise.all(matchesToLoad.map((m) => m.resolve()));
2803 return results.reduce(
2804 (acc, result, i) => Object.assign(acc, { [matchesToLoad[i].route.id]: result }),
2805 {}
2806 );
2807}
2808async function callDataStrategyImpl(dataStrategyImpl, type, state, request, matchesToLoad, matches, fetcherKey, manifest, mapRouteProperties2, requestContext) {
2809 let loadRouteDefinitionsPromises = matches.map(
2810 (m) => m.route.lazy ? loadLazyRouteModule(m.route, mapRouteProperties2, manifest) : void 0
2811 );
2812 let dsMatches = matches.map((match, i) => {
2813 let loadRoutePromise = loadRouteDefinitionsPromises[i];
2814 let shouldLoad = matchesToLoad.some((m) => m.route.id === match.route.id);
2815 let resolve = async (handlerOverride) => {
2816 if (handlerOverride && request.method === "GET" && (match.route.lazy || match.route.loader)) {
2817 shouldLoad = true;
2818 }
2819 return shouldLoad ? callLoaderOrAction(
2820 type,
2821 request,
2822 match,
2823 loadRoutePromise,
2824 handlerOverride,
2825 requestContext
2826 ) : Promise.resolve({ type: "data" /* data */, result: void 0 });
2827 };
2828 return {
2829 ...match,
2830 shouldLoad,
2831 resolve
2832 };
2833 });
2834 let results = await dataStrategyImpl({
2835 matches: dsMatches,
2836 request,
2837 params: matches[0].params,
2838 fetcherKey,
2839 context: requestContext
2840 });
2841 try {
2842 await Promise.all(loadRouteDefinitionsPromises);
2843 } catch (e) {
2844 }
2845 return results;
2846}
2847async function callLoaderOrAction(type, request, match, loadRoutePromise, handlerOverride, staticContext) {
2848 let result;
2849 let onReject;
2850 let runHandler = (handler) => {
2851 let reject;
2852 let abortPromise = new Promise((_, r) => reject = r);
2853 onReject = () => reject();
2854 request.signal.addEventListener("abort", onReject);
2855 let actualHandler = (ctx) => {
2856 if (typeof handler !== "function") {
2857 return Promise.reject(
2858 new Error(
2859 `You cannot call the handler for a route which defines a boolean "${type}" [routeId: ${match.route.id}]`
2860 )
2861 );
2862 }
2863 return handler(
2864 {
2865 request,
2866 params: match.params,
2867 context: staticContext
2868 },
2869 ...ctx !== void 0 ? [ctx] : []
2870 );
2871 };
2872 let handlerPromise = (async () => {
2873 try {
2874 let val = await (handlerOverride ? handlerOverride((ctx) => actualHandler(ctx)) : actualHandler());
2875 return { type: "data", result: val };
2876 } catch (e) {
2877 return { type: "error", result: e };
2878 }
2879 })();
2880 return Promise.race([handlerPromise, abortPromise]);
2881 };
2882 try {
2883 let handler = match.route[type];
2884 if (loadRoutePromise) {
2885 if (handler) {
2886 let handlerError;
2887 let [value] = await Promise.all([
2888 // If the handler throws, don't let it immediately bubble out,
2889 // since we need to let the lazy() execution finish so we know if this
2890 // route has a boundary that can handle the error
2891 runHandler(handler).catch((e) => {
2892 handlerError = e;
2893 }),
2894 loadRoutePromise
2895 ]);
2896 if (handlerError !== void 0) {
2897 throw handlerError;
2898 }
2899 result = value;
2900 } else {
2901 await loadRoutePromise;
2902 handler = match.route[type];
2903 if (handler) {
2904 result = await runHandler(handler);
2905 } else if (type === "action") {
2906 let url = new URL(request.url);
2907 let pathname = url.pathname + url.search;
2908 throw getInternalRouterError(405, {
2909 method: request.method,
2910 pathname,
2911 routeId: match.route.id
2912 });
2913 } else {
2914 return { type: "data" /* data */, result: void 0 };
2915 }
2916 }
2917 } else if (!handler) {
2918 let url = new URL(request.url);
2919 let pathname = url.pathname + url.search;
2920 throw getInternalRouterError(404, {
2921 pathname
2922 });
2923 } else {
2924 result = await runHandler(handler);
2925 }
2926 } catch (e) {
2927 return { type: "error" /* error */, result: e };
2928 } finally {
2929 if (onReject) {
2930 request.signal.removeEventListener("abort", onReject);
2931 }
2932 }
2933 return result;
2934}
2935async function convertDataStrategyResultToDataResult(dataStrategyResult) {
2936 let { result, type } = dataStrategyResult;
2937 if (isResponse(result)) {
2938 let data2;
2939 try {
2940 let contentType = result.headers.get("Content-Type");
2941 if (contentType && /\bapplication\/json\b/.test(contentType)) {
2942 if (result.body == null) {
2943 data2 = null;
2944 } else {
2945 data2 = await result.json();
2946 }
2947 } else {
2948 data2 = await result.text();
2949 }
2950 } catch (e) {
2951 return { type: "error" /* error */, error: e };
2952 }
2953 if (type === "error" /* error */) {
2954 return {
2955 type: "error" /* error */,
2956 error: new ErrorResponseImpl(result.status, result.statusText, data2),
2957 statusCode: result.status,
2958 headers: result.headers
2959 };
2960 }
2961 return {
2962 type: "data" /* data */,
2963 data: data2,
2964 statusCode: result.status,
2965 headers: result.headers
2966 };
2967 }
2968 if (type === "error" /* error */) {
2969 if (isDataWithResponseInit(result)) {
2970 if (result.data instanceof Error) {
2971 return {
2972 type: "error" /* error */,
2973 error: result.data,
2974 statusCode: result.init?.status
2975 };
2976 }
2977 result = new ErrorResponseImpl(
2978 result.init?.status || 500,
2979 void 0,
2980 result.data
2981 );
2982 }
2983 return {
2984 type: "error" /* error */,
2985 error: result,
2986 statusCode: isRouteErrorResponse(result) ? result.status : void 0
2987 };
2988 }
2989 if (isDataWithResponseInit(result)) {
2990 return {
2991 type: "data" /* data */,
2992 data: result.data,
2993 statusCode: result.init?.status,
2994 headers: result.init?.headers ? new Headers(result.init.headers) : void 0
2995 };
2996 }
2997 return { type: "data" /* data */, data: result };
2998}
2999function normalizeRelativeRoutingRedirectResponse(response, request, routeId, matches, basename) {
3000 let location = response.headers.get("Location");
3001 invariant(
3002 location,
3003 "Redirects returned/thrown from loaders/actions must have a Location header"
3004 );
3005 if (!ABSOLUTE_URL_REGEX.test(location)) {
3006 let trimmedMatches = matches.slice(
3007 0,
3008 matches.findIndex((m) => m.route.id === routeId) + 1
3009 );
3010 location = normalizeTo(
3011 new URL(request.url),
3012 trimmedMatches,
3013 basename,
3014 location
3015 );
3016 response.headers.set("Location", location);
3017 }
3018 return response;
3019}
3020function normalizeRedirectLocation(location, currentUrl, basename) {
3021 if (ABSOLUTE_URL_REGEX.test(location)) {
3022 let normalizedLocation = location;
3023 let url = normalizedLocation.startsWith("//") ? new URL(currentUrl.protocol + normalizedLocation) : new URL(normalizedLocation);
3024 let isSameBasename = stripBasename(url.pathname, basename) != null;
3025 if (url.origin === currentUrl.origin && isSameBasename) {
3026 return url.pathname + url.search + url.hash;
3027 }
3028 }
3029 return location;
3030}
3031function createClientSideRequest(history, location, signal, submission) {
3032 let url = history.createURL(stripHashFromPath(location)).toString();
3033 let init = { signal };
3034 if (submission && isMutationMethod(submission.formMethod)) {
3035 let { formMethod, formEncType } = submission;
3036 init.method = formMethod.toUpperCase();
3037 if (formEncType === "application/json") {
3038 init.headers = new Headers({ "Content-Type": formEncType });
3039 init.body = JSON.stringify(submission.json);
3040 } else if (formEncType === "text/plain") {
3041 init.body = submission.text;
3042 } else if (formEncType === "application/x-www-form-urlencoded" && submission.formData) {
3043 init.body = convertFormDataToSearchParams(submission.formData);
3044 } else {
3045 init.body = submission.formData;
3046 }
3047 }
3048 return new Request(url, init);
3049}
3050function convertFormDataToSearchParams(formData) {
3051 let searchParams = new URLSearchParams();
3052 for (let [key, value] of formData.entries()) {
3053 searchParams.append(key, typeof value === "string" ? value : value.name);
3054 }
3055 return searchParams;
3056}
3057function convertSearchParamsToFormData(searchParams) {
3058 let formData = new FormData();
3059 for (let [key, value] of searchParams.entries()) {
3060 formData.append(key, value);
3061 }
3062 return formData;
3063}
3064function processRouteLoaderData(matches, results, pendingActionResult, isStaticHandler = false, skipLoaderErrorBubbling = false) {
3065 let loaderData = {};
3066 let errors = null;
3067 let statusCode;
3068 let foundError = false;
3069 let loaderHeaders = {};
3070 let pendingError = pendingActionResult && isErrorResult(pendingActionResult[1]) ? pendingActionResult[1].error : void 0;
3071 matches.forEach((match) => {
3072 if (!(match.route.id in results)) {
3073 return;
3074 }
3075 let id = match.route.id;
3076 let result = results[id];
3077 invariant(
3078 !isRedirectResult(result),
3079 "Cannot handle redirect results in processLoaderData"
3080 );
3081 if (isErrorResult(result)) {
3082 let error = result.error;
3083 if (pendingError !== void 0) {
3084 error = pendingError;
3085 pendingError = void 0;
3086 }
3087 errors = errors || {};
3088 if (skipLoaderErrorBubbling) {
3089 errors[id] = error;
3090 } else {
3091 let boundaryMatch = findNearestBoundary(matches, id);
3092 if (errors[boundaryMatch.route.id] == null) {
3093 errors[boundaryMatch.route.id] = error;
3094 }
3095 }
3096 if (!isStaticHandler) {
3097 loaderData[id] = ResetLoaderDataSymbol;
3098 }
3099 if (!foundError) {
3100 foundError = true;
3101 statusCode = isRouteErrorResponse(result.error) ? result.error.status : 500;
3102 }
3103 if (result.headers) {
3104 loaderHeaders[id] = result.headers;
3105 }
3106 } else {
3107 loaderData[id] = result.data;
3108 if (result.statusCode && result.statusCode !== 200 && !foundError) {
3109 statusCode = result.statusCode;
3110 }
3111 if (result.headers) {
3112 loaderHeaders[id] = result.headers;
3113 }
3114 }
3115 });
3116 if (pendingError !== void 0 && pendingActionResult) {
3117 errors = { [pendingActionResult[0]]: pendingError };
3118 loaderData[pendingActionResult[0]] = void 0;
3119 }
3120 return {
3121 loaderData,
3122 errors,
3123 statusCode: statusCode || 200,
3124 loaderHeaders
3125 };
3126}
3127function processLoaderData(state, matches, results, pendingActionResult, revalidatingFetchers, fetcherResults) {
3128 let { loaderData, errors } = processRouteLoaderData(
3129 matches,
3130 results,
3131 pendingActionResult
3132 );
3133 revalidatingFetchers.forEach((rf) => {
3134 let { key, match, controller } = rf;
3135 let result = fetcherResults[key];
3136 invariant(result, "Did not find corresponding fetcher result");
3137 if (controller && controller.signal.aborted) {
3138 return;
3139 } else if (isErrorResult(result)) {
3140 let boundaryMatch = findNearestBoundary(state.matches, match?.route.id);
3141 if (!(errors && errors[boundaryMatch.route.id])) {
3142 errors = {
3143 ...errors,
3144 [boundaryMatch.route.id]: result.error
3145 };
3146 }
3147 state.fetchers.delete(key);
3148 } else if (isRedirectResult(result)) {
3149 invariant(false, "Unhandled fetcher revalidation redirect");
3150 } else {
3151 let doneFetcher = getDoneFetcher(result.data);
3152 state.fetchers.set(key, doneFetcher);
3153 }
3154 });
3155 return { loaderData, errors };
3156}
3157function mergeLoaderData(loaderData, newLoaderData, matches, errors) {
3158 let mergedLoaderData = Object.entries(newLoaderData).filter(([, v]) => v !== ResetLoaderDataSymbol).reduce((merged, [k, v]) => {
3159 merged[k] = v;
3160 return merged;
3161 }, {});
3162 for (let match of matches) {
3163 let id = match.route.id;
3164 if (!newLoaderData.hasOwnProperty(id) && loaderData.hasOwnProperty(id) && match.route.loader) {
3165 mergedLoaderData[id] = loaderData[id];
3166 }
3167 if (errors && errors.hasOwnProperty(id)) {
3168 break;
3169 }
3170 }
3171 return mergedLoaderData;
3172}
3173function getActionDataForCommit(pendingActionResult) {
3174 if (!pendingActionResult) {
3175 return {};
3176 }
3177 return isErrorResult(pendingActionResult[1]) ? {
3178 // Clear out prior actionData on errors
3179 actionData: {}
3180 } : {
3181 actionData: {
3182 [pendingActionResult[0]]: pendingActionResult[1].data
3183 }
3184 };
3185}
3186function findNearestBoundary(matches, routeId) {
3187 let eligibleMatches = routeId ? matches.slice(0, matches.findIndex((m) => m.route.id === routeId) + 1) : [...matches];
3188 return eligibleMatches.reverse().find((m) => m.route.hasErrorBoundary === true) || matches[0];
3189}
3190function getShortCircuitMatches(routes) {
3191 let route = routes.length === 1 ? routes[0] : routes.find((r) => r.index || !r.path || r.path === "/") || {
3192 id: `__shim-error-route__`
3193 };
3194 return {
3195 matches: [
3196 {
3197 params: {},
3198 pathname: "",
3199 pathnameBase: "",
3200 route
3201 }
3202 ],
3203 route
3204 };
3205}
3206function getInternalRouterError(status, {
3207 pathname,
3208 routeId,
3209 method,
3210 type,
3211 message
3212} = {}) {
3213 let statusText = "Unknown Server Error";
3214 let errorMessage = "Unknown @remix-run/router error";
3215 if (status === 400) {
3216 statusText = "Bad Request";
3217 if (method && pathname && routeId) {
3218 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.`;
3219 } else if (type === "invalid-body") {
3220 errorMessage = "Unable to encode submission body";
3221 }
3222 } else if (status === 403) {
3223 statusText = "Forbidden";
3224 errorMessage = `Route "${routeId}" does not match URL "${pathname}"`;
3225 } else if (status === 404) {
3226 statusText = "Not Found";
3227 errorMessage = `No route matches URL "${pathname}"`;
3228 } else if (status === 405) {
3229 statusText = "Method Not Allowed";
3230 if (method && pathname && routeId) {
3231 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.`;
3232 } else if (method) {
3233 errorMessage = `Invalid request method "${method.toUpperCase()}"`;
3234 }
3235 }
3236 return new ErrorResponseImpl(
3237 status || 500,
3238 statusText,
3239 new Error(errorMessage),
3240 true
3241 );
3242}
3243function findRedirect(results) {
3244 let entries = Object.entries(results);
3245 for (let i = entries.length - 1; i >= 0; i--) {
3246 let [key, result] = entries[i];
3247 if (isRedirectResult(result)) {
3248 return { key, result };
3249 }
3250 }
3251}
3252function stripHashFromPath(path) {
3253 let parsedPath = typeof path === "string" ? parsePath(path) : path;
3254 return createPath({ ...parsedPath, hash: "" });
3255}
3256function isHashChangeOnly(a, b) {
3257 if (a.pathname !== b.pathname || a.search !== b.search) {
3258 return false;
3259 }
3260 if (a.hash === "") {
3261 return b.hash !== "";
3262 } else if (a.hash === b.hash) {
3263 return true;
3264 } else if (b.hash !== "") {
3265 return true;
3266 }
3267 return false;
3268}
3269function isRedirectDataStrategyResult(result) {
3270 return isResponse(result.result) && redirectStatusCodes.has(result.result.status);
3271}
3272function isErrorResult(result) {
3273 return result.type === "error" /* error */;
3274}
3275function isRedirectResult(result) {
3276 return (result && result.type) === "redirect" /* redirect */;
3277}
3278function isDataWithResponseInit(value) {
3279 return typeof value === "object" && value != null && "type" in value && "data" in value && "init" in value && value.type === "DataWithResponseInit";
3280}
3281function isResponse(value) {
3282 return value != null && typeof value.status === "number" && typeof value.statusText === "string" && typeof value.headers === "object" && typeof value.body !== "undefined";
3283}
3284function isValidMethod(method) {
3285 return validRequestMethods.has(method.toUpperCase());
3286}
3287function isMutationMethod(method) {
3288 return validMutationMethods.has(method.toUpperCase());
3289}
3290function hasNakedIndexQuery(search) {
3291 return new URLSearchParams(search).getAll("index").some((v) => v === "");
3292}
3293function getTargetMatch(matches, location) {
3294 let search = typeof location === "string" ? parsePath(location).search : location.search;
3295 if (matches[matches.length - 1].route.index && hasNakedIndexQuery(search || "")) {
3296 return matches[matches.length - 1];
3297 }
3298 let pathMatches = getPathContributingMatches(matches);
3299 return pathMatches[pathMatches.length - 1];
3300}
3301function getSubmissionFromNavigation(navigation) {
3302 let { formMethod, formAction, formEncType, text, formData, json } = navigation;
3303 if (!formMethod || !formAction || !formEncType) {
3304 return;
3305 }
3306 if (text != null) {
3307 return {
3308 formMethod,
3309 formAction,
3310 formEncType,
3311 formData: void 0,
3312 json: void 0,
3313 text
3314 };
3315 } else if (formData != null) {
3316 return {
3317 formMethod,
3318 formAction,
3319 formEncType,
3320 formData,
3321 json: void 0,
3322 text: void 0
3323 };
3324 } else if (json !== void 0) {
3325 return {
3326 formMethod,
3327 formAction,
3328 formEncType,
3329 formData: void 0,
3330 json,
3331 text: void 0
3332 };
3333 }
3334}
3335function getLoadingNavigation(location, submission) {
3336 if (submission) {
3337 let navigation = {
3338 state: "loading",
3339 location,
3340 formMethod: submission.formMethod,
3341 formAction: submission.formAction,
3342 formEncType: submission.formEncType,
3343 formData: submission.formData,
3344 json: submission.json,
3345 text: submission.text
3346 };
3347 return navigation;
3348 } else {
3349 let navigation = {
3350 state: "loading",
3351 location,
3352 formMethod: void 0,
3353 formAction: void 0,
3354 formEncType: void 0,
3355 formData: void 0,
3356 json: void 0,
3357 text: void 0
3358 };
3359 return navigation;
3360 }
3361}
3362function getSubmittingNavigation(location, submission) {
3363 let navigation = {
3364 state: "submitting",
3365 location,
3366 formMethod: submission.formMethod,
3367 formAction: submission.formAction,
3368 formEncType: submission.formEncType,
3369 formData: submission.formData,
3370 json: submission.json,
3371 text: submission.text
3372 };
3373 return navigation;
3374}
3375function getLoadingFetcher(submission, data2) {
3376 if (submission) {
3377 let fetcher = {
3378 state: "loading",
3379 formMethod: submission.formMethod,
3380 formAction: submission.formAction,
3381 formEncType: submission.formEncType,
3382 formData: submission.formData,
3383 json: submission.json,
3384 text: submission.text,
3385 data: data2
3386 };
3387 return fetcher;
3388 } else {
3389 let fetcher = {
3390 state: "loading",
3391 formMethod: void 0,
3392 formAction: void 0,
3393 formEncType: void 0,
3394 formData: void 0,
3395 json: void 0,
3396 text: void 0,
3397 data: data2
3398 };
3399 return fetcher;
3400 }
3401}
3402function getSubmittingFetcher(submission, existingFetcher) {
3403 let fetcher = {
3404 state: "submitting",
3405 formMethod: submission.formMethod,
3406 formAction: submission.formAction,
3407 formEncType: submission.formEncType,
3408 formData: submission.formData,
3409 json: submission.json,
3410 text: submission.text,
3411 data: existingFetcher ? existingFetcher.data : void 0
3412 };
3413 return fetcher;
3414}
3415function getDoneFetcher(data2) {
3416 let fetcher = {
3417 state: "idle",
3418 formMethod: void 0,
3419 formAction: void 0,
3420 formEncType: void 0,
3421 formData: void 0,
3422 json: void 0,
3423 text: void 0,
3424 data: data2
3425 };
3426 return fetcher;
3427}
3428function restoreAppliedTransitions(_window, transitions) {
3429 try {
3430 let sessionPositions = _window.sessionStorage.getItem(
3431 TRANSITIONS_STORAGE_KEY
3432 );
3433 if (sessionPositions) {
3434 let json = JSON.parse(sessionPositions);
3435 for (let [k, v] of Object.entries(json || {})) {
3436 if (v && Array.isArray(v)) {
3437 transitions.set(k, new Set(v || []));
3438 }
3439 }
3440 }
3441 } catch (e) {
3442 }
3443}
3444function persistAppliedTransitions(_window, transitions) {
3445 if (transitions.size > 0) {
3446 let json = {};
3447 for (let [k, v] of transitions) {
3448 json[k] = [...v];
3449 }
3450 try {
3451 _window.sessionStorage.setItem(
3452 TRANSITIONS_STORAGE_KEY,
3453 JSON.stringify(json)
3454 );
3455 } catch (error) {
3456 warning(
3457 false,
3458 `Failed to save applied view transitions in sessionStorage (${error}).`
3459 );
3460 }
3461 }
3462}
3463function createDeferred() {
3464 let resolve;
3465 let reject;
3466 let promise = new Promise((res, rej) => {
3467 resolve = async (val) => {
3468 res(val);
3469 try {
3470 await promise;
3471 } catch (e) {
3472 }
3473 };
3474 reject = async (error) => {
3475 rej(error);
3476 try {
3477 await promise;
3478 } catch (e) {
3479 }
3480 };
3481 });
3482 return {
3483 promise,
3484 //@ts-ignore
3485 resolve,
3486 //@ts-ignore
3487 reject
3488 };
3489}
3490
3491// lib/components.tsx
3492var React3 = __toESM(require("react"));
3493
3494// lib/context.ts
3495var React = __toESM(require("react"));
3496var DataRouterContext = React.createContext(null);
3497DataRouterContext.displayName = "DataRouter";
3498var DataRouterStateContext = React.createContext(null);
3499DataRouterStateContext.displayName = "DataRouterState";
3500var ViewTransitionContext = React.createContext({
3501 isTransitioning: false
3502});
3503ViewTransitionContext.displayName = "ViewTransition";
3504var FetchersContext = React.createContext(
3505 /* @__PURE__ */ new Map()
3506);
3507FetchersContext.displayName = "Fetchers";
3508var AwaitContext = React.createContext(null);
3509AwaitContext.displayName = "Await";
3510var NavigationContext = React.createContext(
3511 null
3512);
3513NavigationContext.displayName = "Navigation";
3514var LocationContext = React.createContext(
3515 null
3516);
3517LocationContext.displayName = "Location";
3518var RouteContext = React.createContext({
3519 outlet: null,
3520 matches: [],
3521 isDataRoute: false
3522});
3523RouteContext.displayName = "Route";
3524var RouteErrorContext = React.createContext(null);
3525RouteErrorContext.displayName = "RouteError";
3526
3527// lib/hooks.tsx
3528var React2 = __toESM(require("react"));
3529var ENABLE_DEV_WARNINGS = true;
3530function useInRouterContext() {
3531 return React2.useContext(LocationContext) != null;
3532}
3533function useLocation() {
3534 invariant(
3535 useInRouterContext(),
3536 // TODO: This error is probably because they somehow have 2 versions of the
3537 // router loaded. We can help them understand how to avoid that.
3538 `useLocation() may be used only in the context of a <Router> component.`
3539 );
3540 return React2.useContext(LocationContext).location;
3541}
3542var OutletContext = React2.createContext(null);
3543function useRoutesImpl(routes, locationArg, dataRouterState, future) {
3544 invariant(
3545 useInRouterContext(),
3546 // TODO: This error is probably because they somehow have 2 versions of the
3547 // router loaded. We can help them understand how to avoid that.
3548 `useRoutes() may be used only in the context of a <Router> component.`
3549 );
3550 let { navigator: navigator2 } = React2.useContext(NavigationContext);
3551 let { matches: parentMatches } = React2.useContext(RouteContext);
3552 let routeMatch = parentMatches[parentMatches.length - 1];
3553 let parentParams = routeMatch ? routeMatch.params : {};
3554 let parentPathname = routeMatch ? routeMatch.pathname : "/";
3555 let parentPathnameBase = routeMatch ? routeMatch.pathnameBase : "/";
3556 let parentRoute = routeMatch && routeMatch.route;
3557 if (ENABLE_DEV_WARNINGS) {
3558 let parentPath = parentRoute && parentRoute.path || "";
3559 warningOnce(
3560 parentPathname,
3561 !parentRoute || parentPath.endsWith("*") || parentPath.endsWith("*?"),
3562 `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.
3563
3564Please change the parent <Route path="${parentPath}"> to <Route path="${parentPath === "/" ? "*" : `${parentPath}/*`}">.`
3565 );
3566 }
3567 let locationFromContext = useLocation();
3568 let location;
3569 if (locationArg) {
3570 let parsedLocationArg = typeof locationArg === "string" ? parsePath(locationArg) : locationArg;
3571 invariant(
3572 parentPathnameBase === "/" || parsedLocationArg.pathname?.startsWith(parentPathnameBase),
3573 `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.`
3574 );
3575 location = parsedLocationArg;
3576 } else {
3577 location = locationFromContext;
3578 }
3579 let pathname = location.pathname || "/";
3580 let remainingPathname = pathname;
3581 if (parentPathnameBase !== "/") {
3582 let parentSegments = parentPathnameBase.replace(/^\//, "").split("/");
3583 let segments = pathname.replace(/^\//, "").split("/");
3584 remainingPathname = "/" + segments.slice(parentSegments.length).join("/");
3585 }
3586 let matches = matchRoutes(routes, { pathname: remainingPathname });
3587 if (ENABLE_DEV_WARNINGS) {
3588 warning(
3589 parentRoute || matches != null,
3590 `No routes matched location "${location.pathname}${location.search}${location.hash}" `
3591 );
3592 warning(
3593 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,
3594 `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.`
3595 );
3596 }
3597 let renderedMatches = _renderMatches(
3598 matches && matches.map(
3599 (match) => Object.assign({}, match, {
3600 params: Object.assign({}, parentParams, match.params),
3601 pathname: joinPaths([
3602 parentPathnameBase,
3603 // Re-encode pathnames that were decoded inside matchRoutes
3604 navigator2.encodeLocation ? navigator2.encodeLocation(match.pathname).pathname : match.pathname
3605 ]),
3606 pathnameBase: match.pathnameBase === "/" ? parentPathnameBase : joinPaths([
3607 parentPathnameBase,
3608 // Re-encode pathnames that were decoded inside matchRoutes
3609 navigator2.encodeLocation ? navigator2.encodeLocation(match.pathnameBase).pathname : match.pathnameBase
3610 ])
3611 })
3612 ),
3613 parentMatches,
3614 dataRouterState,
3615 future
3616 );
3617 if (locationArg && renderedMatches) {
3618 return /* @__PURE__ */ React2.createElement(
3619 LocationContext.Provider,
3620 {
3621 value: {
3622 location: {
3623 pathname: "/",
3624 search: "",
3625 hash: "",
3626 state: null,
3627 key: "default",
3628 ...location
3629 },
3630 navigationType: "POP" /* Pop */
3631 }
3632 },
3633 renderedMatches
3634 );
3635 }
3636 return renderedMatches;
3637}
3638function DefaultErrorComponent() {
3639 let error = useRouteError();
3640 let message = isRouteErrorResponse(error) ? `${error.status} ${error.statusText}` : error instanceof Error ? error.message : JSON.stringify(error);
3641 let stack = error instanceof Error ? error.stack : null;
3642 let lightgrey = "rgba(200,200,200, 0.5)";
3643 let preStyles = { padding: "0.5rem", backgroundColor: lightgrey };
3644 let codeStyles = { padding: "2px 4px", backgroundColor: lightgrey };
3645 let devInfo = null;
3646 if (ENABLE_DEV_WARNINGS) {
3647 console.error(
3648 "Error handled by React Router default ErrorBoundary:",
3649 error
3650 );
3651 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."));
3652 }
3653 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);
3654}
3655var defaultErrorElement = /* @__PURE__ */ React2.createElement(DefaultErrorComponent, null);
3656var RenderErrorBoundary = class extends React2.Component {
3657 constructor(props) {
3658 super(props);
3659 this.state = {
3660 location: props.location,
3661 revalidation: props.revalidation,
3662 error: props.error
3663 };
3664 }
3665 static getDerivedStateFromError(error) {
3666 return { error };
3667 }
3668 static getDerivedStateFromProps(props, state) {
3669 if (state.location !== props.location || state.revalidation !== "idle" && props.revalidation === "idle") {
3670 return {
3671 error: props.error,
3672 location: props.location,
3673 revalidation: props.revalidation
3674 };
3675 }
3676 return {
3677 error: props.error !== void 0 ? props.error : state.error,
3678 location: state.location,
3679 revalidation: props.revalidation || state.revalidation
3680 };
3681 }
3682 componentDidCatch(error, errorInfo) {
3683 console.error(
3684 "React Router caught the following error during render",
3685 error,
3686 errorInfo
3687 );
3688 }
3689 render() {
3690 return this.state.error !== void 0 ? /* @__PURE__ */ React2.createElement(RouteContext.Provider, { value: this.props.routeContext }, /* @__PURE__ */ React2.createElement(
3691 RouteErrorContext.Provider,
3692 {
3693 value: this.state.error,
3694 children: this.props.component
3695 }
3696 )) : this.props.children;
3697 }
3698};
3699function RenderedRoute({ routeContext, match, children }) {
3700 let dataRouterContext = React2.useContext(DataRouterContext);
3701 if (dataRouterContext && dataRouterContext.static && dataRouterContext.staticContext && (match.route.errorElement || match.route.ErrorBoundary)) {
3702 dataRouterContext.staticContext._deepestRenderedBoundaryId = match.route.id;
3703 }
3704 return /* @__PURE__ */ React2.createElement(RouteContext.Provider, { value: routeContext }, children);
3705}
3706function _renderMatches(matches, parentMatches = [], dataRouterState = null, future = null) {
3707 if (matches == null) {
3708 if (!dataRouterState) {
3709 return null;
3710 }
3711 if (dataRouterState.errors) {
3712 matches = dataRouterState.matches;
3713 } else if (parentMatches.length === 0 && !dataRouterState.initialized && dataRouterState.matches.length > 0) {
3714 matches = dataRouterState.matches;
3715 } else {
3716 return null;
3717 }
3718 }
3719 let renderedMatches = matches;
3720 let errors = dataRouterState?.errors;
3721 if (errors != null) {
3722 let errorIndex = renderedMatches.findIndex(
3723 (m) => m.route.id && errors?.[m.route.id] !== void 0
3724 );
3725 invariant(
3726 errorIndex >= 0,
3727 `Could not find a matching route for errors on route IDs: ${Object.keys(
3728 errors
3729 ).join(",")}`
3730 );
3731 renderedMatches = renderedMatches.slice(
3732 0,
3733 Math.min(renderedMatches.length, errorIndex + 1)
3734 );
3735 }
3736 let renderFallback = false;
3737 let fallbackIndex = -1;
3738 if (dataRouterState) {
3739 for (let i = 0; i < renderedMatches.length; i++) {
3740 let match = renderedMatches[i];
3741 if (match.route.HydrateFallback || match.route.hydrateFallbackElement) {
3742 fallbackIndex = i;
3743 }
3744 if (match.route.id) {
3745 let { loaderData, errors: errors2 } = dataRouterState;
3746 let needsToRunLoader = match.route.loader && !loaderData.hasOwnProperty(match.route.id) && (!errors2 || errors2[match.route.id] === void 0);
3747 if (match.route.lazy || needsToRunLoader) {
3748 renderFallback = true;
3749 if (fallbackIndex >= 0) {
3750 renderedMatches = renderedMatches.slice(0, fallbackIndex + 1);
3751 } else {
3752 renderedMatches = [renderedMatches[0]];
3753 }
3754 break;
3755 }
3756 }
3757 }
3758 }
3759 return renderedMatches.reduceRight((outlet, match, index) => {
3760 let error;
3761 let shouldRenderHydrateFallback = false;
3762 let errorElement = null;
3763 let hydrateFallbackElement = null;
3764 if (dataRouterState) {
3765 error = errors && match.route.id ? errors[match.route.id] : void 0;
3766 errorElement = match.route.errorElement || defaultErrorElement;
3767 if (renderFallback) {
3768 if (fallbackIndex < 0 && index === 0) {
3769 warningOnce(
3770 "route-fallback",
3771 false,
3772 "No `HydrateFallback` element provided to render during initial hydration"
3773 );
3774 shouldRenderHydrateFallback = true;
3775 hydrateFallbackElement = null;
3776 } else if (fallbackIndex === index) {
3777 shouldRenderHydrateFallback = true;
3778 hydrateFallbackElement = match.route.hydrateFallbackElement || null;
3779 }
3780 }
3781 }
3782 let matches2 = parentMatches.concat(renderedMatches.slice(0, index + 1));
3783 let getChildren = () => {
3784 let children;
3785 if (error) {
3786 children = errorElement;
3787 } else if (shouldRenderHydrateFallback) {
3788 children = hydrateFallbackElement;
3789 } else if (match.route.Component) {
3790 children = /* @__PURE__ */ React2.createElement(match.route.Component, null);
3791 } else if (match.route.element) {
3792 children = match.route.element;
3793 } else {
3794 children = outlet;
3795 }
3796 return /* @__PURE__ */ React2.createElement(
3797 RenderedRoute,
3798 {
3799 match,
3800 routeContext: {
3801 outlet,
3802 matches: matches2,
3803 isDataRoute: dataRouterState != null
3804 },
3805 children
3806 }
3807 );
3808 };
3809 return dataRouterState && (match.route.ErrorBoundary || match.route.errorElement || index === 0) ? /* @__PURE__ */ React2.createElement(
3810 RenderErrorBoundary,
3811 {
3812 location: dataRouterState.location,
3813 revalidation: dataRouterState.revalidation,
3814 component: errorElement,
3815 error,
3816 children: getChildren(),
3817 routeContext: { outlet: null, matches: matches2, isDataRoute: true }
3818 }
3819 ) : getChildren();
3820 }, null);
3821}
3822function getDataRouterConsoleError(hookName) {
3823 return `${hookName} must be used within a data router. See https://reactrouter.com/en/main/routers/picking-a-router.`;
3824}
3825function useDataRouterState(hookName) {
3826 let state = React2.useContext(DataRouterStateContext);
3827 invariant(state, getDataRouterConsoleError(hookName));
3828 return state;
3829}
3830function useRouteContext(hookName) {
3831 let route = React2.useContext(RouteContext);
3832 invariant(route, getDataRouterConsoleError(hookName));
3833 return route;
3834}
3835function useCurrentRouteId(hookName) {
3836 let route = useRouteContext(hookName);
3837 let thisRoute = route.matches[route.matches.length - 1];
3838 invariant(
3839 thisRoute.route.id,
3840 `${hookName} can only be used on routes that contain a unique "id"`
3841 );
3842 return thisRoute.route.id;
3843}
3844function useRouteError() {
3845 let error = React2.useContext(RouteErrorContext);
3846 let state = useDataRouterState("useRouteError" /* UseRouteError */);
3847 let routeId = useCurrentRouteId("useRouteError" /* UseRouteError */);
3848 if (error !== void 0) {
3849 return error;
3850 }
3851 return state.errors?.[routeId];
3852}
3853var alreadyWarned = {};
3854function warningOnce(key, cond, message) {
3855 if (!cond && !alreadyWarned[key]) {
3856 alreadyWarned[key] = true;
3857 warning(false, message);
3858 }
3859}
3860
3861// lib/server-runtime/warnings.ts
3862var alreadyWarned2 = {};
3863function warnOnce(condition, message) {
3864 if (!condition && !alreadyWarned2[message]) {
3865 alreadyWarned2[message] = true;
3866 console.warn(message);
3867 }
3868}
3869
3870// lib/components.tsx
3871var ENABLE_DEV_WARNINGS2 = true;
3872function mapRouteProperties(route) {
3873 let updates = {
3874 // Note: this check also occurs in createRoutesFromChildren so update
3875 // there if you change this -- please and thank you!
3876 hasErrorBoundary: route.hasErrorBoundary || route.ErrorBoundary != null || route.errorElement != null
3877 };
3878 if (route.Component) {
3879 if (ENABLE_DEV_WARNINGS2) {
3880 if (route.element) {
3881 warning(
3882 false,
3883 "You should not include both `Component` and `element` on your route - `Component` will be used."
3884 );
3885 }
3886 }
3887 Object.assign(updates, {
3888 element: React3.createElement(route.Component),
3889 Component: void 0
3890 });
3891 }
3892 if (route.HydrateFallback) {
3893 if (ENABLE_DEV_WARNINGS2) {
3894 if (route.hydrateFallbackElement) {
3895 warning(
3896 false,
3897 "You should not include both `HydrateFallback` and `hydrateFallbackElement` on your route - `HydrateFallback` will be used."
3898 );
3899 }
3900 }
3901 Object.assign(updates, {
3902 hydrateFallbackElement: React3.createElement(route.HydrateFallback),
3903 HydrateFallback: void 0
3904 });
3905 }
3906 if (route.ErrorBoundary) {
3907 if (ENABLE_DEV_WARNINGS2) {
3908 if (route.errorElement) {
3909 warning(
3910 false,
3911 "You should not include both `ErrorBoundary` and `errorElement` on your route - `ErrorBoundary` will be used."
3912 );
3913 }
3914 }
3915 Object.assign(updates, {
3916 errorElement: React3.createElement(route.ErrorBoundary),
3917 ErrorBoundary: void 0
3918 });
3919 }
3920 return updates;
3921}
3922var Deferred = class {
3923 constructor() {
3924 this.status = "pending";
3925 this.promise = new Promise((resolve, reject) => {
3926 this.resolve = (value) => {
3927 if (this.status === "pending") {
3928 this.status = "resolved";
3929 resolve(value);
3930 }
3931 };
3932 this.reject = (reason) => {
3933 if (this.status === "pending") {
3934 this.status = "rejected";
3935 reject(reason);
3936 }
3937 };
3938 });
3939 }
3940};
3941function RouterProvider({
3942 router: router2,
3943 flushSync: reactDomFlushSyncImpl
3944}) {
3945 let [state, setStateImpl] = React3.useState(router2.state);
3946 let [pendingState, setPendingState] = React3.useState();
3947 let [vtContext, setVtContext] = React3.useState({
3948 isTransitioning: false
3949 });
3950 let [renderDfd, setRenderDfd] = React3.useState();
3951 let [transition, setTransition] = React3.useState();
3952 let [interruption, setInterruption] = React3.useState();
3953 let fetcherData = React3.useRef(/* @__PURE__ */ new Map());
3954 let setState = React3.useCallback(
3955 (newState, { deletedFetchers, flushSync: flushSync2, viewTransitionOpts }) => {
3956 deletedFetchers.forEach((key) => fetcherData.current.delete(key));
3957 newState.fetchers.forEach((fetcher, key) => {
3958 if (fetcher.data !== void 0) {
3959 fetcherData.current.set(key, fetcher.data);
3960 }
3961 });
3962 warnOnce(
3963 flushSync2 === false || reactDomFlushSyncImpl != null,
3964 '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.'
3965 );
3966 let isViewTransitionAvailable = router2.window != null && router2.window.document != null && typeof router2.window.document.startViewTransition === "function";
3967 warnOnce(
3968 viewTransitionOpts == null || isViewTransitionAvailable,
3969 "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."
3970 );
3971 if (!viewTransitionOpts || !isViewTransitionAvailable) {
3972 if (reactDomFlushSyncImpl && flushSync2) {
3973 reactDomFlushSyncImpl(() => setStateImpl(newState));
3974 } else {
3975 React3.startTransition(() => setStateImpl(newState));
3976 }
3977 return;
3978 }
3979 if (reactDomFlushSyncImpl && flushSync2) {
3980 reactDomFlushSyncImpl(() => {
3981 if (transition) {
3982 renderDfd && renderDfd.resolve();
3983 transition.skipTransition();
3984 }
3985 setVtContext({
3986 isTransitioning: true,
3987 flushSync: true,
3988 currentLocation: viewTransitionOpts.currentLocation,
3989 nextLocation: viewTransitionOpts.nextLocation
3990 });
3991 });
3992 let t = router2.window.document.startViewTransition(() => {
3993 reactDomFlushSyncImpl(() => setStateImpl(newState));
3994 });
3995 t.finished.finally(() => {
3996 reactDomFlushSyncImpl(() => {
3997 setRenderDfd(void 0);
3998 setTransition(void 0);
3999 setPendingState(void 0);
4000 setVtContext({ isTransitioning: false });
4001 });
4002 });
4003 reactDomFlushSyncImpl(() => setTransition(t));
4004 return;
4005 }
4006 if (transition) {
4007 renderDfd && renderDfd.resolve();
4008 transition.skipTransition();
4009 setInterruption({
4010 state: newState,
4011 currentLocation: viewTransitionOpts.currentLocation,
4012 nextLocation: viewTransitionOpts.nextLocation
4013 });
4014 } else {
4015 setPendingState(newState);
4016 setVtContext({
4017 isTransitioning: true,
4018 flushSync: false,
4019 currentLocation: viewTransitionOpts.currentLocation,
4020 nextLocation: viewTransitionOpts.nextLocation
4021 });
4022 }
4023 },
4024 [router2.window, reactDomFlushSyncImpl, transition, renderDfd]
4025 );
4026 React3.useLayoutEffect(() => router2.subscribe(setState), [router2, setState]);
4027 React3.useEffect(() => {
4028 if (vtContext.isTransitioning && !vtContext.flushSync) {
4029 setRenderDfd(new Deferred());
4030 }
4031 }, [vtContext]);
4032 React3.useEffect(() => {
4033 if (renderDfd && pendingState && router2.window) {
4034 let newState = pendingState;
4035 let renderPromise = renderDfd.promise;
4036 let transition2 = router2.window.document.startViewTransition(async () => {
4037 React3.startTransition(() => setStateImpl(newState));
4038 await renderPromise;
4039 });
4040 transition2.finished.finally(() => {
4041 setRenderDfd(void 0);
4042 setTransition(void 0);
4043 setPendingState(void 0);
4044 setVtContext({ isTransitioning: false });
4045 });
4046 setTransition(transition2);
4047 }
4048 }, [pendingState, renderDfd, router2.window]);
4049 React3.useEffect(() => {
4050 if (renderDfd && pendingState && state.location.key === pendingState.location.key) {
4051 renderDfd.resolve();
4052 }
4053 }, [renderDfd, transition, state.location, pendingState]);
4054 React3.useEffect(() => {
4055 if (!vtContext.isTransitioning && interruption) {
4056 setPendingState(interruption.state);
4057 setVtContext({
4058 isTransitioning: true,
4059 flushSync: false,
4060 currentLocation: interruption.currentLocation,
4061 nextLocation: interruption.nextLocation
4062 });
4063 setInterruption(void 0);
4064 }
4065 }, [vtContext.isTransitioning, interruption]);
4066 let navigator2 = React3.useMemo(() => {
4067 return {
4068 createHref: router2.createHref,
4069 encodeLocation: router2.encodeLocation,
4070 go: (n) => router2.navigate(n),
4071 push: (to, state2, opts) => router2.navigate(to, {
4072 state: state2,
4073 preventScrollReset: opts?.preventScrollReset
4074 }),
4075 replace: (to, state2, opts) => router2.navigate(to, {
4076 replace: true,
4077 state: state2,
4078 preventScrollReset: opts?.preventScrollReset
4079 })
4080 };
4081 }, [router2]);
4082 let basename = router2.basename || "/";
4083 let dataRouterContext = React3.useMemo(
4084 () => ({
4085 router: router2,
4086 navigator: navigator2,
4087 static: false,
4088 basename
4089 }),
4090 [router2, navigator2, basename]
4091 );
4092 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(
4093 Router,
4094 {
4095 basename,
4096 location: state.location,
4097 navigationType: state.historyAction,
4098 navigator: navigator2
4099 },
4100 /* @__PURE__ */ React3.createElement(
4101 MemoizedDataRoutes,
4102 {
4103 routes: router2.routes,
4104 future: router2.future,
4105 state
4106 }
4107 )
4108 ))))), null);
4109}
4110var MemoizedDataRoutes = React3.memo(DataRoutes);
4111function DataRoutes({
4112 routes,
4113 future,
4114 state
4115}) {
4116 return useRoutesImpl(routes, void 0, state, future);
4117}
4118function Router({
4119 basename: basenameProp = "/",
4120 children = null,
4121 location: locationProp,
4122 navigationType = "POP" /* Pop */,
4123 navigator: navigator2,
4124 static: staticProp = false
4125}) {
4126 invariant(
4127 !useInRouterContext(),
4128 `You cannot render a <Router> inside another <Router>. You should never have more than one in your app.`
4129 );
4130 let basename = basenameProp.replace(/^\/*/, "/");
4131 let navigationContext = React3.useMemo(
4132 () => ({
4133 basename,
4134 navigator: navigator2,
4135 static: staticProp,
4136 future: {}
4137 }),
4138 [basename, navigator2, staticProp]
4139 );
4140 if (typeof locationProp === "string") {
4141 locationProp = parsePath(locationProp);
4142 }
4143 let {
4144 pathname = "/",
4145 search = "",
4146 hash = "",
4147 state = null,
4148 key = "default"
4149 } = locationProp;
4150 let locationContext = React3.useMemo(() => {
4151 let trailingPathname = stripBasename(pathname, basename);
4152 if (trailingPathname == null) {
4153 return null;
4154 }
4155 return {
4156 location: {
4157 pathname: trailingPathname,
4158 search,
4159 hash,
4160 state,
4161 key
4162 },
4163 navigationType
4164 };
4165 }, [basename, pathname, search, hash, state, key, navigationType]);
4166 warning(
4167 locationContext != null,
4168 `<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.`
4169 );
4170 if (locationContext == null) {
4171 return null;
4172 }
4173 return /* @__PURE__ */ React3.createElement(NavigationContext.Provider, { value: navigationContext }, /* @__PURE__ */ React3.createElement(LocationContext.Provider, { children, value: locationContext }));
4174}
4175
4176// lib/dom/ssr/components.tsx
4177var React9 = __toESM(require("react"));
4178
4179// lib/dom/ssr/invariant.ts
4180function invariant2(value, message) {
4181 if (value === false || value === null || typeof value === "undefined") {
4182 throw new Error(message);
4183 }
4184}
4185
4186// lib/dom/ssr/routeModules.ts
4187async function loadRouteModule(route, routeModulesCache) {
4188 if (route.id in routeModulesCache) {
4189 return routeModulesCache[route.id];
4190 }
4191 try {
4192 let routeModule = await import(
4193 /* @vite-ignore */
4194 /* webpackIgnore: true */
4195 route.module
4196 );
4197 routeModulesCache[route.id] = routeModule;
4198 return routeModule;
4199 } catch (error) {
4200 console.error(
4201 `Error loading route module \`${route.module}\`, reloading page...`
4202 );
4203 console.error(error);
4204 if (window.__reactRouterContext && window.__reactRouterContext.isSpaMode && // @ts-expect-error
4205 void 0) {
4206 throw error;
4207 }
4208 window.location.reload();
4209 return new Promise(() => {
4210 });
4211 }
4212}
4213
4214// lib/dom/ssr/links.ts
4215async function prefetchStyleLinks(route, routeModule) {
4216 if (!route.css && !routeModule.links || !isPreloadSupported()) return;
4217 let descriptors = [];
4218 if (route.css) {
4219 descriptors.push(...route.css.map((href) => ({ rel: "stylesheet", href })));
4220 }
4221 if (routeModule.links) {
4222 descriptors.push(...routeModule.links());
4223 }
4224 if (descriptors.length === 0) return;
4225 let styleLinks = [];
4226 for (let descriptor of descriptors) {
4227 if (!isPageLinkDescriptor(descriptor) && descriptor.rel === "stylesheet") {
4228 styleLinks.push({
4229 ...descriptor,
4230 rel: "preload",
4231 as: "style"
4232 });
4233 }
4234 }
4235 let matchingLinks = styleLinks.filter(
4236 (link) => (!link.media || window.matchMedia(link.media).matches) && !document.querySelector(`link[rel="stylesheet"][href="${link.href}"]`)
4237 );
4238 await Promise.all(matchingLinks.map(prefetchStyleLink));
4239}
4240async function prefetchStyleLink(descriptor) {
4241 return new Promise((resolve) => {
4242 let link = document.createElement("link");
4243 Object.assign(link, descriptor);
4244 function removeLink() {
4245 if (document.head.contains(link)) {
4246 document.head.removeChild(link);
4247 }
4248 }
4249 link.onload = () => {
4250 removeLink();
4251 resolve();
4252 };
4253 link.onerror = () => {
4254 removeLink();
4255 resolve();
4256 };
4257 document.head.appendChild(link);
4258 });
4259}
4260function isPageLinkDescriptor(object) {
4261 return object != null && typeof object.page === "string";
4262}
4263var _isPreloadSupported;
4264function isPreloadSupported() {
4265 if (_isPreloadSupported !== void 0) {
4266 return _isPreloadSupported;
4267 }
4268 let el = document.createElement("link");
4269 _isPreloadSupported = el.relList.supports("preload");
4270 el = null;
4271 return _isPreloadSupported;
4272}
4273
4274// lib/dom/ssr/markup.ts
4275function createHtml(html) {
4276 return { __html: html };
4277}
4278
4279// lib/dom/ssr/single-fetch.tsx
4280var React4 = __toESM(require("react"));
4281var import_turbo_stream = require("turbo-stream");
4282
4283// lib/dom/ssr/data.ts
4284async function createRequestInit(request) {
4285 let init = { signal: request.signal };
4286 if (request.method !== "GET") {
4287 init.method = request.method;
4288 let contentType = request.headers.get("Content-Type");
4289 if (contentType && /\bapplication\/json\b/.test(contentType)) {
4290 init.headers = { "Content-Type": contentType };
4291 init.body = JSON.stringify(await request.json());
4292 } else if (contentType && /\btext\/plain\b/.test(contentType)) {
4293 init.headers = { "Content-Type": contentType };
4294 init.body = await request.text();
4295 } else if (contentType && /\bapplication\/x-www-form-urlencoded\b/.test(contentType)) {
4296 init.body = new URLSearchParams(await request.text());
4297 } else {
4298 init.body = await request.formData();
4299 }
4300 }
4301 return init;
4302}
4303
4304// lib/dom/ssr/single-fetch.tsx
4305var SingleFetchRedirectSymbol = Symbol("SingleFetchRedirect");
4306function getSingleFetchDataStrategy(manifest, routeModules, getRouter) {
4307 return async ({ request, matches, fetcherKey }) => {
4308 if (request.method !== "GET") {
4309 return singleFetchActionStrategy(request, matches);
4310 }
4311 if (fetcherKey) {
4312 return singleFetchLoaderFetcherStrategy(request, matches);
4313 }
4314 return singleFetchLoaderNavigationStrategy(
4315 manifest,
4316 routeModules,
4317 getRouter(),
4318 request,
4319 matches
4320 );
4321 };
4322}
4323async function singleFetchActionStrategy(request, matches) {
4324 let actionMatch = matches.find((m) => m.shouldLoad);
4325 invariant2(actionMatch, "No action match found");
4326 let actionStatus = void 0;
4327 let result = await actionMatch.resolve(async (handler) => {
4328 let result2 = await handler(async () => {
4329 let url = singleFetchUrl(request.url);
4330 let init = await createRequestInit(request);
4331 let { data: data2, status } = await fetchAndDecode(url, init);
4332 actionStatus = status;
4333 return unwrapSingleFetchResult(
4334 data2,
4335 actionMatch.route.id
4336 );
4337 });
4338 return result2;
4339 });
4340 if (isResponse(result.result) || isRouteErrorResponse(result.result)) {
4341 return { [actionMatch.route.id]: result };
4342 }
4343 return {
4344 [actionMatch.route.id]: {
4345 type: result.type,
4346 result: data(result.result, actionStatus)
4347 }
4348 };
4349}
4350async function singleFetchLoaderNavigationStrategy(manifest, routeModules, router2, request, matches) {
4351 let routesParams = /* @__PURE__ */ new Set();
4352 let foundOptOutRoute = false;
4353 let routeDfds = matches.map(() => createDeferred2());
4354 let routesLoadedPromise = Promise.all(routeDfds.map((d) => d.promise));
4355 let singleFetchDfd = createDeferred2();
4356 let url = stripIndexParam(singleFetchUrl(request.url));
4357 let init = await createRequestInit(request);
4358 let results = {};
4359 let resolvePromise = Promise.all(
4360 matches.map(
4361 async (m, i) => m.resolve(async (handler) => {
4362 routeDfds[i].resolve();
4363 let manifestRoute = manifest.routes[m.route.id];
4364 if (!m.shouldLoad) {
4365 if (!router2.state.initialized) {
4366 return;
4367 }
4368 if (m.route.id in router2.state.loaderData && manifestRoute && manifestRoute.hasLoader && routeModules[m.route.id]?.shouldRevalidate) {
4369 foundOptOutRoute = true;
4370 return;
4371 }
4372 }
4373 if (manifestRoute && manifestRoute.hasClientLoader) {
4374 if (manifestRoute.hasLoader) {
4375 foundOptOutRoute = true;
4376 }
4377 try {
4378 let result = await fetchSingleLoader(
4379 handler,
4380 url,
4381 init,
4382 m.route.id
4383 );
4384 results[m.route.id] = { type: "data", result };
4385 } catch (e) {
4386 results[m.route.id] = { type: "error", result: e };
4387 }
4388 return;
4389 }
4390 if (manifestRoute && manifestRoute.hasLoader) {
4391 routesParams.add(m.route.id);
4392 }
4393 try {
4394 let result = await handler(async () => {
4395 let data2 = await singleFetchDfd.promise;
4396 return unwrapSingleFetchResults(data2, m.route.id);
4397 });
4398 results[m.route.id] = {
4399 type: "data",
4400 result
4401 };
4402 } catch (e) {
4403 results[m.route.id] = {
4404 type: "error",
4405 result: e
4406 };
4407 }
4408 })
4409 )
4410 );
4411 await routesLoadedPromise;
4412 if ((!router2.state.initialized || routesParams.size === 0) && !window.__reactRouterHdrActive) {
4413 singleFetchDfd.resolve({});
4414 } else {
4415 try {
4416 if (foundOptOutRoute && routesParams.size > 0) {
4417 url.searchParams.set(
4418 "_routes",
4419 matches.filter((m) => routesParams.has(m.route.id)).map((m) => m.route.id).join(",")
4420 );
4421 }
4422 let data2 = await fetchAndDecode(url, init);
4423 singleFetchDfd.resolve(data2.data);
4424 } catch (e) {
4425 singleFetchDfd.reject(e);
4426 }
4427 }
4428 await resolvePromise;
4429 return results;
4430}
4431async function singleFetchLoaderFetcherStrategy(request, matches) {
4432 let fetcherMatch = matches.find((m) => m.shouldLoad);
4433 invariant2(fetcherMatch, "No fetcher match found");
4434 let result = await fetcherMatch.resolve(async (handler) => {
4435 let url = stripIndexParam(singleFetchUrl(request.url));
4436 let init = await createRequestInit(request);
4437 return fetchSingleLoader(handler, url, init, fetcherMatch.route.id);
4438 });
4439 return { [fetcherMatch.route.id]: result };
4440}
4441function fetchSingleLoader(handler, url, init, routeId) {
4442 return handler(async () => {
4443 let singleLoaderUrl = new URL(url);
4444 singleLoaderUrl.searchParams.set("_routes", routeId);
4445 let { data: data2 } = await fetchAndDecode(singleLoaderUrl, init);
4446 return unwrapSingleFetchResults(data2, routeId);
4447 });
4448}
4449function stripIndexParam(url) {
4450 let indexValues = url.searchParams.getAll("index");
4451 url.searchParams.delete("index");
4452 let indexValuesToKeep = [];
4453 for (let indexValue of indexValues) {
4454 if (indexValue) {
4455 indexValuesToKeep.push(indexValue);
4456 }
4457 }
4458 for (let toKeep of indexValuesToKeep) {
4459 url.searchParams.append("index", toKeep);
4460 }
4461 return url;
4462}
4463function singleFetchUrl(reqUrl) {
4464 let url = typeof reqUrl === "string" ? new URL(
4465 reqUrl,
4466 // This can be called during the SSR flow via PrefetchPageLinksImpl so
4467 // don't assume window is available
4468 typeof window === "undefined" ? "server://singlefetch/" : window.location.origin
4469 ) : reqUrl;
4470 if (url.pathname === "/") {
4471 url.pathname = "_root.data";
4472 } else {
4473 url.pathname = `${url.pathname.replace(/\/$/, "")}.data`;
4474 }
4475 return url;
4476}
4477async function fetchAndDecode(url, init) {
4478 let res = await fetch(url, init);
4479 if (res.status === 404 && !res.headers.has("X-Remix-Response")) {
4480 throw new ErrorResponseImpl(404, "Not Found", true);
4481 }
4482 invariant2(res.body, "No response body to decode");
4483 try {
4484 let decoded = await decodeViaTurboStream(res.body, window);
4485 return { status: res.status, data: decoded.value };
4486 } catch (e) {
4487 throw new Error("Unable to decode turbo-stream response");
4488 }
4489}
4490function decodeViaTurboStream(body, global) {
4491 return (0, import_turbo_stream.decode)(body, {
4492 plugins: [
4493 (type, ...rest) => {
4494 if (type === "SanitizedError") {
4495 let [name, message, stack] = rest;
4496 let Constructor = Error;
4497 if (name && name in global && typeof global[name] === "function") {
4498 Constructor = global[name];
4499 }
4500 let error = new Constructor(message);
4501 error.stack = stack;
4502 return { value: error };
4503 }
4504 if (type === "ErrorResponse") {
4505 let [data2, status, statusText] = rest;
4506 return {
4507 value: new ErrorResponseImpl(status, statusText, data2)
4508 };
4509 }
4510 if (type === "SingleFetchRedirect") {
4511 return { value: { [SingleFetchRedirectSymbol]: rest[0] } };
4512 }
4513 if (type === "SingleFetchClassInstance") {
4514 return { value: rest[0] };
4515 }
4516 if (type === "SingleFetchFallback") {
4517 return { value: void 0 };
4518 }
4519 }
4520 ]
4521 });
4522}
4523function unwrapSingleFetchResults(results, routeId) {
4524 let redirect2 = results[SingleFetchRedirectSymbol];
4525 if (redirect2) {
4526 return unwrapSingleFetchResult(redirect2, routeId);
4527 }
4528 return results[routeId] !== void 0 ? unwrapSingleFetchResult(results[routeId], routeId) : null;
4529}
4530function unwrapSingleFetchResult(result, routeId) {
4531 if ("error" in result) {
4532 throw result.error;
4533 } else if ("redirect" in result) {
4534 let headers = {};
4535 if (result.revalidate) {
4536 headers["X-Remix-Revalidate"] = "yes";
4537 }
4538 if (result.reload) {
4539 headers["X-Remix-Reload-Document"] = "yes";
4540 }
4541 if (result.replace) {
4542 headers["X-Remix-Replace"] = "yes";
4543 }
4544 return redirect(result.redirect, { status: result.status, headers });
4545 } else if ("data" in result) {
4546 return result.data;
4547 } else {
4548 throw new Error(`No response found for routeId "${routeId}"`);
4549 }
4550}
4551function createDeferred2() {
4552 let resolve;
4553 let reject;
4554 let promise = new Promise((res, rej) => {
4555 resolve = async (val) => {
4556 res(val);
4557 try {
4558 await promise;
4559 } catch (e) {
4560 }
4561 };
4562 reject = async (error) => {
4563 rej(error);
4564 try {
4565 await promise;
4566 } catch (e) {
4567 }
4568 };
4569 });
4570 return {
4571 promise,
4572 //@ts-ignore
4573 resolve,
4574 //@ts-ignore
4575 reject
4576 };
4577}
4578
4579// lib/dom/ssr/fog-of-war.ts
4580var React8 = __toESM(require("react"));
4581
4582// lib/dom/ssr/routes.tsx
4583var React7 = __toESM(require("react"));
4584
4585// lib/dom/ssr/errorBoundaries.tsx
4586var React5 = __toESM(require("react"));
4587var RemixErrorBoundary = class extends React5.Component {
4588 constructor(props) {
4589 super(props);
4590 this.state = { error: props.error || null, location: props.location };
4591 }
4592 static getDerivedStateFromError(error) {
4593 return { error };
4594 }
4595 static getDerivedStateFromProps(props, state) {
4596 if (state.location !== props.location) {
4597 return { error: props.error || null, location: props.location };
4598 }
4599 return { error: props.error || state.error, location: state.location };
4600 }
4601 render() {
4602 if (this.state.error) {
4603 return /* @__PURE__ */ React5.createElement(
4604 RemixRootDefaultErrorBoundary,
4605 {
4606 error: this.state.error,
4607 isOutsideRemixApp: true
4608 }
4609 );
4610 } else {
4611 return this.props.children;
4612 }
4613 }
4614};
4615function RemixRootDefaultErrorBoundary({
4616 error,
4617 isOutsideRemixApp
4618}) {
4619 console.error(error);
4620 let heyDeveloper = /* @__PURE__ */ React5.createElement(
4621 "script",
4622 {
4623 dangerouslySetInnerHTML: {
4624 __html: `
4625 console.log(
4626 "\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."
4627 );
4628 `
4629 }
4630 }
4631 );
4632 if (isRouteErrorResponse(error)) {
4633 return /* @__PURE__ */ React5.createElement(BoundaryShell, { title: "Unhandled Thrown Response!" }, /* @__PURE__ */ React5.createElement("h1", { style: { fontSize: "24px" } }, error.status, " ", error.statusText), heyDeveloper);
4634 }
4635 let errorInstance;
4636 if (error instanceof Error) {
4637 errorInstance = error;
4638 } else {
4639 let errorString = error == null ? "Unknown Error" : typeof error === "object" && "toString" in error ? error.toString() : JSON.stringify(error);
4640 errorInstance = new Error(errorString);
4641 }
4642 return /* @__PURE__ */ React5.createElement(
4643 BoundaryShell,
4644 {
4645 title: "Application Error!",
4646 isOutsideRemixApp
4647 },
4648 /* @__PURE__ */ React5.createElement("h1", { style: { fontSize: "24px" } }, "Application Error"),
4649 /* @__PURE__ */ React5.createElement(
4650 "pre",
4651 {
4652 style: {
4653 padding: "2rem",
4654 background: "hsla(10, 50%, 50%, 0.1)",
4655 color: "red",
4656 overflow: "auto"
4657 }
4658 },
4659 errorInstance.stack
4660 ),
4661 heyDeveloper
4662 );
4663}
4664function BoundaryShell({
4665 title,
4666 renderScripts,
4667 isOutsideRemixApp,
4668 children
4669}) {
4670 let { routeModules } = useFrameworkContext();
4671 if (routeModules.root?.Layout && !isOutsideRemixApp) {
4672 return children;
4673 }
4674 return /* @__PURE__ */ React5.createElement("html", { lang: "en" }, /* @__PURE__ */ React5.createElement("head", null, /* @__PURE__ */ React5.createElement("meta", { charSet: "utf-8" }), /* @__PURE__ */ React5.createElement(
4675 "meta",
4676 {
4677 name: "viewport",
4678 content: "width=device-width,initial-scale=1,viewport-fit=cover"
4679 }
4680 ), /* @__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)));
4681}
4682
4683// lib/dom/ssr/fallback.tsx
4684var React6 = __toESM(require("react"));
4685function RemixRootDefaultHydrateFallback() {
4686 return /* @__PURE__ */ React6.createElement(BoundaryShell, { title: "Loading...", renderScripts: true }, /* @__PURE__ */ React6.createElement(
4687 "script",
4688 {
4689 dangerouslySetInnerHTML: {
4690 __html: `
4691 console.log(
4692 "\u{1F4BF} Hey developer \u{1F44B}. You can provide a way better UX than this " +
4693 "when your app is loading JS modules and/or running \`clientLoader\` " +
4694 "functions. Check out https://remix.run/route/hydrate-fallback " +
4695 "for more information."
4696 );
4697 `
4698 }
4699 }
4700 ));
4701}
4702
4703// lib/dom/ssr/routes.tsx
4704function groupRoutesByParentId(manifest) {
4705 let routes = {};
4706 Object.values(manifest).forEach((route) => {
4707 if (route) {
4708 let parentId = route.parentId || "";
4709 if (!routes[parentId]) {
4710 routes[parentId] = [];
4711 }
4712 routes[parentId].push(route);
4713 }
4714 });
4715 return routes;
4716}
4717function getRouteComponents(route, routeModule, isSpaMode) {
4718 let Component4 = getRouteModuleComponent(routeModule);
4719 let HydrateFallback = routeModule.HydrateFallback && (!isSpaMode || route.id === "root") ? routeModule.HydrateFallback : route.id === "root" ? RemixRootDefaultHydrateFallback : void 0;
4720 let ErrorBoundary = routeModule.ErrorBoundary ? routeModule.ErrorBoundary : route.id === "root" ? () => /* @__PURE__ */ React7.createElement(RemixRootDefaultErrorBoundary, { error: useRouteError() }) : void 0;
4721 if (route.id === "root" && routeModule.Layout) {
4722 return {
4723 ...Component4 ? {
4724 element: /* @__PURE__ */ React7.createElement(routeModule.Layout, null, /* @__PURE__ */ React7.createElement(Component4, null))
4725 } : { Component: Component4 },
4726 ...ErrorBoundary ? {
4727 errorElement: /* @__PURE__ */ React7.createElement(routeModule.Layout, null, /* @__PURE__ */ React7.createElement(ErrorBoundary, null))
4728 } : { ErrorBoundary },
4729 ...HydrateFallback ? {
4730 hydrateFallbackElement: /* @__PURE__ */ React7.createElement(routeModule.Layout, null, /* @__PURE__ */ React7.createElement(HydrateFallback, null))
4731 } : { HydrateFallback }
4732 };
4733 }
4734 return { Component: Component4, ErrorBoundary, HydrateFallback };
4735}
4736function createClientRoutesWithHMRRevalidationOptOut(needsRevalidation, manifest, routeModulesCache, initialState, future, isSpaMode) {
4737 return createClientRoutes(
4738 manifest,
4739 routeModulesCache,
4740 initialState,
4741 isSpaMode,
4742 "",
4743 groupRoutesByParentId(manifest),
4744 needsRevalidation
4745 );
4746}
4747function preventInvalidServerHandlerCall(type, route, isSpaMode) {
4748 if (isSpaMode) {
4749 let fn2 = type === "action" ? "serverAction()" : "serverLoader()";
4750 let msg2 = `You cannot call ${fn2} in SPA Mode (routeId: "${route.id}")`;
4751 console.error(msg2);
4752 throw new ErrorResponseImpl(400, "Bad Request", new Error(msg2), true);
4753 }
4754 let fn = type === "action" ? "serverAction()" : "serverLoader()";
4755 let msg = `You are trying to call ${fn} on a route that does not have a server ${type} (routeId: "${route.id}")`;
4756 if (type === "loader" && !route.hasLoader || type === "action" && !route.hasAction) {
4757 console.error(msg);
4758 throw new ErrorResponseImpl(400, "Bad Request", new Error(msg), true);
4759 }
4760}
4761function noActionDefinedError(type, routeId) {
4762 let article = type === "clientAction" ? "a" : "an";
4763 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`;
4764 console.error(msg);
4765 throw new ErrorResponseImpl(405, "Method Not Allowed", new Error(msg), true);
4766}
4767function createClientRoutes(manifest, routeModulesCache, initialState, isSpaMode, parentId = "", routesByParentId = groupRoutesByParentId(manifest), needsRevalidation) {
4768 return (routesByParentId[parentId] || []).map((route) => {
4769 let routeModule = routeModulesCache[route.id];
4770 function fetchServerHandler(singleFetch) {
4771 invariant2(
4772 typeof singleFetch === "function",
4773 "No single fetch function available for route handler"
4774 );
4775 return singleFetch();
4776 }
4777 function fetchServerLoader(singleFetch) {
4778 if (!route.hasLoader) return Promise.resolve(null);
4779 return fetchServerHandler(singleFetch);
4780 }
4781 function fetchServerAction(singleFetch) {
4782 if (!route.hasAction) {
4783 throw noActionDefinedError("action", route.id);
4784 }
4785 return fetchServerHandler(singleFetch);
4786 }
4787 async function prefetchStylesAndCallHandler(handler) {
4788 let cachedModule = routeModulesCache[route.id];
4789 let linkPrefetchPromise = cachedModule ? prefetchStyleLinks(route, cachedModule) : Promise.resolve();
4790 try {
4791 return handler();
4792 } finally {
4793 await linkPrefetchPromise;
4794 }
4795 }
4796 let dataRoute = {
4797 id: route.id,
4798 index: route.index,
4799 path: route.path
4800 };
4801 if (routeModule) {
4802 Object.assign(dataRoute, {
4803 ...dataRoute,
4804 ...getRouteComponents(route, routeModule, isSpaMode),
4805 handle: routeModule.handle,
4806 shouldRevalidate: getShouldRevalidateFunction(
4807 routeModule,
4808 route.id,
4809 needsRevalidation
4810 )
4811 });
4812 let hasInitialData = initialState && initialState.loaderData && route.id in initialState.loaderData;
4813 let initialData = hasInitialData ? initialState?.loaderData?.[route.id] : void 0;
4814 let hasInitialError = initialState && initialState.errors && route.id in initialState.errors;
4815 let initialError = hasInitialError ? initialState?.errors?.[route.id] : void 0;
4816 let isHydrationRequest = needsRevalidation == null && (routeModule.clientLoader?.hydrate === true || !route.hasLoader);
4817 dataRoute.loader = async ({ request, params }, singleFetch) => {
4818 try {
4819 let result = await prefetchStylesAndCallHandler(async () => {
4820 invariant2(
4821 routeModule,
4822 "No `routeModule` available for critical-route loader"
4823 );
4824 if (!routeModule.clientLoader) {
4825 if (isSpaMode) return null;
4826 return fetchServerLoader(singleFetch);
4827 }
4828 return routeModule.clientLoader({
4829 request,
4830 params,
4831 async serverLoader() {
4832 preventInvalidServerHandlerCall("loader", route, isSpaMode);
4833 if (isHydrationRequest) {
4834 if (hasInitialData) {
4835 return initialData;
4836 }
4837 if (hasInitialError) {
4838 throw initialError;
4839 }
4840 }
4841 return fetchServerLoader(singleFetch);
4842 }
4843 });
4844 });
4845 return result;
4846 } finally {
4847 isHydrationRequest = false;
4848 }
4849 };
4850 dataRoute.loader.hydrate = shouldHydrateRouteLoader(
4851 route,
4852 routeModule,
4853 isSpaMode
4854 );
4855 dataRoute.action = ({ request, params }, singleFetch) => {
4856 return prefetchStylesAndCallHandler(async () => {
4857 invariant2(
4858 routeModule,
4859 "No `routeModule` available for critical-route action"
4860 );
4861 if (!routeModule.clientAction) {
4862 if (isSpaMode) {
4863 throw noActionDefinedError("clientAction", route.id);
4864 }
4865 return fetchServerAction(singleFetch);
4866 }
4867 return routeModule.clientAction({
4868 request,
4869 params,
4870 async serverAction() {
4871 preventInvalidServerHandlerCall("action", route, isSpaMode);
4872 return fetchServerAction(singleFetch);
4873 }
4874 });
4875 });
4876 };
4877 } else {
4878 if (!route.hasClientLoader) {
4879 dataRoute.loader = ({ request }, singleFetch) => prefetchStylesAndCallHandler(() => {
4880 if (isSpaMode) return Promise.resolve(null);
4881 return fetchServerLoader(singleFetch);
4882 });
4883 }
4884 if (!route.hasClientAction) {
4885 dataRoute.action = ({ request }, singleFetch) => prefetchStylesAndCallHandler(() => {
4886 if (isSpaMode) {
4887 throw noActionDefinedError("clientAction", route.id);
4888 }
4889 return fetchServerAction(singleFetch);
4890 });
4891 }
4892 dataRoute.lazy = async () => {
4893 let mod = await loadRouteModuleWithBlockingLinks(
4894 route,
4895 routeModulesCache
4896 );
4897 let lazyRoute = { ...mod };
4898 if (mod.clientLoader) {
4899 let clientLoader = mod.clientLoader;
4900 lazyRoute.loader = (args, singleFetch) => clientLoader({
4901 ...args,
4902 async serverLoader() {
4903 preventInvalidServerHandlerCall("loader", route, isSpaMode);
4904 return fetchServerLoader(singleFetch);
4905 }
4906 });
4907 }
4908 if (mod.clientAction) {
4909 let clientAction = mod.clientAction;
4910 lazyRoute.action = (args, singleFetch) => clientAction({
4911 ...args,
4912 async serverAction() {
4913 preventInvalidServerHandlerCall("action", route, isSpaMode);
4914 return fetchServerAction(singleFetch);
4915 }
4916 });
4917 }
4918 return {
4919 ...lazyRoute.loader ? { loader: lazyRoute.loader } : {},
4920 ...lazyRoute.action ? { action: lazyRoute.action } : {},
4921 hasErrorBoundary: lazyRoute.hasErrorBoundary,
4922 shouldRevalidate: getShouldRevalidateFunction(
4923 lazyRoute,
4924 route.id,
4925 needsRevalidation
4926 ),
4927 handle: lazyRoute.handle,
4928 // No need to wrap these in layout since the root route is never
4929 // loaded via route.lazy()
4930 Component: lazyRoute.Component,
4931 ErrorBoundary: lazyRoute.ErrorBoundary
4932 };
4933 };
4934 }
4935 let children = createClientRoutes(
4936 manifest,
4937 routeModulesCache,
4938 initialState,
4939 isSpaMode,
4940 route.id,
4941 routesByParentId,
4942 needsRevalidation
4943 );
4944 if (children.length > 0) dataRoute.children = children;
4945 return dataRoute;
4946 });
4947}
4948function getShouldRevalidateFunction(route, routeId, needsRevalidation) {
4949 if (needsRevalidation) {
4950 return wrapShouldRevalidateForHdr(
4951 routeId,
4952 route.shouldRevalidate,
4953 needsRevalidation
4954 );
4955 }
4956 if (route.shouldRevalidate) {
4957 let fn = route.shouldRevalidate;
4958 return (opts) => fn({ ...opts, defaultShouldRevalidate: true });
4959 }
4960 return route.shouldRevalidate;
4961}
4962function wrapShouldRevalidateForHdr(routeId, routeShouldRevalidate, needsRevalidation) {
4963 let handledRevalidation = false;
4964 return (arg) => {
4965 if (!handledRevalidation) {
4966 handledRevalidation = true;
4967 return needsRevalidation.has(routeId);
4968 }
4969 return routeShouldRevalidate ? routeShouldRevalidate(arg) : arg.defaultShouldRevalidate;
4970 };
4971}
4972async function loadRouteModuleWithBlockingLinks(route, routeModules) {
4973 let routeModule = await loadRouteModule(route, routeModules);
4974 await prefetchStyleLinks(route, routeModule);
4975 return {
4976 Component: getRouteModuleComponent(routeModule),
4977 ErrorBoundary: routeModule.ErrorBoundary,
4978 clientAction: routeModule.clientAction,
4979 clientLoader: routeModule.clientLoader,
4980 handle: routeModule.handle,
4981 links: routeModule.links,
4982 meta: routeModule.meta,
4983 shouldRevalidate: routeModule.shouldRevalidate
4984 };
4985}
4986function getRouteModuleComponent(routeModule) {
4987 if (routeModule.default == null) return void 0;
4988 let isEmptyObject = typeof routeModule.default === "object" && Object.keys(routeModule.default).length === 0;
4989 if (!isEmptyObject) {
4990 return routeModule.default;
4991 }
4992}
4993function shouldHydrateRouteLoader(route, routeModule, isSpaMode) {
4994 return isSpaMode && route.id !== "root" || routeModule.clientLoader != null && (routeModule.clientLoader.hydrate === true || route.hasLoader !== true);
4995}
4996
4997// lib/dom/ssr/fog-of-war.ts
4998var nextPaths = /* @__PURE__ */ new Set();
4999var discoveredPathsMaxSize = 1e3;
5000var discoveredPaths = /* @__PURE__ */ new Set();
5001var URL_LIMIT = 7680;
5002function isFogOfWarEnabled(isSpaMode) {
5003 return !isSpaMode;
5004}
5005function getPartialManifest(manifest, router2) {
5006 let routeIds = new Set(router2.state.matches.map((m) => m.route.id));
5007 let segments = router2.state.location.pathname.split("/").filter(Boolean);
5008 let paths = ["/"];
5009 segments.pop();
5010 while (segments.length > 0) {
5011 paths.push(`/${segments.join("/")}`);
5012 segments.pop();
5013 }
5014 paths.forEach((path) => {
5015 let matches = matchRoutes(router2.routes, path, router2.basename);
5016 if (matches) {
5017 matches.forEach((m) => routeIds.add(m.route.id));
5018 }
5019 });
5020 let initialRoutes = [...routeIds].reduce(
5021 (acc, id) => Object.assign(acc, { [id]: manifest.routes[id] }),
5022 {}
5023 );
5024 return {
5025 ...manifest,
5026 routes: initialRoutes
5027 };
5028}
5029function getPatchRoutesOnNavigationFunction(manifest, routeModules, isSpaMode, basename) {
5030 if (!isFogOfWarEnabled(isSpaMode)) {
5031 return void 0;
5032 }
5033 return async ({ path, patch }) => {
5034 if (discoveredPaths.has(path)) {
5035 return;
5036 }
5037 await fetchAndApplyManifestPatches(
5038 [path],
5039 manifest,
5040 routeModules,
5041 isSpaMode,
5042 basename,
5043 patch
5044 );
5045 };
5046}
5047function useFogOFWarDiscovery(router2, manifest, routeModules, isSpaMode) {
5048 React8.useEffect(() => {
5049 if (!isFogOfWarEnabled(isSpaMode) || navigator.connection?.saveData === true) {
5050 return;
5051 }
5052 function registerElement(el) {
5053 let path = el.tagName === "FORM" ? el.getAttribute("action") : el.getAttribute("href");
5054 if (!path) {
5055 return;
5056 }
5057 let url = new URL(path, window.location.origin);
5058 if (!discoveredPaths.has(url.pathname)) {
5059 nextPaths.add(url.pathname);
5060 }
5061 }
5062 async function fetchPatches() {
5063 let lazyPaths = Array.from(nextPaths.keys()).filter((path) => {
5064 if (discoveredPaths.has(path)) {
5065 nextPaths.delete(path);
5066 return false;
5067 }
5068 return true;
5069 });
5070 if (lazyPaths.length === 0) {
5071 return;
5072 }
5073 try {
5074 await fetchAndApplyManifestPatches(
5075 lazyPaths,
5076 manifest,
5077 routeModules,
5078 isSpaMode,
5079 router2.basename,
5080 router2.patchRoutes
5081 );
5082 } catch (e) {
5083 console.error("Failed to fetch manifest patches", e);
5084 }
5085 }
5086 document.body.querySelectorAll("a[data-discover], form[data-discover]").forEach((el) => registerElement(el));
5087 fetchPatches();
5088 let debouncedFetchPatches = debounce(fetchPatches, 100);
5089 function isElement(node) {
5090 return node.nodeType === Node.ELEMENT_NODE;
5091 }
5092 let observer = new MutationObserver((records) => {
5093 let elements = /* @__PURE__ */ new Set();
5094 records.forEach((r) => {
5095 [r.target, ...r.addedNodes].forEach((node) => {
5096 if (!isElement(node)) return;
5097 if (node.tagName === "A" && node.getAttribute("data-discover")) {
5098 elements.add(node);
5099 } else if (node.tagName === "FORM" && node.getAttribute("data-discover")) {
5100 elements.add(node);
5101 }
5102 if (node.tagName !== "A") {
5103 node.querySelectorAll("a[data-discover], form[data-discover]").forEach((el) => elements.add(el));
5104 }
5105 });
5106 });
5107 elements.forEach((el) => registerElement(el));
5108 debouncedFetchPatches();
5109 });
5110 observer.observe(document.documentElement, {
5111 subtree: true,
5112 childList: true,
5113 attributes: true,
5114 attributeFilter: ["data-discover", "href", "action"]
5115 });
5116 return () => observer.disconnect();
5117 }, [isSpaMode, manifest, routeModules, router2]);
5118}
5119async function fetchAndApplyManifestPatches(paths, manifest, routeModules, isSpaMode, basename, patchRoutes) {
5120 let manifestPath = `${basename != null ? basename : "/"}/__manifest`.replace(
5121 /\/+/g,
5122 "/"
5123 );
5124 let url = new URL(manifestPath, window.location.origin);
5125 paths.sort().forEach((path) => url.searchParams.append("p", path));
5126 url.searchParams.set("version", manifest.version);
5127 if (url.toString().length > URL_LIMIT) {
5128 nextPaths.clear();
5129 return;
5130 }
5131 let res = await fetch(url);
5132 if (!res.ok) {
5133 throw new Error(`${res.status} ${res.statusText}`);
5134 } else if (res.status >= 400) {
5135 throw new Error(await res.text());
5136 }
5137 let serverPatches = await res.json();
5138 let knownRoutes = new Set(Object.keys(manifest.routes));
5139 let patches = Object.values(serverPatches).reduce((acc, route) => {
5140 if (route && !knownRoutes.has(route.id)) {
5141 acc[route.id] = route;
5142 }
5143 return acc;
5144 }, {});
5145 Object.assign(manifest.routes, patches);
5146 paths.forEach((p) => addToFifoQueue(p, discoveredPaths));
5147 let parentIds = /* @__PURE__ */ new Set();
5148 Object.values(patches).forEach((patch) => {
5149 if (patch && (!patch.parentId || !patches[patch.parentId])) {
5150 parentIds.add(patch.parentId);
5151 }
5152 });
5153 parentIds.forEach(
5154 (parentId) => patchRoutes(
5155 parentId || null,
5156 createClientRoutes(patches, routeModules, null, isSpaMode, parentId)
5157 )
5158 );
5159}
5160function addToFifoQueue(path, queue) {
5161 if (queue.size >= discoveredPathsMaxSize) {
5162 let first = queue.values().next().value;
5163 queue.delete(first);
5164 }
5165 queue.add(path);
5166}
5167function debounce(callback, wait) {
5168 let timeoutId;
5169 return (...args) => {
5170 window.clearTimeout(timeoutId);
5171 timeoutId = window.setTimeout(() => callback(...args), wait);
5172 };
5173}
5174
5175// lib/dom/ssr/components.tsx
5176function useDataRouterContext() {
5177 let context = React9.useContext(DataRouterContext);
5178 invariant2(
5179 context,
5180 "You must render this element inside a <DataRouterContext.Provider> element"
5181 );
5182 return context;
5183}
5184function useDataRouterStateContext() {
5185 let context = React9.useContext(DataRouterStateContext);
5186 invariant2(
5187 context,
5188 "You must render this element inside a <DataRouterStateContext.Provider> element"
5189 );
5190 return context;
5191}
5192var FrameworkContext = React9.createContext(void 0);
5193FrameworkContext.displayName = "FrameworkContext";
5194function useFrameworkContext() {
5195 let context = React9.useContext(FrameworkContext);
5196 invariant2(
5197 context,
5198 "You must render this element inside a <HydratedRouter> element"
5199 );
5200 return context;
5201}
5202function getActiveMatches(matches, errors, isSpaMode) {
5203 if (isSpaMode && !isHydrated) {
5204 return [matches[0]];
5205 }
5206 if (errors) {
5207 let errorIdx = matches.findIndex((m) => errors[m.route.id] !== void 0);
5208 return matches.slice(0, errorIdx + 1);
5209 }
5210 return matches;
5211}
5212var isHydrated = false;
5213function Scripts(props) {
5214 let { manifest, serverHandoffString, isSpaMode, renderMeta } = useFrameworkContext();
5215 let { router: router2, static: isStatic, staticContext } = useDataRouterContext();
5216 let { matches: routerMatches } = useDataRouterStateContext();
5217 let enableFogOfWar = isFogOfWarEnabled(isSpaMode);
5218 if (renderMeta) {
5219 renderMeta.didRenderScripts = true;
5220 }
5221 let matches = getActiveMatches(routerMatches, null, isSpaMode);
5222 React9.useEffect(() => {
5223 isHydrated = true;
5224 }, []);
5225 let initialScripts = React9.useMemo(() => {
5226 let streamScript = "window.__reactRouterContext.stream = new ReadableStream({start(controller){window.__reactRouterContext.streamController = controller;}}).pipeThrough(new TextEncoderStream());";
5227 let contextScript = staticContext ? `window.__reactRouterContext = ${serverHandoffString};${streamScript}` : " ";
5228 let routeModulesScript = !isStatic ? " " : `${manifest.hmr?.runtime ? `import ${JSON.stringify(manifest.hmr.runtime)};` : ""}${!enableFogOfWar ? `import ${JSON.stringify(manifest.url)}` : ""};
5229${matches.map(
5230 (match, index) => `import * as route${index} from ${JSON.stringify(
5231 manifest.routes[match.route.id].module
5232 )};`
5233 ).join("\n")}
5234 ${enableFogOfWar ? (
5235 // Inline a minimal manifest with the SSR matches
5236 `window.__reactRouterManifest = ${JSON.stringify(
5237 getPartialManifest(manifest, router2),
5238 null,
5239 2
5240 )};`
5241 ) : ""}
5242 window.__reactRouterRouteModules = {${matches.map((match, index) => `${JSON.stringify(match.route.id)}:route${index}`).join(",")}};
5243
5244import(${JSON.stringify(manifest.entry.module)});`;
5245 return /* @__PURE__ */ React9.createElement(React9.Fragment, null, /* @__PURE__ */ React9.createElement(
5246 "script",
5247 {
5248 ...props,
5249 suppressHydrationWarning: true,
5250 dangerouslySetInnerHTML: createHtml(contextScript),
5251 type: void 0
5252 }
5253 ), /* @__PURE__ */ React9.createElement(
5254 "script",
5255 {
5256 ...props,
5257 suppressHydrationWarning: true,
5258 dangerouslySetInnerHTML: createHtml(routeModulesScript),
5259 type: "module",
5260 async: true
5261 }
5262 ));
5263 }, []);
5264 let routePreloads = matches.map((match) => {
5265 let route = manifest.routes[match.route.id];
5266 return route ? (route.imports || []).concat([route.module]) : [];
5267 }).flat(1);
5268 let preloads = isHydrated ? [] : manifest.entry.imports.concat(routePreloads);
5269 return isHydrated ? null : /* @__PURE__ */ React9.createElement(React9.Fragment, null, !enableFogOfWar ? /* @__PURE__ */ React9.createElement(
5270 "link",
5271 {
5272 rel: "modulepreload",
5273 href: manifest.url,
5274 crossOrigin: props.crossOrigin
5275 }
5276 ) : null, /* @__PURE__ */ React9.createElement(
5277 "link",
5278 {
5279 rel: "modulepreload",
5280 href: manifest.entry.module,
5281 crossOrigin: props.crossOrigin
5282 }
5283 ), dedupe(preloads).map((path) => /* @__PURE__ */ React9.createElement(
5284 "link",
5285 {
5286 key: path,
5287 rel: "modulepreload",
5288 href: path,
5289 crossOrigin: props.crossOrigin
5290 }
5291 )), initialScripts);
5292}
5293function dedupe(array) {
5294 return [...new Set(array)];
5295}
5296
5297// lib/dom/ssr/errors.ts
5298function deserializeErrors(errors) {
5299 if (!errors) return null;
5300 let entries = Object.entries(errors);
5301 let serialized = {};
5302 for (let [key, val] of entries) {
5303 if (val && val.__type === "RouteErrorResponse") {
5304 serialized[key] = new ErrorResponseImpl(
5305 val.status,
5306 val.statusText,
5307 val.data,
5308 val.internal === true
5309 );
5310 } else if (val && val.__type === "Error") {
5311 if (val.__subType) {
5312 let ErrorConstructor = window[val.__subType];
5313 if (typeof ErrorConstructor === "function") {
5314 try {
5315 let error = new ErrorConstructor(val.message);
5316 error.stack = val.stack;
5317 serialized[key] = error;
5318 } catch (e) {
5319 }
5320 }
5321 }
5322 if (serialized[key] == null) {
5323 let error = new Error(val.message);
5324 error.stack = val.stack;
5325 serialized[key] = error;
5326 }
5327 } else {
5328 serialized[key] = val;
5329 }
5330 }
5331 return serialized;
5332}
5333
5334// lib/dom-export/dom-router-provider.tsx
5335function RouterProvider2(props) {
5336 return /* @__PURE__ */ React10.createElement(RouterProvider, { flushSync: ReactDOM.flushSync, ...props });
5337}
5338
5339// lib/dom-export/hydrated-router.tsx
5340var React11 = __toESM(require("react"));
5341var ssrInfo = null;
5342var router = null;
5343function initSsrInfo() {
5344 if (!ssrInfo && window.__reactRouterContext && window.__reactRouterManifest && window.__reactRouterRouteModules) {
5345 ssrInfo = {
5346 context: window.__reactRouterContext,
5347 manifest: window.__reactRouterManifest,
5348 routeModules: window.__reactRouterRouteModules,
5349 stateDecodingPromise: void 0,
5350 router: void 0,
5351 routerInitialized: false
5352 };
5353 }
5354}
5355function createHydratedRouter() {
5356 initSsrInfo();
5357 if (!ssrInfo) {
5358 throw new Error(
5359 "You must be using the SSR features of React Router in order to skip passing a `router` prop to `<RouterProvider>`"
5360 );
5361 }
5362 let localSsrInfo = ssrInfo;
5363 if (!ssrInfo.stateDecodingPromise) {
5364 let stream = ssrInfo.context.stream;
5365 invariant(stream, "No stream found for single fetch decoding");
5366 ssrInfo.context.stream = void 0;
5367 ssrInfo.stateDecodingPromise = decodeViaTurboStream(stream, window).then((value) => {
5368 ssrInfo.context.state = value.value;
5369 localSsrInfo.stateDecodingPromise.value = true;
5370 }).catch((e) => {
5371 localSsrInfo.stateDecodingPromise.error = e;
5372 });
5373 }
5374 if (ssrInfo.stateDecodingPromise.error) {
5375 throw ssrInfo.stateDecodingPromise.error;
5376 }
5377 if (!ssrInfo.stateDecodingPromise.value) {
5378 throw ssrInfo.stateDecodingPromise;
5379 }
5380 let routes = createClientRoutes(
5381 ssrInfo.manifest.routes,
5382 ssrInfo.routeModules,
5383 ssrInfo.context.state,
5384 ssrInfo.context.isSpaMode
5385 );
5386 let hydrationData = void 0;
5387 if (!ssrInfo.context.isSpaMode) {
5388 hydrationData = {
5389 ...ssrInfo.context.state,
5390 loaderData: { ...ssrInfo.context.state.loaderData }
5391 };
5392 let initialMatches = matchRoutes(
5393 routes,
5394 window.location,
5395 window.__reactRouterContext?.basename
5396 );
5397 if (initialMatches) {
5398 for (let match of initialMatches) {
5399 let routeId = match.route.id;
5400 let route = ssrInfo.routeModules[routeId];
5401 let manifestRoute = ssrInfo.manifest.routes[routeId];
5402 if (route && manifestRoute && shouldHydrateRouteLoader(
5403 manifestRoute,
5404 route,
5405 ssrInfo.context.isSpaMode
5406 ) && (route.HydrateFallback || !manifestRoute.hasLoader)) {
5407 delete hydrationData.loaderData[routeId];
5408 } else if (manifestRoute && !manifestRoute.hasLoader) {
5409 hydrationData.loaderData[routeId] = null;
5410 }
5411 }
5412 }
5413 if (hydrationData && hydrationData.errors) {
5414 hydrationData.errors = deserializeErrors(hydrationData.errors);
5415 }
5416 }
5417 let router2 = createRouter({
5418 routes,
5419 history: createBrowserHistory(),
5420 basename: ssrInfo.context.basename,
5421 hydrationData,
5422 mapRouteProperties,
5423 dataStrategy: getSingleFetchDataStrategy(
5424 ssrInfo.manifest,
5425 ssrInfo.routeModules,
5426 () => router2
5427 ),
5428 patchRoutesOnNavigation: getPatchRoutesOnNavigationFunction(
5429 ssrInfo.manifest,
5430 ssrInfo.routeModules,
5431 ssrInfo.context.isSpaMode,
5432 ssrInfo.context.basename
5433 )
5434 });
5435 ssrInfo.router = router2;
5436 if (router2.state.initialized) {
5437 ssrInfo.routerInitialized = true;
5438 router2.initialize();
5439 }
5440 router2.createRoutesForHMR = /* spacer so ts-ignore does not affect the right hand of the assignment */
5441 createClientRoutesWithHMRRevalidationOptOut;
5442 window.__reactRouterDataRouter = router2;
5443 return router2;
5444}
5445function HydratedRouter() {
5446 if (!router) {
5447 router = createHydratedRouter();
5448 }
5449 let [criticalCss, setCriticalCss] = React11.useState(
5450 process.env.NODE_ENV === "development" ? ssrInfo?.context.criticalCss : void 0
5451 );
5452 if (process.env.NODE_ENV === "development") {
5453 if (ssrInfo) {
5454 window.__reactRouterClearCriticalCss = () => setCriticalCss(void 0);
5455 }
5456 }
5457 let [location, setLocation] = React11.useState(router.state.location);
5458 React11.useLayoutEffect(() => {
5459 if (ssrInfo && ssrInfo.router && !ssrInfo.routerInitialized) {
5460 ssrInfo.routerInitialized = true;
5461 ssrInfo.router.initialize();
5462 }
5463 }, []);
5464 React11.useLayoutEffect(() => {
5465 if (ssrInfo && ssrInfo.router) {
5466 return ssrInfo.router.subscribe((newState) => {
5467 if (newState.location !== location) {
5468 setLocation(newState.location);
5469 }
5470 });
5471 }
5472 }, [location]);
5473 invariant(ssrInfo, "ssrInfo unavailable for HydratedRouter");
5474 useFogOFWarDiscovery(
5475 router,
5476 ssrInfo.manifest,
5477 ssrInfo.routeModules,
5478 ssrInfo.context.isSpaMode
5479 );
5480 return (
5481 // This fragment is important to ensure we match the <ServerRouter> JSX
5482 // structure so that useId values hydrate correctly
5483 /* @__PURE__ */ React11.createElement(React11.Fragment, null, /* @__PURE__ */ React11.createElement(
5484 FrameworkContext.Provider,
5485 {
5486 value: {
5487 manifest: ssrInfo.manifest,
5488 routeModules: ssrInfo.routeModules,
5489 future: ssrInfo.context.future,
5490 criticalCss,
5491 isSpaMode: ssrInfo.context.isSpaMode
5492 }
5493 },
5494 /* @__PURE__ */ React11.createElement(RemixErrorBoundary, { location }, /* @__PURE__ */ React11.createElement(RouterProvider2, { router }))
5495 ), /* @__PURE__ */ React11.createElement(React11.Fragment, null))
5496 );
5497}
5498// Annotate the CommonJS export names for ESM import in node:
54990 && (module.exports = {
5500 HydratedRouter,
5501 RouterProvider
5502});