UNPKG

130 kBJavaScriptView Raw
1/**
2 * react-router v8.3.0
3 *
4 * Copyright (c) Remix Software Inc.
5 *
6 * This source code is licensed under the MIT license found in the
7 * LICENSE.md file in the root directory of this source tree.
8 *
9 * @license MIT
10 */
11import { AsyncLocalStorage } from "node:async_hooks";
12import * as React from "react";
13import { parse, serialize, splitSetCookieString } from "cookie-es";
14import { BrowserRouter, Form, HashRouter, Link, Links, MemoryRouter, Meta, NavLink, Navigate, Outlet, Outlet as Outlet$1, Route, Router, RouterProvider, Routes, ScrollRestoration, StaticRouter, StaticRouterProvider, UNSAFE_AwaitContextProvider, UNSAFE_WithComponentProps, UNSAFE_WithErrorBoundaryProps, UNSAFE_WithHydrateFallbackProps, unstable_HistoryRouter } from "react-router/internal/react-server-client";
15//#region lib/router/url.ts
16const ABSOLUTE_URL_REGEX = /^(?:[a-z][a-z0-9+.-]*:|[\\/]{2})/i;
17//#endregion
18//#region lib/router/history.ts
19function invariant$1(value, message) {
20 if (value === false || value === null || typeof value === "undefined") throw new Error(message);
21}
22function warning(cond, message) {
23 if (!cond) {
24 if (typeof console !== "undefined") console.warn(message);
25 try {
26 throw new Error(message);
27 } catch (e) {}
28 }
29}
30function createKey$1() {
31 return Math.random().toString(36).substring(2, 10);
32}
33/**
34* Creates a Location object with a unique key from the given Path
35*/
36function createLocation(current, to, state = null, key, mask) {
37 return {
38 pathname: typeof current === "string" ? current : current.pathname,
39 search: "",
40 hash: "",
41 ...typeof to === "string" ? parsePath(to) : to,
42 state,
43 key: to && to.key || key || createKey$1(),
44 mask
45 };
46}
47/**
48* Creates a string URL path from the given pathname, search, and hash components.
49*
50* @public
51* @category Utils
52* @param path The pathname, search, and hash components to combine.
53* @returns The combined URL path.
54*/
55function createPath({ pathname = "/", search = "", hash = "" }) {
56 if (search && search !== "?") pathname += search.charAt(0) === "?" ? search : "?" + search;
57 if (hash && hash !== "#") pathname += hash.charAt(0) === "#" ? hash : "#" + hash;
58 return pathname;
59}
60/**
61* Parses a string URL path into its separate pathname, search, and hash components.
62*
63* @public
64* @category Utils
65* @param path The URL path to parse.
66* @returns The parsed pathname, search, and hash components.
67*/
68function parsePath(path) {
69 let parsedPath = {};
70 if (path) {
71 let hashIndex = path.indexOf("#");
72 if (hashIndex >= 0) {
73 parsedPath.hash = path.substring(hashIndex);
74 path = path.substring(0, hashIndex);
75 }
76 let searchIndex = path.indexOf("?");
77 if (searchIndex >= 0) {
78 parsedPath.search = path.substring(searchIndex);
79 path = path.substring(0, searchIndex);
80 }
81 if (path) parsedPath.pathname = path;
82 }
83 return parsedPath;
84}
85//#endregion
86//#region lib/router/utils.ts
87/**
88* Creates a type-safe {@link RouterContext} object that can be used to
89* store and retrieve arbitrary values in [`action`](../../start/framework/route-module#action)s,
90* [`loader`](../../start/framework/route-module#loader)s, and [middleware](../../how-to/middleware).
91* Similar to React's [`createContext`](https://react.dev/reference/react/createContext),
92* but specifically designed for React Router's request/response lifecycle.
93*
94* If a `defaultValue` is provided, it will be returned from `context.get()`
95* when no value has been set for the context. Otherwise, reading this context
96* when no value has been set will throw an error.
97*
98* ```tsx filename=app/context.ts
99* import { createContext } from "react-router";
100*
101* // Create a context for user data
102* export const userContext =
103* createContext<User | null>(null);
104* ```
105*
106* ```tsx filename=app/middleware/auth.ts
107* import { getUserFromSession } from "~/auth.server";
108* import { userContext } from "~/context";
109*
110* export const authMiddleware = async ({
111* context,
112* request,
113* }) => {
114* const user = await getUserFromSession(request);
115* context.set(userContext, user);
116* };
117* ```
118*
119* ```tsx filename=app/routes/profile.tsx
120* import { userContext } from "~/context";
121*
122* export async function loader({
123* context,
124* }: Route.LoaderArgs) {
125* const user = context.get(userContext);
126*
127* if (!user) {
128* throw new Response("Unauthorized", { status: 401 });
129* }
130*
131* return { user };
132* }
133* ```
134*
135* @public
136* @category Utils
137* @mode framework
138* @mode data
139* @param defaultValue An optional default value for the context. This value
140* will be returned if no value has been set for this context.
141* @returns A {@link RouterContext} object that can be used with
142* `context.get()` and `context.set()` in [`action`](../../start/framework/route-module#action)s,
143* [`loader`](../../start/framework/route-module#loader)s, and [middleware](../../how-to/middleware).
144*/
145function createContext(defaultValue) {
146 return { defaultValue };
147}
148/**
149* Provides methods for writing/reading values in application context in a
150* type-safe way. Primarily for usage with [middleware](../../how-to/middleware).
151*
152* @example
153* import {
154* createContext,
155* RouterContextProvider
156* } from "react-router";
157*
158* const userContext = createContext<User | null>(null);
159* const contextProvider = new RouterContextProvider();
160* contextProvider.set(userContext, getUser());
161* // ^ Type-safe
162* const user = contextProvider.get(userContext);
163* // ^ User
164*
165* @public
166* @category Utils
167* @mode framework
168* @mode data
169*/
170var RouterContextProvider = class {
171 #map = /* @__PURE__ */ new Map();
172 /**
173 * Create a new `RouterContextProvider` instance
174 * @param init An optional initial context map to populate the provider with
175 */
176 constructor(init) {
177 if (init) for (let [context, value] of init) this.set(context, value);
178 }
179 /**
180 * Access a value from the context. If no value has been set for the context,
181 * it will return the context's `defaultValue` if provided, or throw an error
182 * if no `defaultValue` was set.
183 * @param context The context to get the value for
184 * @returns The value for the context, or the context's `defaultValue` if no
185 * value was set
186 */
187 get(context) {
188 if (this.#map.has(context)) return this.#map.get(context);
189 if (context.defaultValue !== void 0) return context.defaultValue;
190 throw new Error("No value found for context");
191 }
192 /**
193 * Set a value for the context. If the context already has a value set, this
194 * will overwrite it.
195 *
196 * @param context The context to set the value for
197 * @param value The value to set for the context
198 * @returns {void}
199 */
200 set(context, value) {
201 this.#map.set(context, value);
202 }
203};
204const unsupportedLazyRouteObjectKeys = new Set([
205 "lazy",
206 "caseSensitive",
207 "path",
208 "id",
209 "index",
210 "children"
211]);
212function isUnsupportedLazyRouteObjectKey(key) {
213 return unsupportedLazyRouteObjectKeys.has(key);
214}
215const unsupportedLazyRouteFunctionKeys = new Set([
216 "lazy",
217 "caseSensitive",
218 "path",
219 "id",
220 "index",
221 "middleware",
222 "children"
223]);
224function isUnsupportedLazyRouteFunctionKey(key) {
225 return unsupportedLazyRouteFunctionKeys.has(key);
226}
227function isIndexRoute(route) {
228 return route.index === true;
229}
230function defaultMapRouteProperties(route) {
231 let updates = {};
232 if (route.Component) {
233 if (route.element) warning(false, "You should not include both `Component` and `element` on your route - `Component` will be used.");
234 Object.assign(updates, {
235 element: React.createElement(route.Component),
236 Component: void 0
237 });
238 }
239 if (route.HydrateFallback) {
240 if (route.hydrateFallbackElement) warning(false, "You should not include both `HydrateFallback` and `hydrateFallbackElement` on your route - `HydrateFallback` will be used.");
241 Object.assign(updates, {
242 hydrateFallbackElement: React.createElement(route.HydrateFallback),
243 HydrateFallback: void 0
244 });
245 }
246 if (route.ErrorBoundary) {
247 if (route.errorElement) warning(false, "You should not include both `ErrorBoundary` and `errorElement` on your route - `ErrorBoundary` will be used.");
248 Object.assign(updates, {
249 errorElement: React.createElement(route.ErrorBoundary),
250 ErrorBoundary: void 0
251 });
252 }
253 return updates;
254}
255function convertRoutesToDataRoutes(routes, mapRouteProperties = defaultMapRouteProperties, parentPath = [], manifest = {}, allowInPlaceMutations = false) {
256 return routes.map((route, index) => {
257 let treePath = [...parentPath, String(index)];
258 let id = typeof route.id === "string" ? route.id : treePath.join("-");
259 invariant$1(route.index !== true || !route.children, `Cannot specify children on an index route`);
260 invariant$1(allowInPlaceMutations || !manifest[id], `Found a route id collision on id "${id}". Route id's must be globally unique within Data Router usages`);
261 if (isIndexRoute(route)) {
262 let indexRoute = {
263 ...route,
264 id
265 };
266 manifest[id] = mergeRouteUpdates(indexRoute, mapRouteProperties(indexRoute));
267 return indexRoute;
268 } else {
269 let pathOrLayoutRoute = {
270 ...route,
271 id,
272 children: void 0
273 };
274 manifest[id] = mergeRouteUpdates(pathOrLayoutRoute, mapRouteProperties(pathOrLayoutRoute));
275 if (route.children) pathOrLayoutRoute.children = convertRoutesToDataRoutes(route.children, mapRouteProperties, treePath, manifest, allowInPlaceMutations);
276 return pathOrLayoutRoute;
277 }
278 });
279}
280function mergeRouteUpdates(route, updates) {
281 return Object.assign(route, {
282 ...updates,
283 ...typeof updates.lazy === "object" && updates.lazy != null ? { lazy: {
284 ...route.lazy,
285 ...updates.lazy
286 } } : {}
287 });
288}
289/**
290* Matches the given routes to a location and returns the match data.
291*
292* @example
293* import { matchRoutes } from "react-router";
294*
295* let routes = [{
296* path: "/",
297* Component: Root,
298* children: [{
299* path: "dashboard",
300* Component: Dashboard,
301* }]
302* }];
303*
304* matchRoutes(routes, "/dashboard"); // [rootMatch, dashboardMatch]
305*
306* @public
307* @category Utils
308* @param routes The array of route objects to match against.
309* @param locationArg The location to match against, either a string path or a
310* partial {@link Location} object
311* @param basename Optional base path to strip from the location before matching.
312* Defaults to `/`.
313* @returns An array of matched routes, or `null` if no matches were found.
314*/
315function matchRoutes(routes, locationArg, basename = "/") {
316 return matchRoutesImpl(routes, locationArg, basename, false);
317}
318function matchRoutesImpl(routes, locationArg, basename, allowPartial, precomputedBranches) {
319 let pathname = stripBasename((typeof locationArg === "string" ? parsePath(locationArg) : locationArg).pathname || "/", basename);
320 if (pathname == null) return null;
321 let branches = precomputedBranches ?? flattenAndRankRoutes(routes);
322 let matches = null;
323 let decoded = decodePath(pathname);
324 for (let i = 0; matches == null && i < branches.length; ++i) matches = matchRouteBranch(branches[i], decoded, allowPartial);
325 return matches;
326}
327function convertRouteMatchToUiMatch(match, loaderData) {
328 let { route, pathname, params } = match;
329 return {
330 id: route.id,
331 pathname,
332 params,
333 loaderData: loaderData[route.id],
334 handle: route.handle
335 };
336}
337function flattenAndRankRoutes(routes) {
338 let branches = flattenRoutes(routes);
339 rankRouteBranches(branches);
340 return branches;
341}
342function flattenRoutes(routes, branches = [], parentsMeta = [], parentPath = "", _hasParentOptionalSegments = false) {
343 let flattenRoute = (route, index, hasParentOptionalSegments = _hasParentOptionalSegments, relativePath) => {
344 let meta = {
345 relativePath: relativePath === void 0 ? route.path || "" : relativePath,
346 caseSensitive: route.caseSensitive === true,
347 childrenIndex: index,
348 route
349 };
350 if (meta.relativePath.startsWith("/")) {
351 if (!meta.relativePath.startsWith(parentPath) && hasParentOptionalSegments) return;
352 invariant$1(meta.relativePath.startsWith(parentPath), `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.`);
353 meta.relativePath = meta.relativePath.slice(parentPath.length);
354 }
355 let path = joinPaths([parentPath, meta.relativePath]);
356 let routesMeta = parentsMeta.concat(meta);
357 if (route.children && route.children.length > 0) {
358 invariant$1(route.index !== true, `Index routes must not have child routes. Please remove all child routes from route path "${path}".`);
359 flattenRoutes(route.children, branches, routesMeta, path, hasParentOptionalSegments);
360 }
361 if (route.path == null && !route.index) return;
362 branches.push({
363 path,
364 score: computeScore(path, route.index),
365 routesMeta: routesMeta.map((meta, i) => {
366 let [matcher, params] = compilePath(meta.relativePath, meta.caseSensitive, i === routesMeta.length - 1);
367 return {
368 ...meta,
369 matcher,
370 compiledParams: params
371 };
372 })
373 });
374 };
375 routes.forEach((route, index) => {
376 if (route.path === "" || !route.path?.includes("?")) flattenRoute(route, index);
377 else for (let exploded of explodeOptionalSegments(route.path)) flattenRoute(route, index, true, exploded);
378 });
379 return branches;
380}
381function explodeOptionalSegments(path) {
382 let segments = path.split("/");
383 if (segments.length === 0) return [];
384 let [first, ...rest] = segments;
385 let isOptional = first.endsWith("?");
386 let required = first.replace(/\?$/, "");
387 if (rest.length === 0) return isOptional ? [required, ""] : [required];
388 let restExploded = explodeOptionalSegments(rest.join("/"));
389 let result = [];
390 result.push(...restExploded.map((subpath) => subpath === "" ? required : [required, subpath].join("/")));
391 if (isOptional) result.push(...restExploded);
392 return result.map((exploded) => path.startsWith("/") && exploded === "" ? "/" : exploded);
393}
394function rankRouteBranches(branches) {
395 branches.sort((a, b) => a.score !== b.score ? b.score - a.score : compareIndexes(a.routesMeta.map((meta) => meta.childrenIndex), b.routesMeta.map((meta) => meta.childrenIndex)));
396}
397const paramRe = /^:[\w-]+$/;
398const partialParamRe = /^:[\w-]+/;
399const partialDynamicSegmentValue = 3.5;
400const dynamicSegmentValue = 3;
401const indexRouteValue = 2;
402const emptySegmentValue = 1;
403const staticSegmentValue = 10;
404const splatPenalty = -2;
405const isSplat = (s) => s === "*";
406function computeScore(path, index) {
407 let segments = path.split("/");
408 let initialScore = segments.length;
409 if (segments.some(isSplat)) initialScore += splatPenalty;
410 if (index) initialScore += indexRouteValue;
411 return segments.filter((s) => !isSplat(s)).reduce((score, segment) => score + (paramRe.test(segment) ? dynamicSegmentValue : partialParamRe.test(segment) ? partialDynamicSegmentValue : segment === "" ? emptySegmentValue : staticSegmentValue), initialScore);
412}
413function compareIndexes(a, b) {
414 return a.length === b.length && a.slice(0, -1).every((n, i) => n === b[i]) ? a[a.length - 1] - b[b.length - 1] : 0;
415}
416function matchRouteBranch(branch, pathname, allowPartial = false) {
417 let { routesMeta } = branch;
418 let matchedParams = {};
419 let matchedPathname = "/";
420 let matches = [];
421 for (let i = 0; i < routesMeta.length; ++i) {
422 let meta = routesMeta[i];
423 let end = i === routesMeta.length - 1;
424 let remainingPathname = matchedPathname === "/" ? pathname : pathname.slice(matchedPathname.length) || "/";
425 let pattern = {
426 path: meta.relativePath,
427 caseSensitive: meta.caseSensitive,
428 end
429 };
430 let match = meta.matcher && meta.compiledParams ? matchPathImpl(pattern, remainingPathname, meta.matcher, meta.compiledParams) : matchPath(pattern, remainingPathname);
431 let route = meta.route;
432 if (!match && end && allowPartial && !routesMeta[routesMeta.length - 1].route.index) match = matchPath({
433 path: meta.relativePath,
434 caseSensitive: meta.caseSensitive,
435 end: false
436 }, remainingPathname);
437 if (!match) return null;
438 Object.assign(matchedParams, match.params);
439 matches.push({
440 params: matchedParams,
441 pathname: joinPaths([matchedPathname, match.pathname]),
442 pathnameBase: normalizePathname(joinPaths([matchedPathname, match.pathnameBase])),
443 route
444 });
445 if (match.pathnameBase !== "/") matchedPathname = joinPaths([matchedPathname, match.pathnameBase]);
446 }
447 return matches;
448}
449/**
450* Characters that `encodeURIComponent` escapes but that are valid literally in
451* a URL path segment. Per RFC 3986 §3.3, a path segment is made of `pchar`:
452*
453* ```
454* pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
455* sub-delims = "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / ";" / "="
456* ```
457*
458* `encodeURIComponent` targets query-string values, where `$ & + , ; = : @`
459* are delimiters and must be escaped — but in a path segment they carry no
460* special meaning, and browsers keep them literal in `location.pathname`.
461* (`! ' ( ) *` and the unreserved set are already left alone by
462* `encodeURIComponent`, so they need no restoring.)
463*/
464const PATH_PARAM_OVERESCAPED = {
465 "%24": "$",
466 "%26": "&",
467 "%2B": "+",
468 "%2C": ",",
469 "%3A": ":",
470 "%3B": ";",
471 "%3D": "=",
472 "%40": "@"
473};
474/**
475* Encodes a param value for interpolation into a single URL path segment.
476*
477* Escapes characters that would break the path (`/ ? # %`, whitespace,
478* non-ASCII, …) while leaving characters that RFC 3986 permits literally in a
479* path segment untouched. Escaping those would needlessly rewrite URLs — e.g.
480* a semver build param `1.0.0+1` would become `1.0.0%2B1` even though browsers
481* display and match the `+` literally in `location.pathname`.
482*
483* See [RFC 3986 §3.3](https://datatracker.ietf.org/doc/html/rfc3986#section-3.3))
484*
485* @param value The param value to encode.
486* @returns The encoded value, safe for use as a single path segment.
487*/
488function encodePathParam(value) {
489 return encodeURIComponent(value).replace(/%(?:24|26|2B|2C|3A|3B|3D|40)/g, (match) => PATH_PARAM_OVERESCAPED[match]);
490}
491/**
492* Performs pattern matching on a URL pathname and returns information about
493* the match.
494*
495* @public
496* @category Utils
497* @param pattern The pattern to match against the URL pathname. This can be a
498* string or a {@link PathPattern} object. If a string is provided, it will be
499* treated as a pattern with `caseSensitive` set to `false` and `end` set to
500* `true`.
501* @param pathname The URL pathname to match against the pattern.
502* @returns A path match object if the pattern matches the pathname,
503* or `null` if it does not match.
504*/
505function matchPath(pattern, pathname) {
506 if (typeof pattern === "string") pattern = {
507 path: pattern,
508 caseSensitive: false,
509 end: true
510 };
511 let [matcher, compiledParams] = compilePath(pattern.path, pattern.caseSensitive, pattern.end);
512 return matchPathImpl(pattern, pathname, matcher, compiledParams);
513}
514function matchPathImpl(pattern, pathname, matcher, compiledParams) {
515 let match = pathname.match(matcher);
516 if (!match) return null;
517 let matchedPathname = match[0];
518 let pathnameBase = matchedPathname.replace(/(.)\/+$/, "$1");
519 let captureGroups = match.slice(1);
520 return {
521 params: compiledParams.reduce((memo, { paramName, isOptional }, index) => {
522 if (paramName === "*") {
523 let splatValue = captureGroups[index] || "";
524 pathnameBase = matchedPathname.slice(0, matchedPathname.length - splatValue.length).replace(/(.)\/+$/, "$1");
525 }
526 const value = captureGroups[index];
527 if (isOptional && !value) memo[paramName] = void 0;
528 else memo[paramName] = (value || "").replace(/%2F/g, "/");
529 return memo;
530 }, {}),
531 pathname: matchedPathname,
532 pathnameBase,
533 pattern
534 };
535}
536function compilePath(path, caseSensitive = false, end = true) {
537 warning(path === "*" || !path.endsWith("*") || path.endsWith("/*"), `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(/\*$/, "/*")}".`);
538 let params = [];
539 let regexpSource = "^" + path.replace(/\/*\*?$/, "").replace(/^\/*/, "/").replace(/[\\.*+^${}|()[\]]/g, "\\$&").replace(/\/:([\w-]+)(\?)?/g, (match, paramName, isOptional, index, str) => {
540 params.push({
541 paramName,
542 isOptional: isOptional != null
543 });
544 if (isOptional) {
545 let nextChar = str.charAt(index + match.length);
546 if (nextChar && nextChar !== "/") return "/([^\\/]*)";
547 return "(?:/([^\\/]*))?";
548 }
549 return "/([^\\/]+)";
550 }).replace(/\/([\w-]+)\?(?=\/|$|\()/g, "(?:/$1)?");
551 if (path.endsWith("*")) {
552 params.push({ paramName: "*" });
553 regexpSource += path === "*" || path === "/*" ? "(.*)$" : "(?:\\/(.+)|\\/*)$";
554 } else if (end) regexpSource += "\\/*$";
555 else if (path !== "" && path !== "/") regexpSource += "(?:(?=\\/|$))";
556 return [new RegExp(regexpSource, caseSensitive ? void 0 : "i"), params];
557}
558function decodePath(value) {
559 try {
560 return value.split("/").map((v) => decodeURIComponent(v).replace(/\//g, "%2F")).join("/");
561 } catch (error) {
562 warning(false, `The URL path "${value}" could not be decoded because it is a malformed URL segment. This is probably due to a bad percent encoding (${error}).`);
563 return value;
564 }
565}
566function stripBasename(pathname, basename) {
567 if (basename === "/") return pathname;
568 if (!pathname.toLowerCase().startsWith(basename.toLowerCase())) return null;
569 let startIndex = basename.endsWith("/") ? basename.length - 1 : basename.length;
570 let nextChar = pathname.charAt(startIndex);
571 if (nextChar && nextChar !== "/") return null;
572 return pathname.slice(startIndex) || "/";
573}
574function prependBasename({ basename, pathname }) {
575 return pathname === "/" ? basename : joinPaths([basename, pathname]);
576}
577const isAbsoluteUrl = (url) => ABSOLUTE_URL_REGEX.test(url);
578/**
579* Returns a resolved {@link Path} object relative to the given pathname.
580*
581* @public
582* @category Utils
583* @param to The path to resolve, either a string or a partial {@link Path}
584* object.
585* @param fromPathname The pathname to resolve the path from. Defaults to `/`.
586* @returns A {@link Path} object with the resolved pathname, search, and hash.
587*/
588function resolvePath(to, fromPathname = "/") {
589 let { pathname: toPathname, search = "", hash = "" } = typeof to === "string" ? parsePath(to) : to;
590 let pathname;
591 if (toPathname) {
592 toPathname = removeDoubleSlashes(toPathname);
593 if (toPathname.startsWith("/")) pathname = resolvePathname(toPathname.substring(1), "/");
594 else pathname = resolvePathname(toPathname, fromPathname);
595 } else pathname = fromPathname;
596 return {
597 pathname,
598 search: normalizeSearch(search),
599 hash: normalizeHash(hash)
600 };
601}
602function resolvePathname(relativePath, fromPathname) {
603 let segments = removeTrailingSlash(fromPathname).split("/");
604 relativePath.split("/").forEach((segment) => {
605 if (segment === "..") {
606 if (segments.length > 1) segments.pop();
607 } else if (segment !== ".") segments.push(segment);
608 });
609 return segments.length > 1 ? segments.join("/") : "/";
610}
611function getInvalidPathError(char, field, dest, path) {
612 return `Cannot include a '${char}' character in a manually specified \`to.${field}\` field [${JSON.stringify(path)}]. 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.`;
613}
614function getPathContributingMatches(matches) {
615 return matches.filter((match, index) => index === 0 || match.route.path && match.route.path.length > 0);
616}
617function getResolveToMatches(matches) {
618 let pathMatches = getPathContributingMatches(matches);
619 return pathMatches.map((match, idx) => idx === pathMatches.length - 1 ? match.pathname : match.pathnameBase);
620}
621function resolveTo(toArg, routePathnames, locationPathname, isPathRelative = false) {
622 let to;
623 if (typeof toArg === "string") to = parsePath(toArg);
624 else {
625 to = { ...toArg };
626 invariant$1(!to.pathname || !to.pathname.includes("?"), getInvalidPathError("?", "pathname", "search", to));
627 invariant$1(!to.pathname || !to.pathname.includes("#"), getInvalidPathError("#", "pathname", "hash", to));
628 invariant$1(!to.search || !to.search.includes("#"), getInvalidPathError("#", "search", "hash", to));
629 }
630 let isEmptyPath = toArg === "" || to.pathname === "";
631 let toPathname = isEmptyPath ? "/" : to.pathname;
632 let from;
633 if (toPathname == null) from = locationPathname;
634 else {
635 let routePathnameIndex = routePathnames.length - 1;
636 if (!isPathRelative && toPathname.startsWith("..")) {
637 let toSegments = toPathname.split("/");
638 while (toSegments[0] === "..") {
639 toSegments.shift();
640 routePathnameIndex -= 1;
641 }
642 to.pathname = toSegments.join("/");
643 }
644 from = routePathnameIndex >= 0 ? routePathnames[routePathnameIndex] : "/";
645 }
646 let path = resolvePath(to, from);
647 let hasExplicitTrailingSlash = toPathname && toPathname !== "/" && toPathname.endsWith("/");
648 let hasCurrentTrailingSlash = (isEmptyPath || toPathname === ".") && locationPathname.endsWith("/");
649 if (!path.pathname.endsWith("/") && (hasExplicitTrailingSlash || hasCurrentTrailingSlash)) path.pathname += "/";
650 return path;
651}
652const removeDoubleSlashes = (path) => path.replace(/[\\/]{2,}/g, "/");
653const joinPaths = (paths) => removeDoubleSlashes(paths.join("/"));
654const removeTrailingSlash = (path) => path.replace(/\/+$/, "");
655const normalizePathname = (pathname) => removeTrailingSlash(pathname).replace(/^\/*/, "/");
656const normalizeSearch = (search) => !search || search === "?" ? "" : search.startsWith("?") ? search : "?" + search;
657const normalizeHash = (hash) => !hash || hash === "#" ? "" : hash.startsWith("#") ? hash : "#" + hash;
658var DataWithResponseInit = class {
659 type = "DataWithResponseInit";
660 data;
661 init;
662 constructor(data, init) {
663 this.data = data;
664 this.init = init || null;
665 }
666};
667/**
668* Create "responses" that contain `headers`/`status` without forcing
669* serialization into an actual [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response)
670*
671* @example
672* import { data } from "react-router";
673*
674* export async function action({ request }: Route.ActionArgs) {
675* let formData = await request.formData();
676* let item = await createItem(formData);
677* return data(item, {
678* headers: { "X-Custom-Header": "value" }
679* status: 201,
680* });
681* }
682*
683* @public
684* @category Utils
685* @mode framework
686* @mode data
687* @param data The data to be included in the response.
688* @param init The status code or a `ResponseInit` object to be included in the
689* response.
690* @returns A {@link DataWithResponseInit} instance containing the data and
691* response init.
692*/
693function data(data, init) {
694 return new DataWithResponseInit(data, typeof init === "number" ? { status: init } : init);
695}
696/**
697* A redirect [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response).
698* Sets the status code and the [`Location`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Location)
699* header. Defaults to [`302 Found`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/302).
700*
701* This utility accepts absolute URLs and can navigate to external domains, so
702* the application should validate any user-supplied inputs to redirects.
703*
704* @example
705* import { redirect } from "react-router";
706*
707* export async function loader({ request }: Route.LoaderArgs) {
708* if (!isLoggedIn(request))
709* throw redirect("/login");
710* }
711*
712* // ...
713* }
714*
715* @public
716* @category Utils
717* @mode framework
718* @mode data
719* @param url The URL to redirect to.
720* @param init The status code or a `ResponseInit` object to be included in the
721* response.
722* @returns A [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response)
723* object with the redirect status and [`Location`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Location)
724* header.
725*/
726const redirect$1 = (url, init = 302) => {
727 let responseInit = init;
728 if (typeof responseInit === "number") responseInit = { status: responseInit };
729 else if (typeof responseInit.status === "undefined") responseInit.status = 302;
730 let headers = new Headers(responseInit.headers);
731 headers.set("Location", url);
732 return new Response(null, {
733 ...responseInit,
734 headers
735 });
736};
737/**
738* A redirect [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response)
739* that will force a document reload to the new location. Sets the status code
740* and the [`Location`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Location)
741* header. Defaults to [`302 Found`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/302).
742*
743* This utility accepts absolute URLs and can navigate to external domains, so
744* the application should validate any user-supplied inputs to redirects.
745*
746* ```tsx filename=routes/logout.tsx
747* import { redirectDocument } from "react-router";
748*
749* import { destroySession } from "../sessions.server";
750*
751* export async function action({ request }: Route.ActionArgs) {
752* let session = await getSession(request.headers.get("Cookie"));
753* return redirectDocument("/", {
754* headers: { "Set-Cookie": await destroySession(session) }
755* });
756* }
757* ```
758*
759* @public
760* @category Utils
761* @mode framework
762* @mode data
763* @param url The URL to redirect to.
764* @param init The status code or a `ResponseInit` object to be included in the
765* response.
766* @returns A [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response)
767* object with the redirect status and [`Location`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Location)
768* header.
769*/
770const redirectDocument$1 = (url, init) => {
771 let response = redirect$1(url, init);
772 response.headers.set("X-Remix-Reload-Document", "true");
773 return response;
774};
775/**
776* A redirect [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response)
777* that will perform a [`history.replaceState`](https://developer.mozilla.org/en-US/docs/Web/API/History/replaceState)
778* instead of a [`history.pushState`](https://developer.mozilla.org/en-US/docs/Web/API/History/pushState)
779* for client-side navigation redirects. Sets the status code and the [`Location`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Location)
780* header. Defaults to [`302 Found`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/302).
781*
782* @example
783* import { replace } from "react-router";
784*
785* export async function loader() {
786* return replace("/new-location");
787* }
788*
789* @public
790* @category Utils
791* @mode framework
792* @mode data
793* @param url The URL to redirect to.
794* @param init The status code or a `ResponseInit` object to be included in the
795* response.
796* @returns A [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response)
797* object with the redirect status and [`Location`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Location)
798* header.
799*/
800const replace$1 = (url, init) => {
801 let response = redirect$1(url, init);
802 response.headers.set("X-Remix-Replace", "true");
803 return response;
804};
805var ErrorResponseImpl = class {
806 status;
807 statusText;
808 data;
809 error;
810 internal;
811 constructor(status, statusText, data, internal = false) {
812 this.status = status;
813 this.statusText = statusText || "";
814 this.internal = internal;
815 if (data instanceof Error) {
816 this.data = data.toString();
817 this.error = data;
818 } else this.data = data;
819 }
820};
821/**
822* Check if the given error is an {@link ErrorResponse} generated from a 4xx/5xx
823* [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response)
824* thrown from an [`action`](../../start/framework/route-module#action) or
825* [`loader`](../../start/framework/route-module#loader) function.
826*
827* @example
828* import { isRouteErrorResponse } from "react-router";
829*
830* export function ErrorBoundary({ error }: Route.ErrorBoundaryProps) {
831* if (isRouteErrorResponse(error)) {
832* return (
833* <>
834* <p>Error: `${error.status}: ${error.statusText}`</p>
835* <p>{error.data}</p>
836* </>
837* );
838* }
839*
840* return (
841* <p>Error: {error instanceof Error ? error.message : "Unknown Error"}</p>
842* );
843* }
844*
845* @public
846* @category Utils
847* @mode framework
848* @mode data
849* @param error The error to check.
850* @returns `true` if the error is an {@link ErrorResponse}, `false` otherwise.
851*/
852function isRouteErrorResponse(error) {
853 return error != null && typeof error.status === "number" && typeof error.statusText === "string" && typeof error.internal === "boolean" && "data" in error;
854}
855function getRoutePattern(matches) {
856 return joinPaths(matches.map((m) => m.route.path).filter(Boolean)) || "/";
857}
858function createDataFunctionUrl(request, path) {
859 let url = new URL(typeof request === "string" || request instanceof URL ? request : request.url);
860 let parsed = typeof path === "string" ? parsePath(path) : path;
861 url.pathname = parsed.pathname || "/";
862 if (parsed.search) {
863 let searchParams = new URLSearchParams(parsed.search);
864 let indexValues = searchParams.getAll("index");
865 searchParams.delete("index");
866 for (let value of indexValues.filter(Boolean)) searchParams.append("index", value);
867 let search = searchParams.toString();
868 url.search = search ? `?${search}` : "";
869 } else url.search = "";
870 url.hash = parsed.hash || "";
871 return url;
872}
873typeof window !== "undefined" && typeof window.document !== "undefined" && window.document.createElement;
874//#endregion
875//#region lib/router/instrumentation.ts
876const UninstrumentedSymbol = Symbol("Uninstrumented");
877function getRouteInstrumentationUpdates(fns, route) {
878 let aggregated = {
879 lazy: [],
880 "lazy.loader": [],
881 "lazy.action": [],
882 "lazy.middleware": [],
883 middleware: [],
884 loader: [],
885 action: []
886 };
887 fns.forEach((fn) => fn({
888 id: route.id,
889 index: route.index,
890 path: route.path,
891 instrument(i) {
892 if (i.lazy != null) aggregated.lazy.push(i.lazy);
893 if (i["lazy.loader"] != null) aggregated["lazy.loader"].push(i["lazy.loader"]);
894 if (i["lazy.action"] != null) aggregated["lazy.action"].push(i["lazy.action"]);
895 if (i["lazy.middleware"] != null) aggregated["lazy.middleware"].push(i["lazy.middleware"]);
896 if (i.middleware != null) aggregated.middleware.push(i.middleware);
897 if (i.loader != null) aggregated.loader.push(i.loader);
898 if (i.action != null) aggregated.action.push(i.action);
899 }
900 }));
901 let updates = {};
902 if (typeof route.lazy === "function" && aggregated.lazy.length > 0) {
903 let lazy = route.lazy;
904 updates.lazy = async (...args) => {
905 return throwOrReturnResult(await recurseRight(aggregated.lazy, void 0, () => lazy(...args), getInstrumentationInnerResult));
906 };
907 }
908 if (typeof route.lazy === "object") {
909 let lazyObject = route.lazy;
910 if (typeof lazyObject.middleware === "function" && aggregated["lazy.middleware"].length > 0) {
911 let middleware = lazyObject.middleware;
912 updates.lazy = Object.assign(updates.lazy || {}, { middleware: async (...args) => {
913 return throwOrReturnResult(await recurseRight(aggregated["lazy.middleware"], void 0, () => middleware(...args), getInstrumentationInnerResult));
914 } });
915 }
916 if (typeof lazyObject.loader === "function" && aggregated["lazy.loader"].length > 0) {
917 let loader = lazyObject.loader;
918 updates.lazy = Object.assign(updates.lazy || {}, { loader: async (...args) => {
919 return throwOrReturnResult(await recurseRight(aggregated["lazy.loader"], void 0, () => loader(...args), getInstrumentationInnerResult));
920 } });
921 }
922 if (typeof lazyObject.action === "function" && aggregated["lazy.action"].length > 0) {
923 let action = lazyObject.action;
924 updates.lazy = Object.assign(updates.lazy || {}, { action: async (...args) => {
925 return throwOrReturnResult(await recurseRight(aggregated["lazy.action"], void 0, () => action(...args), getInstrumentationInnerResult));
926 } });
927 }
928 }
929 if (typeof route.loader === "function" && aggregated.loader.length > 0) {
930 let original = getUninstrumentedHandler(route.loader);
931 let instrumented = async (...args) => {
932 return throwOrReturnResult(await recurseRight(aggregated.loader, getHandlerInfo(args[0]), () => original(...args), getInstrumentationInnerResult));
933 };
934 if (original.hydrate === true) instrumented.hydrate = true;
935 setUninstrumentedHandler(instrumented, original);
936 updates.loader = instrumented;
937 }
938 if (typeof route.action === "function" && aggregated.action.length > 0) {
939 let original = getUninstrumentedHandler(route.action);
940 let instrumented = async (...args) => {
941 return throwOrReturnResult(await recurseRight(aggregated.action, getHandlerInfo(args[0]), () => original(...args), getInstrumentationInnerResult));
942 };
943 setUninstrumentedHandler(instrumented, original);
944 updates.action = instrumented;
945 }
946 if (route.middleware && route.middleware.length > 0 && aggregated.middleware.length > 0) updates.middleware = route.middleware.map((middleware) => {
947 let original = getUninstrumentedHandler(middleware);
948 let instrumented = async (...args) => {
949 return throwOrReturnResult(await recurseRight(aggregated.middleware, getHandlerInfo(args[0]), () => original(...args), getInstrumentationInnerResult));
950 };
951 setUninstrumentedHandler(instrumented, original);
952 return instrumented;
953 });
954 return updates;
955}
956function getUninstrumentedHandler(handler) {
957 return handler[UninstrumentedSymbol] ?? handler;
958}
959function setUninstrumentedHandler(handler, uninstrumentedHandler) {
960 handler[UninstrumentedSymbol] = uninstrumentedHandler;
961}
962function throwOrReturnResult(result) {
963 if (result.type === "error") throw result.value;
964 return result.value;
965}
966async function recurseRight(impls, info, handler, getInnerResult, state = {
967 result: null,
968 innerResult: null
969}, index = impls.length - 1) {
970 let impl = impls[index];
971 if (!impl) {
972 try {
973 state.result = {
974 type: "success",
975 value: await handler()
976 };
977 } catch (e) {
978 state.result = {
979 type: "error",
980 value: e
981 };
982 }
983 state.innerResult = getInnerResult(state.result, info);
984 } else {
985 let handlerPromise = void 0;
986 let callHandler = async () => {
987 if (handlerPromise) console.error("You cannot call instrumented handlers more than once");
988 else handlerPromise = recurseRight(impls, info, handler, getInnerResult, state, index - 1);
989 await handlerPromise;
990 invariant$1(state.innerResult, "Expected an inner result");
991 return state.innerResult;
992 };
993 try {
994 await impl(callHandler, info);
995 } catch (e) {
996 console.error("An instrumentation function threw an error:", e);
997 }
998 if (!handlerPromise) await callHandler();
999 await handlerPromise;
1000 }
1001 if (state.result) return state.result;
1002 state.result = {
1003 type: "error",
1004 value: /* @__PURE__ */ new Error("No result assigned in instrumentation chain.")
1005 };
1006 state.innerResult = getInnerResult(state.result, info);
1007 return state.result;
1008}
1009function getInstrumentationInnerResult(result) {
1010 if (result.type === "error" && result.value instanceof Error) return {
1011 status: "error",
1012 error: result.value
1013 };
1014 return {
1015 status: "success",
1016 error: void 0
1017 };
1018}
1019function getHandlerInfo(args) {
1020 let { request, context, params } = args;
1021 return {
1022 ...args,
1023 request: getReadonlyRequest(request),
1024 params: { ...params },
1025 context: getReadonlyContext(context)
1026 };
1027}
1028function getReadonlyRequest(request) {
1029 return {
1030 method: request.method,
1031 url: request.url,
1032 headers: { get: (...args) => request.headers.get(...args) }
1033 };
1034}
1035function getReadonlyContext(context) {
1036 return { get: (ctx) => context.get(ctx) };
1037}
1038//#endregion
1039//#region lib/router/router.ts
1040const validMutationMethodsArr = [
1041 "POST",
1042 "PUT",
1043 "PATCH",
1044 "DELETE"
1045];
1046const validMutationMethods = new Set(validMutationMethodsArr);
1047const validRequestMethodsArr = ["GET", ...validMutationMethodsArr];
1048const validRequestMethods = new Set(validRequestMethodsArr);
1049const redirectStatusCodes = new Set([
1050 301,
1051 302,
1052 303,
1053 307,
1054 308
1055]);
1056const ResetLoaderDataSymbol = Symbol("ResetLoaderData");
1057/**
1058* Create a static handler to perform server-side data loading
1059*
1060* @example
1061* export async function handleRequest(request: Request) {
1062* let { query, dataRoutes } = createStaticHandler(routes);
1063* let context = await query(request);
1064*
1065* if (context instanceof Response) {
1066* return context;
1067* }
1068*
1069* let router = createStaticRouter(dataRoutes, context);
1070* return new Response(
1071* ReactDOMServer.renderToString(<StaticRouterProvider ... />),
1072* { headers: { "Content-Type": "text/html" } }
1073* );
1074* }
1075*
1076* @public
1077* @category Data Routers
1078* @mode data
1079* @param routes The {@link RouteObject | route objects} to create a static
1080* handler for
1081* @param opts Options
1082* @param opts.basename The base URL for the static handler (default: `/`)
1083* @param opts.future Future flags for the static handler
1084* @returns A static handler that can be used to query data for the provided
1085* routes
1086*/
1087function createStaticHandler(routes, opts) {
1088 invariant$1(routes.length > 0, "You must provide a non-empty routes array to createStaticHandler");
1089 let manifest = {};
1090 let basename = (opts ? opts.basename : null) || "/";
1091 let _mapRouteProperties = opts?.mapRouteProperties;
1092 let mapRouteProperties = _mapRouteProperties ? _mapRouteProperties : () => ({});
1093 ({ ...opts?.future });
1094 if (opts?.instrumentations) {
1095 let instrumentations = opts.instrumentations;
1096 mapRouteProperties = (route) => {
1097 return {
1098 ..._mapRouteProperties?.(route),
1099 ...getRouteInstrumentationUpdates(instrumentations.map((i) => i.route).filter(Boolean), route)
1100 };
1101 };
1102 }
1103 let dataRoutes = convertRoutesToDataRoutes(routes, mapRouteProperties, void 0, manifest);
1104 let routeBranches = flattenAndRankRoutes(dataRoutes);
1105 /**
1106 * The query() method is intended for document requests, in which we want to
1107 * call an optional action and potentially multiple loaders for all nested
1108 * routes. It returns a StaticHandlerContext object, which is very similar
1109 * to the router state (location, loaderData, actionData, errors, etc.) and
1110 * also adds SSR-specific information such as the statusCode and headers
1111 * from action/loaders Responses.
1112 *
1113 * It _should_ never throw and should report all errors through the
1114 * returned handlerContext.errors object, properly associating errors to
1115 * their error boundary. Additionally, it tracks _deepestRenderedBoundaryId
1116 * which can be used to emulate React error boundaries during SSR by performing
1117 * a second pass only down to the boundaryId.
1118 *
1119 * The one exception where we do not return a StaticHandlerContext is when a
1120 * redirect response is returned or thrown from any action/loader. We
1121 * propagate that out and return the raw Response so the HTTP server can
1122 * return it directly.
1123 *
1124 * - `opts.requestContext` is an optional server context that will be passed
1125 * to actions/loaders in the `context` parameter
1126 * - `opts.skipLoaderErrorBubbling` is an optional parameter that will prevent
1127 * the bubbling of errors which allows single-fetch-type implementations
1128 * where the client will handle the bubbling and we may need to return data
1129 * for the handling route
1130 */
1131 async function query(request, { requestContext, filterMatchesToLoad, skipLoaderErrorBubbling, skipRevalidation, dataStrategy, generateMiddlewareResponse, normalizePath } = {}) {
1132 let normalizePathImpl = normalizePath || defaultNormalizePath;
1133 let method = request.method;
1134 let location = createLocation("", normalizePathImpl(request), null, "default");
1135 let matches = matchRoutesImpl(dataRoutes, location, basename, false, routeBranches);
1136 requestContext = requestContext != null ? requestContext : new RouterContextProvider();
1137 if (!isValidMethod(method) && method !== "HEAD") {
1138 let error = getInternalRouterError(405, { method });
1139 let { matches: methodNotAllowedMatches, route } = getShortCircuitMatches(dataRoutes);
1140 let staticContext = {
1141 basename,
1142 location,
1143 matches: methodNotAllowedMatches,
1144 loaderData: {},
1145 actionData: null,
1146 errors: { [route.id]: error },
1147 statusCode: error.status,
1148 loaderHeaders: {},
1149 actionHeaders: {}
1150 };
1151 return generateMiddlewareResponse ? generateMiddlewareResponse(() => Promise.resolve(staticContext)) : staticContext;
1152 } else if (!matches) {
1153 let error = getInternalRouterError(404, { pathname: location.pathname });
1154 let { matches: notFoundMatches, route } = getShortCircuitMatches(dataRoutes);
1155 let staticContext = {
1156 basename,
1157 location,
1158 matches: notFoundMatches,
1159 loaderData: {},
1160 actionData: null,
1161 errors: { [route.id]: error },
1162 statusCode: error.status,
1163 loaderHeaders: {},
1164 actionHeaders: {}
1165 };
1166 return generateMiddlewareResponse ? generateMiddlewareResponse(() => Promise.resolve(staticContext)) : staticContext;
1167 }
1168 if (generateMiddlewareResponse) {
1169 invariant$1(requestContext instanceof RouterContextProvider, "When using middleware in `staticHandler.query()`, any provided `requestContext` must be an instance of `RouterContextProvider`");
1170 try {
1171 await loadLazyMiddlewareForMatches(matches, manifest, mapRouteProperties);
1172 let renderedStaticContext;
1173 let response = await runServerMiddlewarePipeline({
1174 request,
1175 url: createDataFunctionUrl(request, location),
1176 pattern: getRoutePattern(matches),
1177 matches,
1178 params: matches[0].params,
1179 context: requestContext
1180 }, async () => {
1181 return await generateMiddlewareResponse(async (revalidationRequest, opts = {}) => {
1182 let result = await queryImpl(revalidationRequest, location, matches, requestContext, dataStrategy || null, skipLoaderErrorBubbling === true, null, "filterMatchesToLoad" in opts ? opts.filterMatchesToLoad ?? null : filterMatchesToLoad ?? null, skipRevalidation === true);
1183 if (isResponse(result)) return result;
1184 renderedStaticContext = {
1185 location,
1186 basename,
1187 ...result
1188 };
1189 return renderedStaticContext;
1190 });
1191 }, async (error, routeId) => {
1192 if (isRedirectResponse(error)) return error;
1193 if (isResponse(error)) try {
1194 error = new ErrorResponseImpl(error.status, error.statusText, await parseResponseBody(error));
1195 } catch (e) {
1196 error = e;
1197 }
1198 if (isDataWithResponseInit(error)) error = dataWithResponseInitToErrorResponse(error);
1199 if (renderedStaticContext) {
1200 if (routeId in renderedStaticContext.loaderData) renderedStaticContext.loaderData[routeId] = void 0;
1201 let staticContext = getStaticContextFromError(dataRoutes, renderedStaticContext, error, skipLoaderErrorBubbling ? routeId : findNearestBoundary(matches, routeId).route.id);
1202 return generateMiddlewareResponse(() => Promise.resolve(staticContext));
1203 } else {
1204 let staticContext = {
1205 matches,
1206 location,
1207 basename,
1208 loaderData: {},
1209 actionData: null,
1210 errors: { [skipLoaderErrorBubbling ? routeId : findNearestBoundary(matches, matches.find((m) => m.route.id === routeId || m.route.loader)?.route.id || routeId).route.id]: error },
1211 statusCode: isRouteErrorResponse(error) ? error.status : 500,
1212 actionHeaders: {},
1213 loaderHeaders: {}
1214 };
1215 return generateMiddlewareResponse(() => Promise.resolve(staticContext));
1216 }
1217 });
1218 invariant$1(isResponse(response), "Expected a response in query()");
1219 return response;
1220 } catch (e) {
1221 if (isResponse(e)) return e;
1222 throw e;
1223 }
1224 }
1225 let result = await queryImpl(request, location, matches, requestContext, dataStrategy || null, skipLoaderErrorBubbling === true, null, filterMatchesToLoad || null, skipRevalidation === true);
1226 if (isResponse(result)) return result;
1227 return {
1228 location,
1229 basename,
1230 ...result
1231 };
1232 }
1233 /**
1234 * The queryRoute() method is intended for targeted route requests, either
1235 * for fetch ?_data requests or resource route requests. In this case, we
1236 * are only ever calling a single action or loader, and we are returning the
1237 * returned value directly. In most cases, this will be a Response returned
1238 * from the action/loader, but it may be a primitive or other value as well -
1239 * and in such cases the calling context should handle that accordingly.
1240 *
1241 * We do respect the throw/return differentiation, so if an action/loader
1242 * throws, then this method will throw the value. This is important so we
1243 * can do proper boundary identification in Remix where a thrown Response
1244 * must go to the Catch Boundary but a returned Response is happy-path.
1245 *
1246 * One thing to note is that any Router-initiated Errors that make sense
1247 * to associate with a status code will be thrown as an ErrorResponse
1248 * instance which include the raw Error, such that the calling context can
1249 * serialize the error as they see fit while including the proper response
1250 * code. Examples here are 404 and 405 errors that occur prior to reaching
1251 * any user-defined loaders.
1252 *
1253 * - `opts.routeId` allows you to specify the specific route handler to call.
1254 * If not provided the handler will determine the proper route by matching
1255 * against `request.url`
1256 * - `opts.requestContext` is an optional server context that will be passed
1257 * to actions/loaders in the `context` parameter
1258 */
1259 async function queryRoute(request, { routeId, requestContext, dataStrategy, generateMiddlewareResponse, normalizePath } = {}) {
1260 let normalizePathImpl = normalizePath || defaultNormalizePath;
1261 let method = request.method;
1262 let location = createLocation("", normalizePathImpl(request), null, "default");
1263 let matches = matchRoutesImpl(dataRoutes, location, basename, false, routeBranches);
1264 requestContext = requestContext != null ? requestContext : new RouterContextProvider();
1265 if (!isValidMethod(method) && method !== "HEAD" && method !== "OPTIONS") throw getInternalRouterError(405, { method });
1266 else if (!matches) throw getInternalRouterError(404, { pathname: location.pathname });
1267 let match = routeId ? matches.find((m) => m.route.id === routeId) : getTargetMatch(matches, location);
1268 if (routeId && !match) throw getInternalRouterError(403, {
1269 pathname: location.pathname,
1270 routeId
1271 });
1272 else if (!match) throw getInternalRouterError(404, { pathname: location.pathname });
1273 if (generateMiddlewareResponse) {
1274 invariant$1(requestContext instanceof RouterContextProvider, "When using middleware in `staticHandler.queryRoute()`, any provided `requestContext` must be an instance of `RouterContextProvider`");
1275 await loadLazyMiddlewareForMatches(matches, manifest, mapRouteProperties);
1276 return await runServerMiddlewarePipeline({
1277 request,
1278 url: createDataFunctionUrl(request, location),
1279 pattern: getRoutePattern(matches),
1280 matches,
1281 params: matches[0].params,
1282 context: requestContext
1283 }, async () => {
1284 return await generateMiddlewareResponse(async (innerRequest) => {
1285 let processed = handleQueryResult(await queryImpl(innerRequest, location, matches, requestContext, dataStrategy || null, false, match, null, false));
1286 return isResponse(processed) ? processed : typeof processed === "string" ? new Response(processed) : Response.json(processed);
1287 });
1288 }, (error) => {
1289 if (isDataWithResponseInit(error)) return Promise.resolve(dataWithResponseInitToResponse(error));
1290 if (isResponse(error)) return Promise.resolve(error);
1291 throw error;
1292 });
1293 }
1294 return handleQueryResult(await queryImpl(request, location, matches, requestContext, dataStrategy || null, false, match, null, false));
1295 function handleQueryResult(result) {
1296 if (isResponse(result)) return result;
1297 let error = result.errors ? Object.values(result.errors)[0] : void 0;
1298 if (error !== void 0) throw error;
1299 if (result.actionData) return Object.values(result.actionData)[0];
1300 if (result.loaderData) return Object.values(result.loaderData)[0];
1301 }
1302 }
1303 async function queryImpl(request, location, matches, requestContext, dataStrategy, skipLoaderErrorBubbling, routeMatch, filterMatchesToLoad, skipRevalidation) {
1304 invariant$1(request.signal, "query()/queryRoute() requests must contain an AbortController signal");
1305 try {
1306 if (isMutationMethod(request.method)) return await submit(request, location, matches, routeMatch || getTargetMatch(matches, location), requestContext, dataStrategy, skipLoaderErrorBubbling, routeMatch != null, filterMatchesToLoad, skipRevalidation);
1307 let result = await loadRouteData(request, location, matches, requestContext, dataStrategy, skipLoaderErrorBubbling, routeMatch, filterMatchesToLoad);
1308 return isResponse(result) ? result : {
1309 ...result,
1310 actionData: null,
1311 actionHeaders: {}
1312 };
1313 } catch (e) {
1314 if (isDataStrategyResult(e) && isResponse(e.result)) {
1315 if (e.type === "error") throw e.result;
1316 return e.result;
1317 }
1318 if (isRedirectResponse(e)) return e;
1319 throw e;
1320 }
1321 }
1322 async function submit(request, location, matches, actionMatch, requestContext, dataStrategy, skipLoaderErrorBubbling, isRouteRequest, filterMatchesToLoad, skipRevalidation) {
1323 let result;
1324 if (!actionMatch.route.action && !actionMatch.route.lazy) {
1325 let error = getInternalRouterError(405, {
1326 method: request.method,
1327 pathname: new URL(request.url).pathname,
1328 routeId: actionMatch.route.id
1329 });
1330 if (isRouteRequest) throw error;
1331 result = {
1332 type: "error",
1333 error
1334 };
1335 } else {
1336 result = (await callDataStrategy(request, location, getTargetedDataStrategyMatches(mapRouteProperties, manifest, request, location, matches, actionMatch, [], requestContext), isRouteRequest, requestContext, dataStrategy))[actionMatch.route.id];
1337 if (request.signal.aborted) throwStaticHandlerAbortedError(request, isRouteRequest);
1338 }
1339 if (isRedirectResult(result)) throw new Response(null, {
1340 status: result.response.status,
1341 headers: { Location: result.response.headers.get("Location") }
1342 });
1343 if (isRouteRequest) {
1344 if (isErrorResult(result)) throw result.error;
1345 return {
1346 matches: [actionMatch],
1347 loaderData: {},
1348 actionData: { [actionMatch.route.id]: result.data },
1349 errors: null,
1350 statusCode: 200,
1351 loaderHeaders: {},
1352 actionHeaders: {}
1353 };
1354 }
1355 if (skipRevalidation) if (isErrorResult(result)) {
1356 let boundaryMatch = skipLoaderErrorBubbling ? actionMatch : findNearestBoundary(matches, actionMatch.route.id);
1357 return {
1358 statusCode: isRouteErrorResponse(result.error) ? result.error.status : result.statusCode != null ? result.statusCode : 500,
1359 actionData: null,
1360 actionHeaders: { ...result.headers ? { [actionMatch.route.id]: result.headers } : {} },
1361 matches,
1362 loaderData: {},
1363 errors: { [boundaryMatch.route.id]: result.error },
1364 loaderHeaders: {}
1365 };
1366 } else return {
1367 actionData: { [actionMatch.route.id]: result.data },
1368 actionHeaders: result.headers ? { [actionMatch.route.id]: result.headers } : {},
1369 matches,
1370 loaderData: {},
1371 errors: null,
1372 statusCode: result.statusCode || 200,
1373 loaderHeaders: {}
1374 };
1375 let loaderRequest = new Request(request.url, {
1376 headers: request.headers,
1377 redirect: request.redirect,
1378 signal: request.signal
1379 });
1380 if (isErrorResult(result)) return {
1381 ...await loadRouteData(loaderRequest, location, matches, requestContext, dataStrategy, skipLoaderErrorBubbling, null, filterMatchesToLoad, [(skipLoaderErrorBubbling ? actionMatch : findNearestBoundary(matches, actionMatch.route.id)).route.id, result]),
1382 statusCode: isRouteErrorResponse(result.error) ? result.error.status : result.statusCode != null ? result.statusCode : 500,
1383 actionData: null,
1384 actionHeaders: { ...result.headers ? { [actionMatch.route.id]: result.headers } : {} }
1385 };
1386 return {
1387 ...await loadRouteData(loaderRequest, location, matches, requestContext, dataStrategy, skipLoaderErrorBubbling, null, filterMatchesToLoad),
1388 actionData: { [actionMatch.route.id]: result.data },
1389 ...result.statusCode ? { statusCode: result.statusCode } : {},
1390 actionHeaders: result.headers ? { [actionMatch.route.id]: result.headers } : {}
1391 };
1392 }
1393 async function loadRouteData(request, location, matches, requestContext, dataStrategy, skipLoaderErrorBubbling, routeMatch, filterMatchesToLoad, pendingActionResult) {
1394 let isRouteRequest = routeMatch != null;
1395 if (isRouteRequest && !routeMatch?.route.loader && !routeMatch?.route.lazy) throw getInternalRouterError(400, {
1396 method: request.method,
1397 pathname: new URL(request.url).pathname,
1398 routeId: routeMatch?.route.id
1399 });
1400 let dsMatches;
1401 if (routeMatch) dsMatches = getTargetedDataStrategyMatches(mapRouteProperties, manifest, request, location, matches, routeMatch, [], requestContext);
1402 else {
1403 let maxIdx = pendingActionResult && isErrorResult(pendingActionResult[1]) ? matches.findIndex((m) => m.route.id === pendingActionResult[0]) - 1 : void 0;
1404 let pattern = getRoutePattern(matches);
1405 dsMatches = matches.map((match, index) => {
1406 if (maxIdx != null && index > maxIdx) return getDataStrategyMatch(mapRouteProperties, manifest, request, location, pattern, match, [], requestContext, false);
1407 return getDataStrategyMatch(mapRouteProperties, manifest, request, location, pattern, match, [], requestContext, (match.route.loader || match.route.lazy) != null && (!filterMatchesToLoad || filterMatchesToLoad(match)));
1408 });
1409 }
1410 if (!dataStrategy && !dsMatches.some((m) => m.shouldLoad)) return {
1411 matches,
1412 loaderData: {},
1413 errors: pendingActionResult && isErrorResult(pendingActionResult[1]) ? { [pendingActionResult[0]]: pendingActionResult[1].error } : null,
1414 statusCode: 200,
1415 loaderHeaders: {}
1416 };
1417 let results = await callDataStrategy(request, location, dsMatches, isRouteRequest, requestContext, dataStrategy);
1418 if (request.signal.aborted) throwStaticHandlerAbortedError(request, isRouteRequest);
1419 return {
1420 ...processRouteLoaderData(matches, results, pendingActionResult, true, skipLoaderErrorBubbling),
1421 matches
1422 };
1423 }
1424 async function callDataStrategy(request, location, matches, isRouteRequest, requestContext, dataStrategy) {
1425 let results = await callDataStrategyImpl(dataStrategy || defaultDataStrategy, request, location, matches, null, requestContext, true);
1426 let dataResults = {};
1427 await Promise.all(matches.map(async (match) => {
1428 if (!(match.route.id in results)) return;
1429 let result = results[match.route.id];
1430 if (isRedirectDataStrategyResult(result)) {
1431 let response = result.result;
1432 throw normalizeRelativeRoutingRedirectResponse(response, request, match.route.id, matches, basename);
1433 }
1434 if (isRouteRequest) {
1435 if (isResponse(result.result)) throw result;
1436 else if (isDataWithResponseInit(result.result)) throw dataWithResponseInitToResponse(result.result);
1437 }
1438 dataResults[match.route.id] = await convertDataStrategyResultToDataResult(result);
1439 }));
1440 return dataResults;
1441 }
1442 return {
1443 dataRoutes,
1444 _internalRouteBranches: routeBranches,
1445 query,
1446 queryRoute
1447 };
1448}
1449/**
1450* Given an existing StaticHandlerContext and an error thrown at render time,
1451* provide an updated StaticHandlerContext suitable for a second SSR render
1452*
1453* @category Utils
1454*/
1455function getStaticContextFromError(routes, handlerContext, error, boundaryId) {
1456 let errorBoundaryId = boundaryId || handlerContext._deepestRenderedBoundaryId || routes[0].id;
1457 return {
1458 ...handlerContext,
1459 statusCode: isRouteErrorResponse(error) ? error.status : 500,
1460 errors: { [errorBoundaryId]: error }
1461 };
1462}
1463function throwStaticHandlerAbortedError(request, isRouteRequest) {
1464 if (request.signal.reason !== void 0) throw request.signal.reason;
1465 throw new Error(`${isRouteRequest ? "queryRoute" : "query"}() call aborted without an \`AbortSignal.reason\`: ${request.method} ${request.url}`);
1466}
1467function defaultNormalizePath(request) {
1468 let url = new URL(request.url);
1469 return {
1470 pathname: url.pathname,
1471 search: url.search,
1472 hash: url.hash
1473 };
1474}
1475function normalizeTo(location, matches, basename, to, fromRouteId, relative) {
1476 let contextualMatches;
1477 let activeRouteMatch;
1478 if (fromRouteId) {
1479 contextualMatches = [];
1480 for (let match of matches) {
1481 contextualMatches.push(match);
1482 if (match.route.id === fromRouteId) {
1483 activeRouteMatch = match;
1484 break;
1485 }
1486 }
1487 } else {
1488 contextualMatches = matches;
1489 activeRouteMatch = matches[matches.length - 1];
1490 }
1491 let path = resolveTo(to ? to : ".", getResolveToMatches(contextualMatches), stripBasename(location.pathname, basename) || location.pathname, relative === "path");
1492 if (to == null) {
1493 path.search = location.search;
1494 path.hash = location.hash;
1495 }
1496 if ((to == null || to === "" || to === ".") && activeRouteMatch) {
1497 let nakedIndex = hasNakedIndexQuery(path.search);
1498 if (activeRouteMatch.route.index && !nakedIndex) path.search = path.search ? path.search.replace(/^\?/, "?index&") : "?index";
1499 else if (!activeRouteMatch.route.index && nakedIndex) {
1500 let params = new URLSearchParams(path.search);
1501 let indexValues = params.getAll("index");
1502 params.delete("index");
1503 indexValues.filter((v) => v).forEach((v) => params.append("index", v));
1504 let qs = params.toString();
1505 path.search = qs ? `?${qs}` : "";
1506 }
1507 }
1508 if (basename !== "/") path.pathname = prependBasename({
1509 basename,
1510 pathname: path.pathname
1511 });
1512 return createPath(path);
1513}
1514function shouldRevalidateLoader(loaderMatch, arg) {
1515 if (loaderMatch.route.shouldRevalidate) {
1516 let routeChoice = loaderMatch.route.shouldRevalidate(arg);
1517 if (typeof routeChoice === "boolean") return routeChoice;
1518 }
1519 return arg.defaultShouldRevalidate;
1520}
1521const lazyRoutePropertyCache = /* @__PURE__ */ new WeakMap();
1522const loadLazyRouteProperty = ({ key, route, manifest, mapRouteProperties }) => {
1523 let routeToUpdate = manifest[route.id];
1524 invariant$1(routeToUpdate, "No route found in manifest");
1525 if (!routeToUpdate.lazy || typeof routeToUpdate.lazy !== "object") return;
1526 let lazyFn = routeToUpdate.lazy[key];
1527 if (!lazyFn) return;
1528 let cache = lazyRoutePropertyCache.get(routeToUpdate);
1529 if (!cache) {
1530 cache = {};
1531 lazyRoutePropertyCache.set(routeToUpdate, cache);
1532 }
1533 let cachedPromise = cache[key];
1534 if (cachedPromise) return cachedPromise;
1535 let propertyPromise = (async () => {
1536 let isUnsupported = isUnsupportedLazyRouteObjectKey(key);
1537 let isStaticallyDefined = routeToUpdate[key] !== void 0;
1538 if (isUnsupported) {
1539 warning(!isUnsupported, "Route property " + key + " is not a supported lazy route property. This property will be ignored.");
1540 cache[key] = Promise.resolve();
1541 } else if (isStaticallyDefined) warning(false, `Route "${routeToUpdate.id}" has a static property "${key}" defined. The lazy property will be ignored.`);
1542 else {
1543 let value = await lazyFn();
1544 if (value != null) {
1545 Object.assign(routeToUpdate, { [key]: value });
1546 Object.assign(routeToUpdate, mapRouteProperties(routeToUpdate));
1547 }
1548 }
1549 if (typeof routeToUpdate.lazy === "object") {
1550 routeToUpdate.lazy[key] = void 0;
1551 if (Object.values(routeToUpdate.lazy).every((value) => value === void 0)) routeToUpdate.lazy = void 0;
1552 }
1553 })();
1554 cache[key] = propertyPromise;
1555 return propertyPromise;
1556};
1557const lazyRouteFunctionCache = /* @__PURE__ */ new WeakMap();
1558/**
1559* Execute route.lazy functions to lazily load route modules (loader, action,
1560* shouldRevalidate) and update the routeManifest in place which shares objects
1561* with dataRoutes so those get updated as well.
1562*/
1563function loadLazyRoute(route, type, manifest, mapRouteProperties, lazyRoutePropertiesToSkip) {
1564 let routeToUpdate = manifest[route.id];
1565 invariant$1(routeToUpdate, "No route found in manifest");
1566 if (!route.lazy) return {
1567 lazyRoutePromise: void 0,
1568 lazyHandlerPromise: void 0
1569 };
1570 if (typeof route.lazy === "function") {
1571 let cachedPromise = lazyRouteFunctionCache.get(routeToUpdate);
1572 if (cachedPromise) return {
1573 lazyRoutePromise: cachedPromise,
1574 lazyHandlerPromise: cachedPromise
1575 };
1576 let lazyRoutePromise = (async () => {
1577 invariant$1(typeof route.lazy === "function", "No lazy route function found");
1578 let lazyRoute = await route.lazy();
1579 let routeUpdates = {};
1580 for (let lazyRouteProperty in lazyRoute) {
1581 let lazyValue = lazyRoute[lazyRouteProperty];
1582 if (lazyValue === void 0) continue;
1583 let isUnsupported = isUnsupportedLazyRouteFunctionKey(lazyRouteProperty);
1584 let isStaticallyDefined = routeToUpdate[lazyRouteProperty] !== void 0;
1585 if (isUnsupported) warning(!isUnsupported, "Route property " + lazyRouteProperty + " is not a supported property to be returned from a lazy route function. This property will be ignored.");
1586 else if (isStaticallyDefined) warning(!isStaticallyDefined, `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.`);
1587 else routeUpdates[lazyRouteProperty] = lazyValue;
1588 }
1589 Object.assign(routeToUpdate, routeUpdates);
1590 Object.assign(routeToUpdate, {
1591 ...mapRouteProperties(routeToUpdate),
1592 lazy: void 0
1593 });
1594 })();
1595 lazyRouteFunctionCache.set(routeToUpdate, lazyRoutePromise);
1596 lazyRoutePromise.catch(() => {});
1597 return {
1598 lazyRoutePromise,
1599 lazyHandlerPromise: lazyRoutePromise
1600 };
1601 }
1602 let lazyKeys = Object.keys(route.lazy);
1603 let lazyPropertyPromises = [];
1604 let lazyHandlerPromise = void 0;
1605 for (let key of lazyKeys) {
1606 if (lazyRoutePropertiesToSkip && lazyRoutePropertiesToSkip.includes(key)) continue;
1607 let promise = loadLazyRouteProperty({
1608 key,
1609 route,
1610 manifest,
1611 mapRouteProperties
1612 });
1613 if (promise) {
1614 lazyPropertyPromises.push(promise);
1615 if (key === type) lazyHandlerPromise = promise;
1616 }
1617 }
1618 let lazyRoutePromise = lazyPropertyPromises.length > 0 ? Promise.all(lazyPropertyPromises).then(() => {}) : void 0;
1619 lazyRoutePromise?.catch(() => {});
1620 lazyHandlerPromise?.catch(() => {});
1621 return {
1622 lazyRoutePromise,
1623 lazyHandlerPromise
1624 };
1625}
1626function isNonNullable(value) {
1627 return value !== void 0;
1628}
1629function loadLazyMiddlewareForMatches(matches, manifest, mapRouteProperties) {
1630 let promises = matches.map(({ route }) => {
1631 if (typeof route.lazy !== "object" || !route.lazy.middleware) return;
1632 return loadLazyRouteProperty({
1633 key: "middleware",
1634 route,
1635 manifest,
1636 mapRouteProperties
1637 });
1638 }).filter(isNonNullable);
1639 return promises.length > 0 ? Promise.all(promises) : void 0;
1640}
1641async function defaultDataStrategy(args) {
1642 let matchesToLoad = args.matches.filter((m) => m.shouldLoad);
1643 let keyedResults = {};
1644 (await Promise.all(matchesToLoad.map((m) => m.resolve()))).forEach((result, i) => {
1645 keyedResults[matchesToLoad[i].route.id] = result;
1646 });
1647 return keyedResults;
1648}
1649function runServerMiddlewarePipeline(args, handler, errorHandler) {
1650 return runMiddlewarePipeline(args, handler, processResult, isResponse, errorHandler);
1651 function processResult(result) {
1652 return isDataWithResponseInit(result) ? dataWithResponseInitToResponse(result) : result;
1653 }
1654}
1655function runClientMiddlewarePipeline(args, handler) {
1656 return runMiddlewarePipeline(args, handler, (r) => {
1657 if (isRedirectResponse(r)) throw r;
1658 return r;
1659 }, isDataStrategyResults, errorHandler);
1660 async function errorHandler(error, routeId, nextResult) {
1661 if (nextResult) return Object.assign(nextResult.value, { [routeId]: {
1662 type: "error",
1663 result: error
1664 } });
1665 else {
1666 let { matches } = args;
1667 let maxBoundaryIdx = Math.min(Math.max(matches.findIndex((m) => m.route.id === routeId), 0), Math.max(matches.findIndex((m) => m.shouldCallHandler()), 0));
1668 let deepestRouteId = matches[maxBoundaryIdx].route.id;
1669 for (let match of matches.slice(0, maxBoundaryIdx + 1)) try {
1670 await match._lazyPromises?.route;
1671 } catch {
1672 deepestRouteId = match.route.id;
1673 break;
1674 }
1675 return { [findNearestBoundary(matches, deepestRouteId).route.id]: {
1676 type: "error",
1677 result: error
1678 } };
1679 }
1680 }
1681}
1682async function runMiddlewarePipeline(args, handler, processResult, isResult, errorHandler) {
1683 let { matches, ...dataFnArgs } = args;
1684 return await callRouteMiddleware(dataFnArgs, matches.flatMap((m) => m.route.middleware ? m.route.middleware.map((fn) => [m.route.id, fn]) : []), handler, processResult, isResult, errorHandler);
1685}
1686async function callRouteMiddleware(args, middlewares, handler, processResult, isResult, errorHandler, idx = 0) {
1687 let { request } = args;
1688 if (request.signal.aborted) throw request.signal.reason ?? /* @__PURE__ */ new Error(`Request aborted: ${request.method} ${request.url}`);
1689 let tuple = middlewares[idx];
1690 if (!tuple) return await handler();
1691 let [routeId, middleware] = tuple;
1692 let nextResult;
1693 let next = async () => {
1694 if (nextResult) throw new Error("You may only call `next()` once per middleware");
1695 try {
1696 nextResult = { value: await callRouteMiddleware(args, middlewares, handler, processResult, isResult, errorHandler, idx + 1) };
1697 return nextResult.value;
1698 } catch (error) {
1699 nextResult = { value: await errorHandler(error, routeId, nextResult) };
1700 return nextResult.value;
1701 }
1702 };
1703 try {
1704 let value = await middleware(args, next);
1705 let result = value != null ? processResult(value) : void 0;
1706 if (isResult(result)) return result;
1707 else if (nextResult) return result ?? nextResult.value;
1708 else {
1709 nextResult = { value: await next() };
1710 return nextResult.value;
1711 }
1712 } catch (error) {
1713 return await errorHandler(error, routeId, nextResult);
1714 }
1715}
1716function getDataStrategyMatchLazyPromises(mapRouteProperties, manifest, request, match, lazyRoutePropertiesToSkip) {
1717 let lazyMiddlewarePromise = loadLazyRouteProperty({
1718 key: "middleware",
1719 route: match.route,
1720 manifest,
1721 mapRouteProperties
1722 });
1723 let lazyRoutePromises = loadLazyRoute(match.route, isMutationMethod(request.method) ? "action" : "loader", manifest, mapRouteProperties, lazyRoutePropertiesToSkip);
1724 return {
1725 middleware: lazyMiddlewarePromise,
1726 route: lazyRoutePromises.lazyRoutePromise,
1727 handler: lazyRoutePromises.lazyHandlerPromise
1728 };
1729}
1730function getDataStrategyMatch(mapRouteProperties, manifest, request, path, pattern, match, lazyRoutePropertiesToSkip, scopedContext, shouldLoad, shouldRevalidateArgs = null, callSiteDefaultShouldRevalidate) {
1731 let isUsingNewApi = false;
1732 let _lazyPromises = getDataStrategyMatchLazyPromises(mapRouteProperties, manifest, request, match, lazyRoutePropertiesToSkip);
1733 return {
1734 ...match,
1735 _lazyPromises,
1736 shouldLoad,
1737 shouldRevalidateArgs,
1738 shouldCallHandler(defaultShouldRevalidate) {
1739 isUsingNewApi = true;
1740 if (!shouldRevalidateArgs) return shouldLoad;
1741 if (typeof callSiteDefaultShouldRevalidate === "boolean") return shouldRevalidateLoader(match, {
1742 ...shouldRevalidateArgs,
1743 defaultShouldRevalidate: callSiteDefaultShouldRevalidate
1744 });
1745 if (typeof defaultShouldRevalidate === "boolean") return shouldRevalidateLoader(match, {
1746 ...shouldRevalidateArgs,
1747 defaultShouldRevalidate
1748 });
1749 return shouldRevalidateLoader(match, shouldRevalidateArgs);
1750 },
1751 resolve(handlerOverride) {
1752 let { lazy, loader, middleware } = match.route;
1753 let callHandler = isUsingNewApi || shouldLoad || handlerOverride && !isMutationMethod(request.method) && (lazy || loader);
1754 let isMiddlewareOnlyRoute = middleware && middleware.length > 0 && !loader && !lazy;
1755 if (callHandler && (isMutationMethod(request.method) || !isMiddlewareOnlyRoute)) return callLoaderOrAction({
1756 request,
1757 path,
1758 pattern,
1759 match,
1760 lazyHandlerPromise: _lazyPromises?.handler,
1761 lazyRoutePromise: _lazyPromises?.route,
1762 handlerOverride,
1763 scopedContext
1764 });
1765 return Promise.resolve({
1766 type: "data",
1767 result: void 0
1768 });
1769 }
1770 };
1771}
1772function getTargetedDataStrategyMatches(mapRouteProperties, manifest, request, path, matches, targetMatch, lazyRoutePropertiesToSkip, scopedContext, shouldRevalidateArgs = null) {
1773 return matches.map((match) => {
1774 if (match.route.id !== targetMatch.route.id) return {
1775 ...match,
1776 shouldLoad: false,
1777 shouldRevalidateArgs,
1778 shouldCallHandler: () => false,
1779 _lazyPromises: getDataStrategyMatchLazyPromises(mapRouteProperties, manifest, request, match, lazyRoutePropertiesToSkip),
1780 resolve: () => Promise.resolve({
1781 type: "data",
1782 result: void 0
1783 })
1784 };
1785 return getDataStrategyMatch(mapRouteProperties, manifest, request, path, getRoutePattern(matches), match, lazyRoutePropertiesToSkip, scopedContext, true, shouldRevalidateArgs);
1786 });
1787}
1788async function callDataStrategyImpl(dataStrategyImpl, request, path, matches, fetcherKey, scopedContext, isStaticHandler) {
1789 if (matches.some((m) => m._lazyPromises?.middleware)) await Promise.all(matches.map((m) => m._lazyPromises?.middleware));
1790 let dataStrategyArgs = {
1791 request,
1792 url: createDataFunctionUrl(request, path),
1793 pattern: getRoutePattern(matches),
1794 params: matches[0].params,
1795 context: scopedContext,
1796 matches
1797 };
1798 let runClientMiddleware = isStaticHandler ? () => {
1799 throw new Error("You cannot call `runClientMiddleware()` from a static handler `dataStrategy`. Middleware is run outside of `dataStrategy` during SSR in order to bubble up the Response. You can enable middleware via the `respond` API in `query`/`queryRoute`");
1800 } : (cb) => {
1801 let typedDataStrategyArgs = dataStrategyArgs;
1802 return runClientMiddlewarePipeline(typedDataStrategyArgs, () => {
1803 return cb({
1804 ...typedDataStrategyArgs,
1805 fetcherKey,
1806 runClientMiddleware: () => {
1807 throw new Error("Cannot call `runClientMiddleware()` from within an `runClientMiddleware` handler");
1808 }
1809 });
1810 });
1811 };
1812 let results = await dataStrategyImpl({
1813 ...dataStrategyArgs,
1814 fetcherKey,
1815 runClientMiddleware
1816 });
1817 try {
1818 await Promise.all(matches.flatMap((m) => [m._lazyPromises?.handler, m._lazyPromises?.route]));
1819 } catch (e) {}
1820 return results;
1821}
1822async function callLoaderOrAction({ request, path, pattern, match, lazyHandlerPromise, lazyRoutePromise, handlerOverride, scopedContext }) {
1823 let result;
1824 let onReject;
1825 let isAction = isMutationMethod(request.method);
1826 let type = isAction ? "action" : "loader";
1827 let runHandler = (handler) => {
1828 let reject;
1829 let abortPromise = new Promise((_, r) => reject = r);
1830 onReject = () => reject();
1831 request.signal.addEventListener("abort", onReject);
1832 let actualHandler = (ctx) => {
1833 if (typeof handler !== "function") return Promise.reject(/* @__PURE__ */ new Error(`You cannot call the handler for a route which defines a boolean "${type}" [routeId: ${match.route.id}]`));
1834 return handler({
1835 request,
1836 url: createDataFunctionUrl(request, path),
1837 pattern,
1838 params: match.params,
1839 context: scopedContext
1840 }, ...ctx !== void 0 ? [ctx] : []);
1841 };
1842 let handlerPromise = (async () => {
1843 try {
1844 return {
1845 type: "data",
1846 result: await (handlerOverride ? handlerOverride((ctx) => actualHandler(ctx)) : actualHandler())
1847 };
1848 } catch (e) {
1849 return {
1850 type: "error",
1851 result: e
1852 };
1853 }
1854 })();
1855 return Promise.race([handlerPromise, abortPromise]);
1856 };
1857 try {
1858 let handler = isAction ? match.route.action : match.route.loader;
1859 if (lazyHandlerPromise || lazyRoutePromise) if (handler) {
1860 let handlerError;
1861 let [value] = await Promise.all([
1862 runHandler(handler).catch((e) => {
1863 handlerError = e;
1864 }),
1865 lazyHandlerPromise,
1866 lazyRoutePromise
1867 ]);
1868 if (handlerError !== void 0) throw handlerError;
1869 result = value;
1870 } else {
1871 await lazyHandlerPromise;
1872 let handler = isAction ? match.route.action : match.route.loader;
1873 if (handler) [result] = await Promise.all([runHandler(handler), lazyRoutePromise]);
1874 else if (type === "action") {
1875 let url = new URL(request.url);
1876 let pathname = url.pathname + url.search;
1877 throw getInternalRouterError(405, {
1878 method: request.method,
1879 pathname,
1880 routeId: match.route.id
1881 });
1882 } else return {
1883 type: "data",
1884 result: void 0
1885 };
1886 }
1887 else if (!handler) {
1888 let url = new URL(request.url);
1889 throw getInternalRouterError(404, { pathname: url.pathname + url.search });
1890 } else result = await runHandler(handler);
1891 } catch (e) {
1892 return {
1893 type: "error",
1894 result: e
1895 };
1896 } finally {
1897 if (onReject) request.signal.removeEventListener("abort", onReject);
1898 }
1899 return result;
1900}
1901async function parseResponseBody(response) {
1902 let contentType = response.headers.get("Content-Type");
1903 if (contentType && /\bapplication\/json\b/.test(contentType)) return response.body == null ? null : response.json();
1904 return response.text();
1905}
1906async function convertDataStrategyResultToDataResult(dataStrategyResult) {
1907 let { result, type } = dataStrategyResult;
1908 if (isResponse(result)) {
1909 let data;
1910 try {
1911 data = await parseResponseBody(result);
1912 } catch (e) {
1913 return {
1914 type: "error",
1915 error: e
1916 };
1917 }
1918 if (type === "error") return {
1919 type: "error",
1920 error: new ErrorResponseImpl(result.status, result.statusText, data),
1921 statusCode: result.status,
1922 headers: result.headers
1923 };
1924 return {
1925 type: "data",
1926 data,
1927 statusCode: result.status,
1928 headers: result.headers
1929 };
1930 }
1931 if (type === "error") {
1932 if (isDataWithResponseInit(result)) {
1933 if (result.data instanceof Error) return {
1934 type: "error",
1935 error: result.data,
1936 statusCode: result.init?.status,
1937 headers: result.init?.headers ? new Headers(result.init.headers) : void 0
1938 };
1939 return {
1940 type: "error",
1941 error: dataWithResponseInitToErrorResponse(result),
1942 statusCode: isRouteErrorResponse(result) ? result.status : void 0,
1943 headers: result.init?.headers ? new Headers(result.init.headers) : void 0
1944 };
1945 }
1946 return {
1947 type: "error",
1948 error: result,
1949 statusCode: isRouteErrorResponse(result) ? result.status : void 0
1950 };
1951 }
1952 if (isDataWithResponseInit(result)) return {
1953 type: "data",
1954 data: result.data,
1955 statusCode: result.init?.status,
1956 headers: result.init?.headers ? new Headers(result.init.headers) : void 0
1957 };
1958 return {
1959 type: "data",
1960 data: result
1961 };
1962}
1963function normalizeRelativeRoutingRedirectResponse(response, request, routeId, matches, basename) {
1964 let location = response.headers.get("Location");
1965 invariant$1(location, "Redirects returned/thrown from loaders/actions must have a Location header");
1966 if (!isAbsoluteUrl(location)) {
1967 let trimmedMatches = matches.slice(0, matches.findIndex((m) => m.route.id === routeId) + 1);
1968 location = normalizeTo(new URL(request.url), trimmedMatches, basename, location);
1969 response.headers.set("Location", location);
1970 }
1971 return response;
1972}
1973function processRouteLoaderData(matches, results, pendingActionResult, isStaticHandler = false, skipLoaderErrorBubbling = false) {
1974 let loaderData = {};
1975 let errors = null;
1976 let statusCode;
1977 let foundError = false;
1978 let loaderHeaders = {};
1979 let pendingError = pendingActionResult && isErrorResult(pendingActionResult[1]) ? pendingActionResult[1].error : void 0;
1980 matches.forEach((match) => {
1981 if (!(match.route.id in results)) return;
1982 let id = match.route.id;
1983 let result = results[id];
1984 invariant$1(!isRedirectResult(result), "Cannot handle redirect results in processLoaderData");
1985 if (isErrorResult(result)) {
1986 let error = result.error;
1987 if (pendingError !== void 0) {
1988 error = pendingError;
1989 pendingError = void 0;
1990 }
1991 errors = errors || {};
1992 if (skipLoaderErrorBubbling) errors[id] = error;
1993 else {
1994 let boundaryMatch = findNearestBoundary(matches, id);
1995 if (errors[boundaryMatch.route.id] == null) errors[boundaryMatch.route.id] = error;
1996 }
1997 if (!isStaticHandler) loaderData[id] = ResetLoaderDataSymbol;
1998 if (!foundError) {
1999 foundError = true;
2000 statusCode = isRouteErrorResponse(result.error) ? result.error.status : 500;
2001 }
2002 if (result.headers) loaderHeaders[id] = result.headers;
2003 } else {
2004 loaderData[id] = result.data;
2005 if (result.statusCode && result.statusCode !== 200 && !foundError) statusCode = result.statusCode;
2006 if (result.headers) loaderHeaders[id] = result.headers;
2007 }
2008 });
2009 if (pendingError !== void 0 && pendingActionResult) {
2010 errors = { [pendingActionResult[0]]: pendingError };
2011 if (pendingActionResult[2]) loaderData[pendingActionResult[2]] = void 0;
2012 }
2013 return {
2014 loaderData,
2015 errors,
2016 statusCode: statusCode || 200,
2017 loaderHeaders
2018 };
2019}
2020function findNearestBoundary(matches, routeId) {
2021 return (routeId ? matches.slice(0, matches.findIndex((m) => m.route.id === routeId) + 1) : [...matches]).reverse().find((m) => m.route.ErrorBoundary != null || m.route.errorElement != null) || matches[0];
2022}
2023function getShortCircuitMatches(routes) {
2024 let route = routes.length === 1 ? routes[0] : routes.find((r) => r.index || !r.path || r.path === "/") || { id: `__shim-error-route__` };
2025 return {
2026 matches: [{
2027 params: {},
2028 pathname: "",
2029 pathnameBase: "",
2030 route
2031 }],
2032 route
2033 };
2034}
2035function getInternalRouterError(status, { pathname, routeId, method, type, message } = {}) {
2036 let statusText = "Unknown Server Error";
2037 let errorMessage = "Unknown @remix-run/router error";
2038 if (status === 400) {
2039 statusText = "Bad Request";
2040 if (method && pathname && routeId) 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.`;
2041 else if (type === "invalid-body") errorMessage = "Unable to encode submission body";
2042 } else if (status === 403) {
2043 statusText = "Forbidden";
2044 errorMessage = `Route "${routeId}" does not match URL "${pathname}"`;
2045 } else if (status === 404) {
2046 statusText = "Not Found";
2047 errorMessage = `No route matches URL "${pathname}"`;
2048 } else if (status === 405) {
2049 statusText = "Method Not Allowed";
2050 if (method && pathname && routeId) 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.`;
2051 else if (method) errorMessage = `Invalid request method "${method.toUpperCase()}"`;
2052 }
2053 return new ErrorResponseImpl(status || 500, statusText, new Error(errorMessage), true);
2054}
2055function dataWithResponseInitToResponse(data) {
2056 return Response.json(data.data, data.init ?? void 0);
2057}
2058function dataWithResponseInitToErrorResponse(data) {
2059 return new ErrorResponseImpl(data.init?.status ?? 500, data.init?.statusText ?? "Internal Server Error", data.data);
2060}
2061function isDataStrategyResults(result) {
2062 return result != null && typeof result === "object" && Object.entries(result).every(([key, value]) => typeof key === "string" && isDataStrategyResult(value));
2063}
2064function isDataStrategyResult(result) {
2065 return result != null && typeof result === "object" && "type" in result && "result" in result && (result.type === "data" || result.type === "error");
2066}
2067function isRedirectDataStrategyResult(result) {
2068 return isResponse(result.result) && redirectStatusCodes.has(result.result.status);
2069}
2070function isErrorResult(result) {
2071 return result.type === "error";
2072}
2073function isRedirectResult(result) {
2074 return (result && result.type) === "redirect";
2075}
2076function isDataWithResponseInit(value) {
2077 return typeof value === "object" && value != null && "type" in value && "data" in value && "init" in value && value.type === "DataWithResponseInit";
2078}
2079function isResponse(value) {
2080 return value != null && typeof value.status === "number" && typeof value.statusText === "string" && typeof value.headers === "object" && typeof value.body !== "undefined";
2081}
2082function isRedirectStatusCode(statusCode) {
2083 return redirectStatusCodes.has(statusCode);
2084}
2085function isRedirectResponse(result) {
2086 return isResponse(result) && isRedirectStatusCode(result.status) && result.headers.has("Location");
2087}
2088function isValidMethod(method) {
2089 return validRequestMethods.has(method.toUpperCase());
2090}
2091function isMutationMethod(method) {
2092 return validMutationMethods.has(method.toUpperCase());
2093}
2094function hasNakedIndexQuery(search) {
2095 return new URLSearchParams(search).getAll("index").some((v) => v === "");
2096}
2097function getTargetMatch(matches, location) {
2098 let search = typeof location === "string" ? parsePath(location).search : location.search;
2099 if (matches[matches.length - 1].route.index && hasNakedIndexQuery(search || "")) return matches[matches.length - 1];
2100 let pathMatches = getPathContributingMatches(matches);
2101 return pathMatches[pathMatches.length - 1];
2102}
2103//#endregion
2104//#region lib/server-runtime/invariant.ts
2105function invariant(value, message) {
2106 if (value === false || value === null || typeof value === "undefined") {
2107 console.error("The following error is a bug in React Router; please open an issue! https://github.com/remix-run/react-router/issues/new/choose");
2108 throw new Error(message);
2109 }
2110}
2111//#endregion
2112//#region lib/server-runtime/headers.ts
2113function getDocumentHeadersImpl(context, getRouteHeadersFn, _defaultHeaders) {
2114 let boundaryIdx = context.errors ? context.matches.findIndex((m) => context.errors[m.route.id]) : -1;
2115 let matches = boundaryIdx >= 0 ? context.matches.slice(0, boundaryIdx + 1) : context.matches;
2116 let errorHeaders;
2117 if (boundaryIdx >= 0) {
2118 let { actionHeaders, actionData, loaderHeaders, loaderData } = context;
2119 context.matches.slice(boundaryIdx).some((match) => {
2120 let id = match.route.id;
2121 if (actionHeaders[id] && (!actionData || !actionData.hasOwnProperty(id))) errorHeaders = actionHeaders[id];
2122 else if (loaderHeaders[id] && !loaderData.hasOwnProperty(id)) errorHeaders = loaderHeaders[id];
2123 return errorHeaders != null;
2124 });
2125 }
2126 const defaultHeaders = new Headers(_defaultHeaders);
2127 return matches.reduce((parentHeaders, match, idx) => {
2128 let { id } = match.route;
2129 let loaderHeaders = context.loaderHeaders[id] || new Headers();
2130 let actionHeaders = context.actionHeaders[id] || new Headers();
2131 let includeErrorHeaders = errorHeaders != null && idx === matches.length - 1;
2132 let includeErrorCookies = includeErrorHeaders && errorHeaders !== loaderHeaders && errorHeaders !== actionHeaders;
2133 let headersFn = getRouteHeadersFn(match);
2134 if (headersFn == null) {
2135 let headers = new Headers(parentHeaders);
2136 if (includeErrorCookies) prependCookies(errorHeaders, headers);
2137 prependCookies(actionHeaders, headers);
2138 prependCookies(loaderHeaders, headers);
2139 return headers;
2140 }
2141 let headers = new Headers(typeof headersFn === "function" ? headersFn({
2142 loaderHeaders,
2143 parentHeaders,
2144 actionHeaders,
2145 errorHeaders: includeErrorHeaders ? errorHeaders : void 0
2146 }) : headersFn);
2147 if (includeErrorCookies) prependCookies(errorHeaders, headers);
2148 prependCookies(actionHeaders, headers);
2149 prependCookies(loaderHeaders, headers);
2150 prependCookies(parentHeaders, headers);
2151 return headers;
2152 }, new Headers(defaultHeaders));
2153}
2154function prependCookies(parentHeaders, childHeaders) {
2155 let parentSetCookieString = parentHeaders.get("Set-Cookie");
2156 if (parentSetCookieString) {
2157 let cookies = splitSetCookieString(parentSetCookieString);
2158 let childCookies = new Set(childHeaders.getSetCookie());
2159 cookies.forEach((cookie) => {
2160 if (!childCookies.has(cookie)) childHeaders.append("Set-Cookie", cookie);
2161 });
2162 }
2163}
2164//#endregion
2165//#region lib/server-runtime/warnings.ts
2166const alreadyWarned = {};
2167function warnOnce(condition, message) {
2168 if (!condition && !alreadyWarned[message]) {
2169 alreadyWarned[message] = true;
2170 console.warn(message);
2171 }
2172}
2173//#endregion
2174//#region lib/errors.ts
2175const ERROR_DIGEST_BASE = "REACT_ROUTER_ERROR";
2176const ERROR_DIGEST_REDIRECT = "REDIRECT";
2177const ERROR_DIGEST_ROUTE_ERROR_RESPONSE = "ROUTE_ERROR_RESPONSE";
2178function createRedirectErrorDigest(response) {
2179 return `${ERROR_DIGEST_BASE}:${ERROR_DIGEST_REDIRECT}:${JSON.stringify({
2180 status: response.status,
2181 statusText: response.statusText,
2182 location: response.headers.get("Location"),
2183 reloadDocument: response.headers.get("X-Remix-Reload-Document") === "true",
2184 replace: response.headers.get("X-Remix-Replace") === "true"
2185 })}`;
2186}
2187function createRouteErrorResponseDigest(response) {
2188 let status = 500;
2189 let statusText = "";
2190 let data;
2191 if (isDataWithResponseInit(response)) {
2192 status = response.init?.status ?? status;
2193 statusText = response.init?.statusText ?? statusText;
2194 data = response.data;
2195 } else {
2196 status = response.status;
2197 statusText = response.statusText;
2198 data = void 0;
2199 }
2200 return `${ERROR_DIGEST_BASE}:${ERROR_DIGEST_ROUTE_ERROR_RESPONSE}:${JSON.stringify({
2201 status,
2202 statusText,
2203 data
2204 })}`;
2205}
2206function getPathsWithAncestors(paths) {
2207 let result = /* @__PURE__ */ new Set();
2208 paths.forEach((path) => {
2209 if (!path.startsWith("/")) path = `/${path}`;
2210 for (let i = 1; i < path.length; i++) if (path[i] === "/") result.add(path.slice(0, i));
2211 result.add(path);
2212 });
2213 return Array.from(result);
2214}
2215//#endregion
2216//#region lib/actions.ts
2217function throwIfPotentialCSRFAttack(request, allowedActionOrigins) {
2218 let originHeader = request.headers.get("origin");
2219 let originDomain = null;
2220 try {
2221 originDomain = typeof originHeader === "string" && originHeader !== "null" ? new URL(originHeader).host : originHeader;
2222 } catch {
2223 throw new Error(`\`origin\` header is not a valid URL. Aborting the action.`);
2224 }
2225 let host = new URL(request.url).host;
2226 if (originDomain && originDomain !== host) {
2227 if (!isAllowedOrigin(originDomain, allowedActionOrigins)) throw new Error("The `request.url` host does not match `origin` header from a forwarded action request. Aborting the action.");
2228 }
2229}
2230function matchWildcardDomain(domain, pattern) {
2231 const domainParts = domain.split(".");
2232 const patternParts = pattern.split(".");
2233 if (patternParts.length < 1) return false;
2234 if (domainParts.length < patternParts.length) return false;
2235 while (patternParts.length) {
2236 const patternPart = patternParts.pop();
2237 const domainPart = domainParts.pop();
2238 switch (patternPart) {
2239 case "": return false;
2240 case "*": if (domainPart) continue;
2241 else return false;
2242 case "**":
2243 if (patternParts.length > 0) return false;
2244 return domainPart !== void 0;
2245 case void 0:
2246 default: if (domainPart !== patternPart) return false;
2247 }
2248 }
2249 return domainParts.length === 0;
2250}
2251function isAllowedOrigin(originDomain, allowedActionOrigins = []) {
2252 return allowedActionOrigins.some((allowedOrigin) => allowedOrigin && (allowedOrigin === originDomain || matchWildcardDomain(originDomain, allowedOrigin)));
2253}
2254//#endregion
2255//#region lib/server-runtime/urls.ts
2256function getNormalizedPath(request) {
2257 let url = new URL(request.url);
2258 let pathname = url.pathname;
2259 if (pathname.endsWith("/_.data")) pathname = pathname.replace(/_\.data$/, "");
2260 else pathname = pathname.replace(/\.data$/, "");
2261 let searchParams = new URLSearchParams(url.search);
2262 searchParams.delete("_routes");
2263 let search = searchParams.toString();
2264 if (search) search = `?${search}`;
2265 return {
2266 pathname,
2267 search,
2268 hash: ""
2269 };
2270}
2271//#endregion
2272//#region lib/rsc/server.rsc.ts
2273const Outlet$2 = Outlet$1;
2274const WithComponentProps = UNSAFE_WithComponentProps;
2275const WithErrorBoundaryProps = UNSAFE_WithErrorBoundaryProps;
2276const WithHydrateFallbackProps = UNSAFE_WithHydrateFallbackProps;
2277const globalVar = typeof globalThis !== "undefined" ? globalThis : global;
2278const ServerStorage = globalVar.___reactRouterServerStorage___ ??= new AsyncLocalStorage();
2279function getRequest() {
2280 const ctx = ServerStorage.getStore();
2281 if (!ctx) throw new Error("getRequest must be called from within a React Server render context");
2282 return ctx.request;
2283}
2284const redirect = (...args) => {
2285 const response = redirect$1(...args);
2286 const ctx = ServerStorage.getStore();
2287 if (ctx && ctx.runningAction) ctx.redirect = response;
2288 return response;
2289};
2290const redirectDocument = (...args) => {
2291 const response = redirectDocument$1(...args);
2292 const ctx = ServerStorage.getStore();
2293 if (ctx && ctx.runningAction) ctx.redirect = response;
2294 return response;
2295};
2296const replace = (...args) => {
2297 const response = replace$1(...args);
2298 const ctx = ServerStorage.getStore();
2299 if (ctx && ctx.runningAction) ctx.redirect = response;
2300 return response;
2301};
2302const cachedResolvePromise = React.cache(async (resolve) => {
2303 return Promise.allSettled([resolve]).then((r) => r[0]);
2304});
2305const Await = (async ({ children, resolve, errorElement }) => {
2306 let resolved = await cachedResolvePromise(resolve);
2307 if (resolved.status === "rejected" && !errorElement) throw resolved.reason;
2308 if (resolved.status === "rejected") return React.createElement(UNSAFE_AwaitContextProvider, {
2309 children: React.createElement(React.Fragment, null, errorElement),
2310 value: {
2311 _tracked: true,
2312 _error: resolved.reason
2313 }
2314 });
2315 const toRender = typeof children === "function" ? children(resolved.value) : children;
2316 return React.createElement(UNSAFE_AwaitContextProvider, {
2317 children: toRender,
2318 value: {
2319 _tracked: true,
2320 _data: resolved.value
2321 }
2322 });
2323});
2324/**
2325* Matches the given routes to a [`Request`](https://developer.mozilla.org/en-US/docs/Web/API/Request)
2326* and returns an [RSC](https://react.dev/reference/rsc/server-components)
2327* [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response)
2328* encoding an {@link unstable_RSCPayload} for consumption by an [RSC](https://react.dev/reference/rsc/server-components)
2329* enabled client router.
2330*
2331* @example
2332* import {
2333* createTemporaryReferenceSet,
2334* decodeAction,
2335* decodeReply,
2336* loadServerAction,
2337* renderToReadableStream,
2338* } from "@vitejs/plugin-rsc/rsc";
2339* import { unstable_matchRSCServerRequest as matchRSCServerRequest } from "react-router";
2340*
2341* matchRSCServerRequest({
2342* createTemporaryReferenceSet,
2343* decodeAction,
2344* decodeFormState,
2345* decodeReply,
2346* loadServerAction,
2347* request,
2348* routes: routes(),
2349* generateResponse(match) {
2350* return new Response(
2351* renderToReadableStream(match.payload),
2352* {
2353* status: match.statusCode,
2354* headers: match.headers,
2355* }
2356* );
2357* },
2358* });
2359*
2360* @name unstable_matchRSCServerRequest
2361* @public
2362* @category RSC
2363* @mode data
2364* @param opts Options
2365* @param opts.allowedActionOrigins Origin patterns that are allowed to execute actions.
2366* @param opts.basename The basename to use when matching the request.
2367* @param opts.createTemporaryReferenceSet A function that returns a temporary
2368* reference set for the request, used to track temporary references in the [RSC](https://react.dev/reference/rsc/server-components)
2369* stream.
2370* @param opts.decodeAction Your `react-server-dom-xyz/server`'s `decodeAction`
2371* function, responsible for loading a server action.
2372* @param opts.decodeFormState A function responsible for decoding form state for
2373* progressively enhanceable forms with React's [`useActionState`](https://react.dev/reference/react/useActionState)
2374* using your `react-server-dom-xyz/server`'s `decodeFormState`.
2375* @param opts.decodeReply Your `react-server-dom-xyz/server`'s `decodeReply`
2376* function, used to decode the server function's arguments and bind them to the
2377* implementation for invocation by the router.
2378* @param opts.generateResponse A function responsible for using your
2379* `renderToReadableStream` to generate a [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response)
2380* encoding the {@link unstable_RSCPayload}.
2381* @param opts.loadServerAction Your `react-server-dom-xyz/server`'s
2382* `loadServerAction` function, used to load a server action by ID.
2383* @param opts.clientVersion A version derived from the client build output used
2384* to detect stale clients during lazy route discovery.
2385* @param opts.onError An optional error handler that will be called with any
2386* errors that occur during the request processing.
2387* @param opts.request The [`Request`](https://developer.mozilla.org/en-US/docs/Web/API/Request)
2388* to match against.
2389* @param opts.requestContext An instance of {@link RouterContextProvider}
2390* that should be created per request, to be passed to [`action`](../../start/data/route-object#action)s,
2391* [`loader`](../../start/data/route-object#loader)s and [middleware](../../how-to/middleware).
2392* @param opts.routeDiscovery The route discovery configuration, used to determine how the router should discover new routes during navigations.
2393* @param opts.routes Your {@link unstable_RSCRouteConfigEntry | route definitions}.
2394* @returns A [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response)
2395* that contains the [RSC](https://react.dev/reference/rsc/server-components)
2396* data for hydration.
2397*/
2398async function matchRSCServerRequest({ allowedActionOrigins, createTemporaryReferenceSet, basename, decodeReply, requestContext, routeDiscovery, loadServerAction, decodeAction, decodeFormState, clientVersion, onError, request, routes, generateResponse }) {
2399 let url = new URL(request.url);
2400 basename = basename || "/";
2401 let normalizedPath = url.pathname;
2402 if (url.pathname.endsWith("/_.rsc")) normalizedPath = url.pathname.replace(/_\.rsc$/, "");
2403 else if (url.pathname.endsWith(".rsc")) normalizedPath = url.pathname.replace(/\.rsc$/, "");
2404 if (stripBasename(normalizedPath, basename) !== "/" && normalizedPath.endsWith("/")) normalizedPath = normalizedPath.slice(0, -1);
2405 url.pathname = normalizedPath;
2406 basename = basename.length > normalizedPath.length ? normalizedPath : basename;
2407 let routerRequest = new Request(url.toString(), {
2408 method: request.method,
2409 headers: request.headers,
2410 body: request.body,
2411 signal: request.signal,
2412 duplex: request.body ? "half" : void 0
2413 });
2414 const temporaryReferences = createTemporaryReferenceSet();
2415 const requestUrl = new URL(request.url);
2416 if (isManifestRequest(requestUrl)) return await generateManifestResponse(routes, basename, request, generateResponse, temporaryReferences, routeDiscovery, clientVersion);
2417 let isDataRequest = isReactServerRequest(requestUrl);
2418 let matches = matchRoutes(routes, url.pathname, basename);
2419 if (matches) await Promise.all(matches.map((m) => explodeLazyRoute(m.route)));
2420 const leafMatch = matches?.[matches.length - 1];
2421 if (!isDataRequest && leafMatch && !leafMatch.route.Component && !leafMatch.route.ErrorBoundary) return generateResourceResponse(routerRequest, routes, basename, leafMatch.route.id, requestContext, onError);
2422 let response = await generateRenderResponse(routerRequest, routes, basename, isDataRequest, decodeReply, requestContext, loadServerAction, decodeAction, decodeFormState, onError, generateResponse, temporaryReferences, allowedActionOrigins, routeDiscovery, clientVersion);
2423 response.headers.set("X-Remix-Response", "yes");
2424 return response;
2425}
2426async function generateManifestResponse(routes, basename, request, generateResponse, temporaryReferences, routeDiscovery, clientVersion) {
2427 let url = new URL(request.url);
2428 if (url.toString().length > 7680) return new Response(null, {
2429 statusText: "Bad Request",
2430 status: 400
2431 });
2432 if (clientVersion !== void 0 && clientVersion !== url.searchParams.get("version")) return new Response(null, {
2433 status: 204,
2434 headers: { "X-Remix-Reload-Document": "true" }
2435 });
2436 if (routeDiscovery?.mode === "initial") {
2437 let payload = {
2438 type: "manifest",
2439 patches: getAllRoutePatches(routes, basename)
2440 };
2441 return generateResponse({
2442 statusCode: 200,
2443 headers: new Headers({
2444 "Content-Type": "text/x-component",
2445 Vary: "Content-Type"
2446 }),
2447 payload
2448 }, {
2449 temporaryReferences,
2450 onError: defaultOnError
2451 });
2452 }
2453 let pathParam = url.searchParams.get("paths");
2454 let pathnames = pathParam ? pathParam.split(",").filter(Boolean) : [url.pathname.replace(/\.manifest$/, "")];
2455 let routeIds = /* @__PURE__ */ new Set();
2456 let matchedRoutes = pathnames.flatMap((pathname) => {
2457 let pathnameMatches = matchRoutes(routes, pathname, basename);
2458 return pathnameMatches?.map((m, i) => ({
2459 ...m.route,
2460 parentId: pathnameMatches[i - 1]?.route.id
2461 })) ?? [];
2462 }).filter((route) => {
2463 if (!routeIds.has(route.id)) {
2464 routeIds.add(route.id);
2465 return true;
2466 }
2467 return false;
2468 });
2469 let payload = {
2470 type: "manifest",
2471 patches: Promise.all([...matchedRoutes.map((route) => getManifestRoute(route)), getAdditionalRoutePatches(pathnames, routes, basename, Array.from(routeIds))]).then((r) => r.flat(1))
2472 };
2473 return generateResponse({
2474 statusCode: 200,
2475 headers: new Headers({ "Content-Type": "text/x-component" }),
2476 payload
2477 }, {
2478 temporaryReferences,
2479 onError: defaultOnError
2480 });
2481}
2482function prependBasenameToRedirectResponse(response, basename = "/") {
2483 if (basename === "/") return response;
2484 let redirect = response.headers.get("Location");
2485 if (!redirect || isAbsoluteUrl(redirect)) return response;
2486 response.headers.set("Location", prependBasename({
2487 basename,
2488 pathname: redirect
2489 }));
2490 return response;
2491}
2492async function processServerAction(request, basename, decodeReply, loadServerAction, decodeAction, decodeFormState, onError, temporaryReferences) {
2493 const getRevalidationRequest = () => new Request(request.url, {
2494 method: "GET",
2495 headers: request.headers,
2496 signal: request.signal
2497 });
2498 const isFormRequest = canDecodeWithFormData(request.headers.get("Content-Type"));
2499 const actionId = request.headers.get("rsc-action-id");
2500 if (actionId) {
2501 if (!decodeReply || !loadServerAction) throw new Error("Cannot handle enhanced server action without decodeReply and loadServerAction functions");
2502 const actionArgs = await decodeReply(isFormRequest ? await request.formData() : await request.text(), { temporaryReferences });
2503 const serverAction = (await loadServerAction(actionId)).bind(null, ...actionArgs);
2504 let actionResult = Promise.resolve(serverAction());
2505 try {
2506 await actionResult;
2507 } catch (error) {
2508 if (isResponse(error)) return error;
2509 onError?.(error);
2510 }
2511 let maybeFormData = actionArgs.length === 1 ? actionArgs[0] : actionArgs[1];
2512 let skipRevalidation = (maybeFormData && typeof maybeFormData === "object" && maybeFormData instanceof FormData ? maybeFormData : null)?.has("$SKIP_REVALIDATION") ?? false;
2513 return {
2514 actionResult,
2515 revalidationRequest: getRevalidationRequest(),
2516 skipRevalidation
2517 };
2518 } else if (isFormRequest) {
2519 const formData = await request.clone().formData();
2520 if (Array.from(formData.keys()).some((k) => k.startsWith("$ACTION_"))) {
2521 if (!decodeAction) throw new Error("Cannot handle form actions without a decodeAction function");
2522 const action = await decodeAction(formData);
2523 let formState = void 0;
2524 try {
2525 let result = await action();
2526 if (isRedirectResponse(result)) result = prependBasenameToRedirectResponse(result, basename);
2527 formState = await decodeFormState?.(result, formData);
2528 } catch (error) {
2529 if (isRedirectResponse(error)) return prependBasenameToRedirectResponse(error, basename);
2530 if (isResponse(error)) return error;
2531 onError?.(error);
2532 }
2533 return {
2534 formState,
2535 revalidationRequest: getRevalidationRequest(),
2536 skipRevalidation: false
2537 };
2538 }
2539 }
2540}
2541async function generateResourceResponse(request, routes, basename, routeId, requestContext, onError) {
2542 try {
2543 return await createStaticHandler(routes, { basename }).queryRoute(request, {
2544 routeId,
2545 requestContext,
2546 async generateMiddlewareResponse(queryRoute) {
2547 try {
2548 return generateResourceResponse(await queryRoute(request));
2549 } catch (error) {
2550 return generateErrorResponse(error);
2551 }
2552 },
2553 normalizePath: (r) => getNormalizedPath(r)
2554 });
2555 } catch (error) {
2556 return generateErrorResponse(error);
2557 }
2558 function generateErrorResponse(error) {
2559 let response;
2560 if (isResponse(error)) response = error;
2561 else if (isRouteErrorResponse(error)) {
2562 onError?.(error);
2563 const errorMessage = typeof error.data === "string" ? error.data : error.statusText;
2564 response = new Response(errorMessage, {
2565 status: error.status,
2566 statusText: error.statusText
2567 });
2568 } else {
2569 onError?.(error);
2570 response = new Response("Internal Server Error", { status: 500 });
2571 }
2572 return generateResourceResponse(response);
2573 }
2574 function generateResourceResponse(response) {
2575 const headers = new Headers(response.headers);
2576 headers.set("React-Router-Resource", "true");
2577 return new Response(response.body, {
2578 status: response.status,
2579 statusText: response.statusText,
2580 headers
2581 });
2582 }
2583}
2584async function generateRenderResponse(request, routes, basename, isDataRequest, decodeReply, requestContext, loadServerAction, decodeAction, decodeFormState, onError, generateResponse, temporaryReferences, allowedActionOrigins, routeDiscovery, clientVersion) {
2585 let statusCode = 200;
2586 let url = new URL(request.url);
2587 let isSubmission = isMutationMethod(request.method);
2588 let routeIdsToLoad = !isSubmission && url.searchParams.has("_routes") ? url.searchParams.get("_routes").split(",") : null;
2589 const staticHandler = createStaticHandler(routes, { basename });
2590 let actionResult;
2591 const ctx = {
2592 request,
2593 runningAction: false
2594 };
2595 const result = await ServerStorage.run(ctx, () => staticHandler.query(request, {
2596 requestContext,
2597 skipLoaderErrorBubbling: isDataRequest,
2598 skipRevalidation: isSubmission,
2599 ...routeIdsToLoad ? { filterMatchesToLoad: (m) => routeIdsToLoad.includes(m.route.id) } : {},
2600 normalizePath: (r) => getNormalizedPath(r),
2601 async generateMiddlewareResponse(query) {
2602 let formState;
2603 let skipRevalidation = false;
2604 let potentialCSRFAttackError;
2605 if (isMutationMethod(request.method)) {
2606 try {
2607 throwIfPotentialCSRFAttack(request, allowedActionOrigins);
2608 } catch (error) {
2609 onError?.(error);
2610 potentialCSRFAttackError = error;
2611 request = new Request(request.url, {
2612 method: "GET",
2613 headers: request.headers,
2614 signal: request.signal
2615 });
2616 }
2617 if (!potentialCSRFAttackError) {
2618 ctx.runningAction = true;
2619 let result = await processServerAction(request, basename, decodeReply, loadServerAction, decodeAction, decodeFormState, onError, temporaryReferences).finally(() => {
2620 ctx.runningAction = false;
2621 });
2622 if (isResponse(result)) return generateRedirectResponse(result, actionResult, basename, isDataRequest, generateResponse, temporaryReferences, ctx.redirect?.headers);
2623 skipRevalidation = result?.skipRevalidation ?? false;
2624 actionResult = result?.actionResult;
2625 formState = result?.formState;
2626 request = result?.revalidationRequest ?? request;
2627 if (ctx.redirect) return generateRedirectResponse(ctx.redirect, actionResult, basename, isDataRequest, generateResponse, temporaryReferences, void 0);
2628 }
2629 }
2630 let staticContext = await query(request, skipRevalidation ? { filterMatchesToLoad: () => false } : void 0);
2631 if (isResponse(staticContext)) return generateRedirectResponse(staticContext, actionResult, basename, isDataRequest, generateResponse, temporaryReferences, ctx.redirect?.headers);
2632 if (potentialCSRFAttackError) {
2633 staticContext.errors ??= {};
2634 staticContext.errors[staticContext.matches[0].route.id] = potentialCSRFAttackError;
2635 staticContext.statusCode = 400;
2636 }
2637 return generateStaticContextResponse(routes, basename, generateResponse, statusCode, routeIdsToLoad, isDataRequest, isSubmission, actionResult, formState, staticContext, temporaryReferences, skipRevalidation, ctx.redirect?.headers, routeDiscovery, clientVersion);
2638 }
2639 }));
2640 if (isRedirectResponse(result)) return generateRedirectResponse(result, actionResult, basename, isDataRequest, generateResponse, temporaryReferences, ctx.redirect?.headers);
2641 invariant(isResponse(result), "Expected a response from query");
2642 return result;
2643}
2644function generateRedirectResponse(response, actionResult, basename, isDataRequest, generateResponse, temporaryReferences, sideEffectRedirectHeaders) {
2645 let redirect = response.headers.get("Location");
2646 if (isDataRequest && basename) redirect = stripBasename(redirect, basename) || redirect;
2647 let payload = {
2648 type: "redirect",
2649 location: redirect,
2650 reload: response.headers.get("X-Remix-Reload-Document") === "true",
2651 replace: response.headers.get("X-Remix-Replace") === "true",
2652 status: response.status,
2653 actionResult
2654 };
2655 let headers = new Headers(sideEffectRedirectHeaders);
2656 for (const [key, value] of response.headers.entries()) headers.append(key, value);
2657 headers.delete("Location");
2658 headers.delete("X-Remix-Reload-Document");
2659 headers.delete("X-Remix-Replace");
2660 headers.delete("Content-Length");
2661 headers.set("Content-Type", "text/x-component");
2662 return generateResponse({
2663 statusCode: 202,
2664 headers,
2665 payload
2666 }, {
2667 temporaryReferences,
2668 onError: defaultOnError
2669 });
2670}
2671async function generateStaticContextResponse(routes, basename, generateResponse, statusCode, routeIdsToLoad, isDataRequest, isSubmission, actionResult, formState, staticContext, temporaryReferences, skipRevalidation, sideEffectRedirectHeaders, routeDiscovery, clientVersion) {
2672 statusCode = staticContext.statusCode ?? statusCode;
2673 if (staticContext.errors) staticContext.errors = Object.fromEntries(Object.entries(staticContext.errors).map(([key, error]) => [key, isRouteErrorResponse(error) ? Object.fromEntries(Object.entries(error)) : error]));
2674 staticContext.matches.forEach((m) => {
2675 const routeHasNoLoaderData = staticContext.loaderData[m.route.id] === void 0;
2676 const routeHasError = Boolean(staticContext.errors && m.route.id in staticContext.errors);
2677 if (routeHasNoLoaderData && !routeHasError) staticContext.loaderData[m.route.id] = null;
2678 });
2679 let headers = getDocumentHeadersImpl(staticContext, (match) => match.route.headers, sideEffectRedirectHeaders);
2680 headers.delete("Content-Length");
2681 const baseRenderPayload = {
2682 type: "render",
2683 basename: staticContext.basename,
2684 clientVersion,
2685 routeDiscovery: routeDiscovery ?? { mode: "lazy" },
2686 actionData: staticContext.actionData,
2687 errors: staticContext.errors,
2688 loaderData: staticContext.loaderData,
2689 location: staticContext.location,
2690 formState
2691 };
2692 const renderPayloadPromise = () => getRenderPayload(baseRenderPayload, routes, basename, routeIdsToLoad, isDataRequest, staticContext, routeDiscovery);
2693 let payload;
2694 if (actionResult) payload = {
2695 type: "action",
2696 actionResult,
2697 rerender: skipRevalidation ? void 0 : renderPayloadPromise()
2698 };
2699 else if (isSubmission && isDataRequest) payload = {
2700 ...baseRenderPayload,
2701 matches: [],
2702 patches: Promise.resolve([])
2703 };
2704 else payload = await renderPayloadPromise();
2705 return generateResponse({
2706 statusCode,
2707 headers,
2708 payload
2709 }, {
2710 temporaryReferences,
2711 onError: defaultOnError
2712 });
2713}
2714async function getRenderPayload(baseRenderPayload, routes, basename, routeIdsToLoad, isDataRequest, staticContext, routeDiscovery) {
2715 let deepestRenderedRouteIdx = staticContext.matches.length - 1;
2716 let parentIds = {};
2717 staticContext.matches.forEach((m, i) => {
2718 if (i > 0) parentIds[m.route.id] = staticContext.matches[i - 1].route.id;
2719 if (staticContext.errors && m.route.id in staticContext.errors && deepestRenderedRouteIdx > i) deepestRenderedRouteIdx = i;
2720 });
2721 let matchesPromise = Promise.all(staticContext.matches.map((match, i) => {
2722 let isBelowErrorBoundary = i > deepestRenderedRouteIdx;
2723 let parentId = parentIds[match.route.id];
2724 return getRSCRouteMatch({
2725 staticContext,
2726 match,
2727 routeIdsToLoad,
2728 isBelowErrorBoundary,
2729 parentId
2730 });
2731 }));
2732 let patches = routeDiscovery?.mode === "initial" && !isDataRequest ? getAllRoutePatches(routes, basename).then((patches) => patches.filter((patch) => !staticContext.matches.some((m) => m.route.id === patch.id))) : getAdditionalRoutePatches(getPathsWithAncestors([staticContext.location.pathname]), routes, basename, staticContext.matches.map((m) => m.route.id));
2733 return {
2734 ...baseRenderPayload,
2735 matches: await matchesPromise,
2736 patches
2737 };
2738}
2739async function getRSCRouteMatch({ staticContext, match, isBelowErrorBoundary, routeIdsToLoad, parentId }) {
2740 const route = match.route;
2741 await explodeLazyRoute(route);
2742 const Layout = route.Layout || React.Fragment;
2743 const Component = route.Component;
2744 const ErrorBoundary = route.ErrorBoundary;
2745 const HydrateFallback = route.HydrateFallback;
2746 const loaderData = staticContext.loaderData[route.id];
2747 const actionData = staticContext.actionData?.[route.id];
2748 const params = match.params;
2749 let element = void 0;
2750 let shouldLoadRoute = !routeIdsToLoad || routeIdsToLoad.includes(route.id);
2751 if (Component && shouldLoadRoute) element = !isBelowErrorBoundary ? React.createElement(Layout, null, isClientReference(Component) ? React.createElement(WithComponentProps, { children: React.createElement(Component) }) : React.createElement(Component, {
2752 loaderData,
2753 actionData,
2754 params,
2755 matches: staticContext.matches.map((match) => convertRouteMatchToUiMatch(match, staticContext.loaderData))
2756 })) : React.createElement(Outlet$2);
2757 let error = void 0;
2758 if (ErrorBoundary && staticContext.errors) error = staticContext.errors[route.id];
2759 const errorElement = ErrorBoundary ? React.createElement(Layout, null, isClientReference(ErrorBoundary) ? React.createElement(WithErrorBoundaryProps, { children: React.createElement(ErrorBoundary) }) : React.createElement(ErrorBoundary, {
2760 loaderData,
2761 actionData,
2762 params,
2763 error
2764 })) : void 0;
2765 const hydrateFallbackElement = HydrateFallback ? React.createElement(Layout, null, isClientReference(HydrateFallback) ? React.createElement(WithHydrateFallbackProps, { children: React.createElement(HydrateFallback) }) : React.createElement(HydrateFallback, {
2766 loaderData,
2767 actionData,
2768 params
2769 })) : void 0;
2770 const hmrRoute = route;
2771 return {
2772 clientAction: route.clientAction,
2773 clientLoader: route.clientLoader,
2774 element,
2775 errorElement,
2776 handle: route.handle,
2777 hasAction: !!route.action,
2778 hasComponent: !!Component,
2779 hasLoader: !!route.loader,
2780 hydrateFallbackElement,
2781 id: route.id,
2782 index: "index" in route ? route.index : void 0,
2783 links: route.links,
2784 meta: route.meta,
2785 params,
2786 parentId,
2787 path: route.path,
2788 pathname: match.pathname,
2789 pathnameBase: match.pathnameBase,
2790 shouldRevalidate: route.shouldRevalidate,
2791 ...hmrRoute.__ensureClientRouteModuleForHMR ? { __ensureClientRouteModuleForHMR: hmrRoute.__ensureClientRouteModuleForHMR } : {}
2792 };
2793}
2794async function getManifestRoute(route) {
2795 await explodeLazyRoute(route);
2796 const Layout = route.Layout || React.Fragment;
2797 const errorElement = route.ErrorBoundary ? React.createElement(Layout, null, React.createElement(route.ErrorBoundary)) : void 0;
2798 return {
2799 clientAction: route.clientAction,
2800 clientLoader: route.clientLoader,
2801 handle: route.handle,
2802 hasAction: !!route.action,
2803 hasComponent: !!route.Component,
2804 errorElement,
2805 hasLoader: !!route.loader,
2806 id: route.id,
2807 parentId: route.parentId,
2808 path: route.path,
2809 index: "index" in route ? route.index : void 0,
2810 links: route.links,
2811 meta: route.meta
2812 };
2813}
2814async function explodeLazyRoute(route) {
2815 if ("lazy" in route && route.lazy) {
2816 let { default: lazyDefaultExport, Component: lazyComponentExport, ...lazyProperties } = await route.lazy();
2817 let Component = lazyComponentExport || lazyDefaultExport;
2818 if (Component && !route.Component) route.Component = Component;
2819 for (let [k, v] of Object.entries(lazyProperties)) if (k !== "id" && k !== "path" && k !== "index" && k !== "children" && route[k] == null) route[k] = v;
2820 route.lazy = void 0;
2821 }
2822}
2823async function getAllRoutePatches(routes, basename) {
2824 let patches = [];
2825 async function traverse(route, parentId) {
2826 let manifestRoute = await getManifestRoute({
2827 ...route,
2828 parentId
2829 });
2830 patches.push(manifestRoute);
2831 if ("children" in route && route.children?.length) for (let child of route.children) await traverse(child, route.id);
2832 }
2833 for (let route of routes) await traverse(route, void 0);
2834 return patches.filter((p) => !!p.parentId);
2835}
2836async function getAdditionalRoutePatches(pathnames, routes, basename, matchedRouteIds) {
2837 let patchRouteMatches = /* @__PURE__ */ new Map();
2838 let matchedPaths = /* @__PURE__ */ new Set();
2839 for (const pathname of pathnames) {
2840 if (matchedPaths.has(pathname)) continue;
2841 matchedPaths.add(pathname);
2842 let matches = matchRoutes(routes, pathname, basename) || [];
2843 matches.forEach((m, i) => {
2844 if (patchRouteMatches.get(m.route.id)) return;
2845 patchRouteMatches.set(m.route.id, {
2846 ...m.route,
2847 parentId: matches[i - 1]?.route.id
2848 });
2849 });
2850 }
2851 return await Promise.all([...patchRouteMatches.values()].filter((route) => !matchedRouteIds.some((id) => id === route.id)).map((route) => getManifestRoute(route)));
2852}
2853function isReactServerRequest(url) {
2854 return url.pathname.endsWith(".rsc");
2855}
2856function isManifestRequest(url) {
2857 return url.pathname.endsWith(".manifest");
2858}
2859function defaultOnError(error) {
2860 if (isRedirectResponse(error)) return createRedirectErrorDigest(error);
2861 if (isResponse(error) || isDataWithResponseInit(error)) return createRouteErrorResponseDigest(error);
2862}
2863function isClientReference(x) {
2864 try {
2865 return x.$$typeof === Symbol.for("react.client.reference");
2866 } catch {
2867 return false;
2868 }
2869}
2870function canDecodeWithFormData(contentType) {
2871 if (!contentType) return false;
2872 return contentType.match(/\bapplication\/x-www-form-urlencoded\b/) || contentType.match(/\bmultipart\/form-data\b/);
2873}
2874//#endregion
2875//#region lib/href.ts
2876function stringify(p) {
2877 return p == null ? "" : typeof p === "string" ? p : String(p);
2878}
2879/**
2880* Returns a resolved URL path for the specified route.
2881*
2882* Param values are percent-encoded for use in a path segment: characters that
2883* would change the URL structure (`/`, `?`, `#`, `%`, whitespace, non-ASCII)
2884* are escaped, while characters that RFC 3986 allows literally in a path
2885* segment (`$ & + , ; = : @`) are kept as-is. Note this differs from query-string
2886* encoding (`encodeURIComponent`/`URLSearchParams`), where those characters are
2887* delimiters and must be escaped. Splat (`*`) values are encoded per segment,
2888* preserving `/` separators.
2889*
2890* See [RFC 3986 §3.3](https://datatracker.ietf.org/doc/html/rfc3986#section-3.3)
2891*
2892* @example
2893* const h = href("/:lang?/about", { lang: "en" })
2894* // -> `/en/about`
2895*
2896* <Link to={href("/products/:id", { id: "abc123" })} />
2897*
2898* @public
2899* @category Utils
2900* @mode framework
2901* @param path The route path to resolve
2902* @param args The route params to use when resolving the path
2903* @returns The resolved URL path
2904*/
2905function href(path, ...args) {
2906 let params = args[0];
2907 let result = trimTrailingSplat(path).replace(/\/:([\w-]+)(\?)?/g, (_, param, questionMark) => {
2908 const isRequired = questionMark === void 0;
2909 const value = params?.[param];
2910 if (isRequired && value === void 0) throw new Error(`Path '${path}' requires param '${param}' but it was not provided`);
2911 return value == null ? "" : "/" + encodePathParam(stringify(value));
2912 });
2913 if (path.endsWith("*")) {
2914 const value = params?.["*"];
2915 if (value !== void 0) result += "/" + stringify(value).split("/").map(encodePathParam).join("/");
2916 }
2917 return result || "/";
2918}
2919/**
2920* Removes a trailing splat and any number of slashes from the end of the path.
2921*
2922* Benchmarked to be faster than `path.replace(/\/*\*?$/, "")`, which backtracks.
2923*/
2924function trimTrailingSplat(path) {
2925 let i = path.length - 1;
2926 let char = path[i];
2927 if (char !== "*" && char !== "/") return path;
2928 i--;
2929 for (; i >= 0; i--) if (path[i] !== "/") break;
2930 return path.slice(0, i + 1);
2931}
2932//#endregion
2933//#region lib/server-runtime/crypto.ts
2934const encoder = /* @__PURE__ */ new TextEncoder();
2935const sign = async (value, secret) => {
2936 let data = encoder.encode(value);
2937 let key = await createKey(secret, ["sign"]);
2938 let signature = await crypto.subtle.sign("HMAC", key, data);
2939 let hash = btoa(String.fromCharCode(...new Uint8Array(signature))).replace(/=+$/, "");
2940 return value + "." + hash;
2941};
2942const unsign = async (cookie, secret) => {
2943 let index = cookie.lastIndexOf(".");
2944 let value = cookie.slice(0, index);
2945 let hash = cookie.slice(index + 1);
2946 let data = encoder.encode(value);
2947 let key = await createKey(secret, ["verify"]);
2948 try {
2949 let signature = byteStringToUint8Array(atob(hash));
2950 return await crypto.subtle.verify("HMAC", key, signature, data) ? value : false;
2951 } catch (e) {
2952 return false;
2953 }
2954};
2955const createKey = async (secret, usages) => crypto.subtle.importKey("raw", encoder.encode(secret), {
2956 name: "HMAC",
2957 hash: "SHA-256"
2958}, false, usages);
2959function byteStringToUint8Array(byteString) {
2960 let array = new Uint8Array(byteString.length);
2961 for (let i = 0; i < byteString.length; i++) array[i] = byteString.charCodeAt(i);
2962 return array;
2963}
2964//#endregion
2965//#region lib/server-runtime/cookies.ts
2966/**
2967* Creates a logical container for managing a browser cookie from the server.
2968*
2969* @public
2970* @category Utils
2971* @mode framework
2972* @mode data
2973* @param name The name of the cookie.
2974* @param cookieOptions Options for parsing and serializing the cookie.
2975* @returns A {@link Cookie} object for parsing and serializing the cookie.
2976*/
2977const createCookie = (name, cookieOptions = {}) => {
2978 let { secrets = [], ...options } = {
2979 path: "/",
2980 sameSite: "lax",
2981 ...cookieOptions
2982 };
2983 warnOnceAboutExpiresCookie(name, options.expires);
2984 return {
2985 get name() {
2986 return name;
2987 },
2988 get isSigned() {
2989 return secrets.length > 0;
2990 },
2991 get expires() {
2992 return typeof options.maxAge !== "undefined" ? new Date(Date.now() + options.maxAge * 1e3) : options.expires;
2993 },
2994 async parse(cookieHeader, parseOptions) {
2995 if (!cookieHeader) return null;
2996 let cookies = parse(cookieHeader, {
2997 ...options,
2998 ...parseOptions
2999 });
3000 if (name in cookies) {
3001 let value = cookies[name];
3002 if (typeof value === "string" && value !== "") return await decodeCookieValue(value, secrets);
3003 else return "";
3004 } else return null;
3005 },
3006 async serialize(value, serializeOptions) {
3007 return serialize(name, value === "" ? "" : await encodeCookieValue(value, secrets), {
3008 ...options,
3009 ...serializeOptions
3010 });
3011 }
3012 };
3013};
3014/**
3015* Returns `true` if a value is a React Router {@link Cookie} object.
3016*
3017* @public
3018* @category Utils
3019* @mode framework
3020* @mode data
3021* @param object The value to check.
3022* @returns `true` if the value is a React Router {@link Cookie} object;
3023* otherwise, `false`.
3024*/
3025const isCookie = (object) => {
3026 return object != null && typeof object.name === "string" && typeof object.isSigned === "boolean" && typeof object.parse === "function" && typeof object.serialize === "function";
3027};
3028async function encodeCookieValue(value, secrets) {
3029 let encoded = encodeData(value);
3030 if (secrets.length > 0) encoded = await sign(encoded, secrets[0]);
3031 return encoded;
3032}
3033async function decodeCookieValue(value, secrets) {
3034 if (secrets.length > 0) {
3035 for (let secret of secrets) {
3036 let unsignedValue = await unsign(value, secret);
3037 if (unsignedValue !== false) return decodeData(unsignedValue);
3038 }
3039 return null;
3040 }
3041 return decodeData(value);
3042}
3043function encodeData(value) {
3044 return btoa(myUnescape(encodeURIComponent(JSON.stringify(value))));
3045}
3046function decodeData(value) {
3047 try {
3048 return JSON.parse(decodeURIComponent(myEscape(atob(value))));
3049 } catch (e) {
3050 return {};
3051 }
3052}
3053function myEscape(value) {
3054 let str = value.toString();
3055 let result = "";
3056 let index = 0;
3057 let chr, code;
3058 while (index < str.length) {
3059 chr = str.charAt(index++);
3060 if (/[\w*+\-./@]/.exec(chr)) result += chr;
3061 else {
3062 code = chr.charCodeAt(0);
3063 if (code < 256) result += "%" + hex(code, 2);
3064 else result += "%u" + hex(code, 4).toUpperCase();
3065 }
3066 }
3067 return result;
3068}
3069function hex(code, length) {
3070 let result = code.toString(16);
3071 while (result.length < length) result = "0" + result;
3072 return result;
3073}
3074function myUnescape(value) {
3075 let str = value.toString();
3076 let result = "";
3077 let index = 0;
3078 let chr, part;
3079 while (index < str.length) {
3080 chr = str.charAt(index++);
3081 if (chr === "%") if (str.charAt(index) === "u") {
3082 part = str.slice(index + 1, index + 5);
3083 if (/^[\da-f]{4}$/i.exec(part)) {
3084 result += String.fromCharCode(parseInt(part, 16));
3085 index += 5;
3086 continue;
3087 }
3088 } else {
3089 part = str.slice(index, index + 2);
3090 if (/^[\da-f]{2}$/i.exec(part)) {
3091 result += String.fromCharCode(parseInt(part, 16));
3092 index += 2;
3093 continue;
3094 }
3095 }
3096 result += chr;
3097 }
3098 return result;
3099}
3100function warnOnceAboutExpiresCookie(name, expires) {
3101 warnOnce(!expires, `The "${name}" cookie has an "expires" property set. This will cause the expires value to not be updated when the session is committed. Instead, you should set the expires value when serializing the cookie. You can use \`commitSession(session, { expires })\` if using a session storage object, or \`cookie.serialize("value", { expires })\` if you're using the cookie directly.`);
3102}
3103//#endregion
3104//#region lib/server-runtime/sessions.ts
3105function flash(name) {
3106 return `__flash_${name}__`;
3107}
3108/**
3109* Creates a new Session object.
3110*
3111* Note: This function is typically not invoked directly by application code.
3112* Instead, use a `SessionStorage` object's `getSession` method.
3113*
3114* @category Utils
3115* @param initialData The initial data for the session.
3116* @param id The identifier for the session. Defaults to an empty string for a
3117* new session.
3118* @returns A new {@link Session} object.
3119*/
3120const createSession = (initialData = {}, id = "") => {
3121 let map = new Map(Object.entries(initialData));
3122 return {
3123 get id() {
3124 return id;
3125 },
3126 get data() {
3127 return Object.fromEntries(map);
3128 },
3129 has(name) {
3130 return map.has(name) || map.has(flash(name));
3131 },
3132 get(name) {
3133 if (map.has(name)) return map.get(name);
3134 let flashName = flash(name);
3135 if (map.has(flashName)) {
3136 let value = map.get(flashName);
3137 map.delete(flashName);
3138 return value;
3139 }
3140 },
3141 set(name, value) {
3142 map.set(name, value);
3143 },
3144 flash(name, value) {
3145 map.set(flash(name), value);
3146 },
3147 unset(name) {
3148 map.delete(name);
3149 }
3150 };
3151};
3152/**
3153* Returns `true` if a value is a React Router {@link Session} object.
3154*
3155* @public
3156* @category Utils
3157* @mode framework
3158* @mode data
3159* @param object The value to check.
3160* @returns `true` if the value is a React Router {@link Session} object;
3161* otherwise, `false`.
3162*/
3163const isSession = (object) => {
3164 return object != null && typeof object.id === "string" && typeof object.data !== "undefined" && typeof object.has === "function" && typeof object.get === "function" && typeof object.set === "function" && typeof object.flash === "function" && typeof object.unset === "function";
3165};
3166/**
3167* Creates a SessionStorage object using a SessionIdStorageStrategy.
3168*
3169* Note: This is a low-level API that should only be used if none of the
3170* existing session storage options meet your requirements.
3171*
3172* @category Utils
3173* @param strategy The strategy used to store session identifiers and data.
3174* @returns A {@link SessionStorage} object that persists session data using the
3175* provided strategy.
3176*/
3177function createSessionStorage({ cookie: cookieArg, createData, readData, updateData, deleteData }) {
3178 let cookie = isCookie(cookieArg) ? cookieArg : createCookie(cookieArg?.name || "__session", cookieArg);
3179 warnOnceAboutSigningSessionCookie(cookie);
3180 return {
3181 async getSession(cookieHeader, options) {
3182 let id = cookieHeader && await cookie.parse(cookieHeader, options);
3183 return createSession(id && await readData(id) || {}, id || "");
3184 },
3185 async commitSession(session, options) {
3186 let { id, data } = session;
3187 let expires = options?.maxAge != null ? new Date(Date.now() + options.maxAge * 1e3) : options?.expires != null ? options.expires : cookie.expires;
3188 if (id) await updateData(id, data, expires);
3189 else id = await createData(data, expires);
3190 return cookie.serialize(id, options);
3191 },
3192 async destroySession(session, options) {
3193 await deleteData(session.id);
3194 return cookie.serialize("", {
3195 ...options,
3196 maxAge: void 0,
3197 expires: /* @__PURE__ */ new Date(0)
3198 });
3199 }
3200 };
3201}
3202function warnOnceAboutSigningSessionCookie(cookie) {
3203 warnOnce(cookie.isSigned, `The "${cookie.name}" cookie is not signed, but session cookies should be signed to prevent tampering on the client before they are sent back to the server. See https://reactrouter.com/explanation/sessions-and-cookies#signing-cookies for more information.`);
3204}
3205//#endregion
3206//#region lib/server-runtime/sessions/cookieStorage.ts
3207/**
3208* Creates and returns a SessionStorage object that stores all session data
3209* directly in the session cookie itself.
3210*
3211* This has the advantage that no database or other backend services are
3212* needed, and can help to simplify some load-balanced scenarios. However, it
3213* also has the limitation that serialized session data may not exceed the
3214* browser's maximum cookie size. Trade-offs!
3215*
3216* @public
3217* @category Utils
3218* @mode framework
3219* @mode data
3220* @param options Options for creating the cookie-backed session storage.
3221* @returns A {@link SessionStorage} object that stores all session data in its
3222* cookie.
3223*/
3224function createCookieSessionStorage({ cookie: cookieArg } = {}) {
3225 let cookie = isCookie(cookieArg) ? cookieArg : createCookie(cookieArg?.name || "__session", cookieArg);
3226 warnOnceAboutSigningSessionCookie(cookie);
3227 return {
3228 async getSession(cookieHeader, options) {
3229 return createSession(cookieHeader && await cookie.parse(cookieHeader, options) || {});
3230 },
3231 async commitSession(session, options) {
3232 let serializedCookie = await cookie.serialize(session.data, options);
3233 if (serializedCookie.length > 4096) throw new Error("Cookie length will exceed browser maximum. Length: " + serializedCookie.length);
3234 return serializedCookie;
3235 },
3236 async destroySession(_session, options) {
3237 return cookie.serialize("", {
3238 ...options,
3239 maxAge: void 0,
3240 expires: /* @__PURE__ */ new Date(0)
3241 });
3242 }
3243 };
3244}
3245//#endregion
3246//#region lib/server-runtime/sessions/memoryStorage.ts
3247/**
3248* Creates and returns a simple in-memory SessionStorage object.
3249*
3250* Intended for local development and testing. It does not scale beyond a single
3251* process, and all session data is lost when the server process stops/restarts.
3252*
3253* @public
3254* @category Utils
3255* @mode framework
3256* @mode data
3257* @param options Options for creating the in-memory session storage.
3258* @returns A {@link SessionStorage} object that stores session data in memory.
3259*/
3260function createMemorySessionStorage({ cookie } = {}) {
3261 let map = /* @__PURE__ */ new Map();
3262 return createSessionStorage({
3263 cookie,
3264 async createData(data, expires) {
3265 let id = crypto.randomUUID();
3266 map.set(id, {
3267 data,
3268 expires
3269 });
3270 return id;
3271 },
3272 async readData(id) {
3273 if (map.has(id)) {
3274 let { data, expires } = map.get(id);
3275 if (!expires || expires > /* @__PURE__ */ new Date()) return data;
3276 if (expires) map.delete(id);
3277 }
3278 return null;
3279 },
3280 async updateData(id, data, expires) {
3281 map.set(id, {
3282 data,
3283 expires
3284 });
3285 },
3286 async deleteData(id) {
3287 map.delete(id);
3288 }
3289 });
3290}
3291//#endregion
3292export { Await, BrowserRouter, Form, HashRouter, Link, Links, MemoryRouter, Meta, NavLink, Navigate, Outlet, Route, Router, RouterContextProvider, RouterProvider, Routes, ScrollRestoration, StaticRouter, StaticRouterProvider, createContext, createCookie, createCookieSessionStorage, createMemorySessionStorage, createSession, createSessionStorage, createStaticHandler, data, href, isCookie, isRouteErrorResponse, isSession, matchRoutes, redirect, redirectDocument, replace, unstable_HistoryRouter, getRequest as unstable_getRequest, matchRSCServerRequest as unstable_matchRSCServerRequest };