UNPKG

130 kB JavaScript View Raw
1/**
2 * react-router v8.3.1
3 *
4 * Copyright (c) Remix Software Inc.
5 *
6 * This source code is licensed under the MIT license found in the
7 * LICENSE.md file in the root directory of this source tree.
8 *
9 * @license MIT
10 */
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 {}
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) Object.assign(updates, {
233 element: React.createElement(route.Component),
234 Component: void 0
235 });
236 if (route.HydrateFallback) Object.assign(updates, {
237 hydrateFallbackElement: React.createElement(route.HydrateFallback),
238 HydrateFallback: void 0
239 });
240 if (route.ErrorBoundary) Object.assign(updates, {
241 errorElement: React.createElement(route.ErrorBoundary),
242 ErrorBoundary: void 0
243 });
244 return updates;
245}
246function convertRoutesToDataRoutes(routes, mapRouteProperties = defaultMapRouteProperties, parentPath = [], manifest = {}, allowInPlaceMutations = false) {
247 return routes.map((route, index) => {
248 let treePath = [...parentPath, String(index)];
249 let id = typeof route.id === "string" ? route.id : treePath.join("-");
250 invariant$1(route.index !== true || !route.children, `Cannot specify children on an index route`);
251 invariant$1(allowInPlaceMutations || !manifest[id], `Found a route id collision on id "${id}". Route id's must be globally unique within Data Router usages`);
252 if (isIndexRoute(route)) {
253 let indexRoute = {
254 ...route,
255 id
256 };
257 manifest[id] = mergeRouteUpdates(indexRoute, mapRouteProperties(indexRoute));
258 return indexRoute;
259 } else {
260 let pathOrLayoutRoute = {
261 ...route,
262 id,
263 children: void 0
264 };
265 manifest[id] = mergeRouteUpdates(pathOrLayoutRoute, mapRouteProperties(pathOrLayoutRoute));
266 if (route.children) pathOrLayoutRoute.children = convertRoutesToDataRoutes(route.children, mapRouteProperties, treePath, manifest, allowInPlaceMutations);
267 return pathOrLayoutRoute;
268 }
269 });
270}
271function mergeRouteUpdates(route, updates) {
272 return Object.assign(route, {
273 ...updates,
274 ...typeof updates.lazy === "object" && updates.lazy != null ? { lazy: {
275 ...route.lazy,
276 ...updates.lazy
277 } } : {}
278 });
279}
280/**
281* Matches the given routes to a location and returns the match data.
282*
283* @example
284* import { matchRoutes } from "react-router";
285*
286* let routes = [{
287* path: "/",
288* Component: Root,
289* children: [{
290* path: "dashboard",
291* Component: Dashboard,
292* }]
293* }];
294*
295* matchRoutes(routes, "/dashboard"); // [rootMatch, dashboardMatch]
296*
297* @public
298* @category Utils
299* @param routes The array of route objects to match against.
300* @param locationArg The location to match against, either a string path or a
301* partial {@link Location} object
302* @param basename Optional base path to strip from the location before matching.
303* Defaults to `/`.
304* @returns An array of matched routes, or `null` if no matches were found.
305*/
306function matchRoutes(routes, locationArg, basename = "/") {
307 return matchRoutesImpl(routes, locationArg, basename, false);
308}
309function matchRoutesImpl(routes, locationArg, basename, allowPartial, precomputedBranches) {
310 let pathname = stripBasename((typeof locationArg === "string" ? parsePath(locationArg) : locationArg).pathname || "/", basename);
311 if (pathname == null) return null;
312 let branches = precomputedBranches ?? flattenAndRankRoutes(routes);
313 let matches = null;
314 let decoded = decodePath(pathname);
315 for (let i = 0; matches == null && i < branches.length; ++i) matches = matchRouteBranch(branches[i], decoded, allowPartial);
316 return matches;
317}
318function convertRouteMatchToUiMatch(match, loaderData) {
319 let { route, pathname, params } = match;
320 return {
321 id: route.id,
322 pathname,
323 params,
324 loaderData: loaderData[route.id],
325 handle: route.handle
326 };
327}
328function flattenAndRankRoutes(routes) {
329 let branches = flattenRoutes(routes);
330 rankRouteBranches(branches);
331 return branches;
332}
333function flattenRoutes(routes, branches = [], parentsMeta = [], parentPath = "", _hasParentOptionalSegments = false) {
334 let flattenRoute = (route, index, hasParentOptionalSegments = _hasParentOptionalSegments, relativePath) => {
335 let meta = {
336 relativePath: relativePath === void 0 ? route.path || "" : relativePath,
337 caseSensitive: route.caseSensitive === true,
338 childrenIndex: index,
339 route
340 };
341 if (meta.relativePath.startsWith("/")) {
342 if (!meta.relativePath.startsWith(parentPath) && hasParentOptionalSegments) return;
343 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.`);
344 meta.relativePath = meta.relativePath.slice(parentPath.length);
345 }
346 let path = joinPaths([parentPath, meta.relativePath]);
347 let routesMeta = parentsMeta.concat(meta);
348 if (route.children && route.children.length > 0) {
349 invariant$1(route.index !== true, `Index routes must not have child routes. Please remove all child routes from route path "${path}".`);
350 flattenRoutes(route.children, branches, routesMeta, path, hasParentOptionalSegments);
351 }
352 if (route.path == null && !route.index) return;
353 branches.push({
354 path,
355 score: computeScore(path, route.index),
356 routesMeta: routesMeta.map((meta, i) => {
357 let [matcher, params] = compilePath(meta.relativePath, meta.caseSensitive, i === routesMeta.length - 1);
358 return {
359 ...meta,
360 matcher,
361 compiledParams: params
362 };
363 })
364 });
365 };
366 routes.forEach((route, index) => {
367 if (route.path === "" || !route.path?.includes("?")) flattenRoute(route, index);
368 else for (let exploded of explodeOptionalSegments(route.path)) flattenRoute(route, index, true, exploded);
369 });
370 return branches;
371}
372function explodeOptionalSegments(path) {
373 let segments = path.split("/");
374 if (segments.length === 0) return [];
375 let [first, ...rest] = segments;
376 let isOptional = first.endsWith("?");
377 let required = first.replace(/\?$/, "");
378 if (rest.length === 0) return isOptional ? [required, ""] : [required];
379 let restExploded = explodeOptionalSegments(rest.join("/"));
380 let result = [];
381 result.push(...restExploded.map((subpath) => subpath === "" ? required : [required, subpath].join("/")));
382 if (isOptional) result.push(...restExploded);
383 return result.map((exploded) => path.startsWith("/") && exploded === "" ? "/" : exploded);
384}
385function rankRouteBranches(branches) {
386 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)));
387}
388const paramRe = /^:[\w-]+$/;
389const partialParamRe = /^:[\w-]+/;
390const partialDynamicSegmentValue = 3.5;
391const dynamicSegmentValue = 3;
392const indexRouteValue = 2;
393const emptySegmentValue = 1;
394const staticSegmentValue = 10;
395const splatPenalty = -2;
396const isSplat = (s) => s === "*";
397function computeScore(path, index) {
398 let segments = path.split("/");
399 let initialScore = segments.length;
400 if (segments.some(isSplat)) initialScore += splatPenalty;
401 if (index) initialScore += indexRouteValue;
402 return segments.filter((s) => !isSplat(s)).reduce((score, segment) => score + (paramRe.test(segment) ? dynamicSegmentValue : partialParamRe.test(segment) ? partialDynamicSegmentValue : segment === "" ? emptySegmentValue : staticSegmentValue), initialScore);
403}
404function compareIndexes(a, b) {
405 return a.length === b.length && a.slice(0, -1).every((n, i) => n === b[i]) ? a[a.length - 1] - b[b.length - 1] : 0;
406}
407function matchRouteBranch(branch, pathname, allowPartial = false) {
408 let { routesMeta } = branch;
409 let matchedParams = {};
410 let matchedPathname = "/";
411 let matches = [];
412 for (let i = 0; i < routesMeta.length; ++i) {
413 let meta = routesMeta[i];
414 let end = i === routesMeta.length - 1;
415 let remainingPathname = matchedPathname === "/" ? pathname : pathname.slice(matchedPathname.length) || "/";
416 let pattern = {
417 path: meta.relativePath,
418 caseSensitive: meta.caseSensitive,
419 end
420 };
421 let match = meta.matcher && meta.compiledParams ? matchPathImpl(pattern, remainingPathname, meta.matcher, meta.compiledParams) : matchPath(pattern, remainingPathname);
422 let route = meta.route;
423 if (!match && end && allowPartial && !routesMeta[routesMeta.length - 1].route.index) match = matchPath({
424 path: meta.relativePath,
425 caseSensitive: meta.caseSensitive,
426 end: false
427 }, remainingPathname);
428 if (!match) return null;
429 Object.assign(matchedParams, match.params);
430 matches.push({
431 params: matchedParams,
432 pathname: joinPaths([matchedPathname, match.pathname]),
433 pathnameBase: normalizePathname(joinPaths([matchedPathname, match.pathnameBase])),
434 route
435 });
436 if (match.pathnameBase !== "/") matchedPathname = joinPaths([matchedPathname, match.pathnameBase]);
437 }
438 return matches;
439}
440/**
441* Characters that `encodeURIComponent` escapes but that are valid literally in
442* a URL path segment. Per RFC 3986 §3.3, a path segment is made of `pchar`:
443*
444* ```
445* pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
446* sub-delims = "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / ";" / "="
447* ```
448*
449* `encodeURIComponent` targets query-string values, where `$ & + , ; = : @`
450* are delimiters and must be escaped — but in a path segment they carry no
451* special meaning, and browsers keep them literal in `location.pathname`.
452* (`! ' ( ) *` and the unreserved set are already left alone by
453* `encodeURIComponent`, so they need no restoring.)
454*/
455const PATH_PARAM_OVERESCAPED = {
456 "%24": "$",
457 "%26": "&",
458 "%2B": "+",
459 "%2C": ",",
460 "%3A": ":",
461 "%3B": ";",
462 "%3D": "=",
463 "%40": "@"
464};
465/**
466* Encodes a param value for interpolation into a single URL path segment.
467*
468* Escapes characters that would break the path (`/ ? # %`, whitespace,
469* non-ASCII, …) while leaving characters that RFC 3986 permits literally in a
470* path segment untouched. Escaping those would needlessly rewrite URLs — e.g.
471* a semver build param `1.0.0+1` would become `1.0.0%2B1` even though browsers
472* display and match the `+` literally in `location.pathname`.
473*
474* See [RFC 3986 §3.3](https://datatracker.ietf.org/doc/html/rfc3986#section-3.3))
475*
476* @param value The param value to encode.
477* @returns The encoded value, safe for use as a single path segment.
478*/
479function encodePathParam(value) {
480 return encodeURIComponent(value).replace(/%(?:24|26|2B|2C|3A|3B|3D|40)/g, (match) => PATH_PARAM_OVERESCAPED[match]);
481}
482/**
483* Performs pattern matching on a URL pathname and returns information about
484* the match.
485*
486* @public
487* @category Utils
488* @param pattern The pattern to match against the URL pathname. This can be a
489* string or a {@link PathPattern} object. If a string is provided, it will be
490* treated as a pattern with `caseSensitive` set to `false` and `end` set to
491* `true`.
492* @param pathname The URL pathname to match against the pattern.
493* @returns A path match object if the pattern matches the pathname,
494* or `null` if it does not match.
495*/
496function matchPath(pattern, pathname) {
497 if (typeof pattern === "string") pattern = {
498 path: pattern,
499 caseSensitive: false,
500 end: true
501 };
502 let [matcher, compiledParams] = compilePath(pattern.path, pattern.caseSensitive, pattern.end);
503 return matchPathImpl(pattern, pathname, matcher, compiledParams);
504}
505function matchPathImpl(pattern, pathname, matcher, compiledParams) {
506 let match = pathname.match(matcher);
507 if (!match) return null;
508 let matchedPathname = match[0];
509 let pathnameBase = removeTrailingSlash(matchedPathname, 1);
510 let captureGroups = match.slice(1);
511 return {
512 params: compiledParams.reduce((memo, { paramName, isOptional }, index) => {
513 if (paramName === "*") {
514 let splatValue = captureGroups[index] || "";
515 pathnameBase = removeTrailingSlash(matchedPathname.slice(0, matchedPathname.length - splatValue.length), 1);
516 }
517 const value = captureGroups[index];
518 if (isOptional && !value) memo[paramName] = void 0;
519 else memo[paramName] = (value || "").replace(/%2F/g, "/");
520 return memo;
521 }, {}),
522 pathname: matchedPathname,
523 pathnameBase,
524 pattern
525 };
526}
527function compilePath(path, caseSensitive = false, end = true) {
528 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(/\*$/, "/*")}".`);
529 let params = [];
530 let regexpSource = "^" + path.replace(/\/*\*?$/, "").replace(/^\/*/, "/").replace(/[\\.*+^${}|()[\]]/g, "\\$&").replace(/\/:([\w-]+)(\?)?/g, (match, paramName, isOptional, index, str) => {
531 params.push({
532 paramName,
533 isOptional: isOptional != null
534 });
535 if (isOptional) {
536 let nextChar = str.charAt(index + match.length);
537 if (nextChar && nextChar !== "/") return "/([^\\/]*)";
538 return "(?:/([^\\/]*))?";
539 }
540 return "/([^\\/]+)";
541 }).replace(/\/([\w-]+)\?(?=\/|$|\()/g, "(?:/$1)?");
542 if (path.endsWith("*")) {
543 params.push({ paramName: "*" });
544 regexpSource += path === "*" || path === "/*" ? "(.*)$" : "(?:\\/(.+)|\\/*)$";
545 } else if (end) regexpSource += "\\/*$";
546 else if (path !== "" && path !== "/") regexpSource += "(?:(?=\\/|$))";
547 return [new RegExp(regexpSource, caseSensitive ? void 0 : "i"), params];
548}
549function decodePath(value) {
550 try {
551 return value.split("/").map((v) => decodeURIComponent(v).replace(/\//g, "%2F")).join("/");
552 } catch (error) {
553 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}).`);
554 return value;
555 }
556}
557function stripBasename(pathname, basename) {
558 if (basename === "/") return pathname;
559 if (!pathname.toLowerCase().startsWith(basename.toLowerCase())) return null;
560 let startIndex = basename.endsWith("/") ? basename.length - 1 : basename.length;
561 let nextChar = pathname.charAt(startIndex);
562 if (nextChar && nextChar !== "/") return null;
563 return pathname.slice(startIndex) || "/";
564}
565function prependBasename({ basename, pathname }) {
566 return pathname === "/" ? basename : joinPaths([basename, pathname]);
567}
568const isAbsoluteUrl = (url) => ABSOLUTE_URL_REGEX.test(url);
569/**
570* Returns a resolved {@link Path} object relative to the given pathname.
571*
572* @public
573* @category Utils
574* @param to The path to resolve, either a string or a partial {@link Path}
575* object.
576* @param fromPathname The pathname to resolve the path from. Defaults to `/`.
577* @returns A {@link Path} object with the resolved pathname, search, and hash.
578*/
579function resolvePath(to, fromPathname = "/") {
580 let { pathname: toPathname, search = "", hash = "" } = typeof to === "string" ? parsePath(to) : to;
581 let pathname;
582 if (toPathname) {
583 toPathname = removeDoubleSlashes(toPathname);
584 if (toPathname.startsWith("/") || toPathname.startsWith("\\")) pathname = resolvePathname(toPathname.substring(1), "/");
585 else pathname = resolvePathname(toPathname, fromPathname);
586 } else pathname = fromPathname;
587 return {
588 pathname,
589 search: normalizeSearch(search),
590 hash: normalizeHash(hash)
591 };
592}
593function resolvePathname(relativePath, fromPathname) {
594 let segments = removeTrailingSlash(fromPathname).split("/");
595 relativePath.split("/").forEach((segment) => {
596 if (segment === "..") {
597 if (segments.length > 1) segments.pop();
598 } else if (segment !== ".") segments.push(segment);
599 });
600 return segments.length > 1 ? segments.join("/") : "/";
601}
602function getInvalidPathError(char, field, dest, path) {
603 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.`;
604}
605function getPathContributingMatches(matches) {
606 return matches.filter((match, index) => index === 0 || match.route.path && match.route.path.length > 0);
607}
608function getResolveToMatches(matches) {
609 let pathMatches = getPathContributingMatches(matches);
610 return pathMatches.map((match, idx) => idx === pathMatches.length - 1 ? match.pathname : match.pathnameBase);
611}
612function resolveTo(toArg, routePathnames, locationPathname, isPathRelative = false) {
613 let to;
614 if (typeof toArg === "string") to = parsePath(toArg);
615 else {
616 to = { ...toArg };
617 invariant$1(!to.pathname || !to.pathname.includes("?"), getInvalidPathError("?", "pathname", "search", to));
618 invariant$1(!to.pathname || !to.pathname.includes("#"), getInvalidPathError("#", "pathname", "hash", to));
619 invariant$1(!to.search || !to.search.includes("#"), getInvalidPathError("#", "search", "hash", to));
620 }
621 let isEmptyPath = toArg === "" || to.pathname === "";
622 let toPathname = isEmptyPath ? "/" : to.pathname;
623 let from;
624 if (toPathname == null) from = locationPathname;
625 else {
626 let routePathnameIndex = routePathnames.length - 1;
627 if (!isPathRelative && toPathname.startsWith("..")) {
628 let toSegments = toPathname.split("/");
629 while (toSegments[0] === "..") {
630 toSegments.shift();
631 routePathnameIndex -= 1;
632 }
633 to.pathname = toSegments.join("/");
634 }
635 from = routePathnameIndex >= 0 ? routePathnames[routePathnameIndex] : "/";
636 }
637 let path = resolvePath(to, from);
638 let hasExplicitTrailingSlash = toPathname && toPathname !== "/" && toPathname.endsWith("/");
639 let hasCurrentTrailingSlash = (isEmptyPath || toPathname === ".") && locationPathname.endsWith("/");
640 if (!path.pathname.endsWith("/") && (hasExplicitTrailingSlash || hasCurrentTrailingSlash)) path.pathname += "/";
641 return path;
642}
643const removeDoubleSlashes = (path) => path.replace(/[\\/]{2,}/g, "/");
644const joinPaths = (paths) => removeDoubleSlashes(paths.join("/"));
645function removeTrailingSlash(path, minLength = 0) {
646 let end = path.length;
647 while (end > minLength && path.charCodeAt(end - 1) === 47) end--;
648 return end === path.length ? path : path.slice(0, end);
649}
650const normalizePathname = (pathname) => removeTrailingSlash(pathname).replace(/^\/*/, "/");
651const normalizeSearch = (search) => !search || search === "?" ? "" : search.startsWith("?") ? search : "?" + search;
652const normalizeHash = (hash) => !hash || hash === "#" ? "" : hash.startsWith("#") ? hash : "#" + hash;
653var DataWithResponseInit = class {
654 type = "DataWithResponseInit";
655 data;
656 init;
657 constructor(data, init) {
658 this.data = data;
659 this.init = init || null;
660 }
661};
662/**
663* Create "responses" that contain `headers`/`status` without forcing
664* serialization into an actual [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response)
665*
666* @example
667* import { data } from "react-router";
668*
669* export async function action({ request }: Route.ActionArgs) {
670* let formData = await request.formData();
671* let item = await createItem(formData);
672* return data(item, {
673* headers: { "X-Custom-Header": "value" }
674* status: 201,
675* });
676* }
677*
678* @public
679* @category Utils
680* @mode framework
681* @mode data
682* @param data The data to be included in the response.
683* @param init The status code or a `ResponseInit` object to be included in the
684* response.
685* @returns A {@link DataWithResponseInit} instance containing the data and
686* response init.
687*/
688function data(data, init) {
689 return new DataWithResponseInit(data, typeof init === "number" ? { status: init } : init);
690}
691/**
692* A redirect [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response).
693* Sets the status code and the [`Location`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Location)
694* header. Defaults to [`302 Found`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/302).
695*
696* This utility accepts absolute URLs and can navigate to external domains, so
697* the application should validate any user-supplied inputs to redirects.
698*
699* @example
700* import { redirect } from "react-router";
701*
702* export async function loader({ request }: Route.LoaderArgs) {
703* if (!isLoggedIn(request))
704* throw redirect("/login");
705* }
706*
707* // ...
708* }
709*
710* @public
711* @category Utils
712* @mode framework
713* @mode data
714* @param url The URL to redirect to.
715* @param init The status code or a `ResponseInit` object to be included in the
716* response.
717* @returns A [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response)
718* object with the redirect status and [`Location`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Location)
719* header.
720*/
721const redirect$1 = (url, init = 302) => {
722 let responseInit = init;
723 if (typeof responseInit === "number") responseInit = { status: responseInit };
724 else if (typeof responseInit.status === "undefined") responseInit.status = 302;
725 let headers = new Headers(responseInit.headers);
726 headers.set("Location", url);
727 return new Response(null, {
728 ...responseInit,
729 headers
730 });
731};
732/**
733* A redirect [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response)
734* that will force a document reload to the new location. Sets the status code
735* and the [`Location`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Location)
736* header. Defaults to [`302 Found`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/302).
737*
738* This utility accepts absolute URLs and can navigate to external domains, so
739* the application should validate any user-supplied inputs to redirects.
740*
741* ```tsx filename=routes/logout.tsx
742* import { redirectDocument } from "react-router";
743*
744* import { destroySession } from "../sessions.server";
745*
746* export async function action({ request }: Route.ActionArgs) {
747* let session = await getSession(request.headers.get("Cookie"));
748* return redirectDocument("/", {
749* headers: { "Set-Cookie": await destroySession(session) }
750* });
751* }
752* ```
753*
754* @public
755* @category Utils
756* @mode framework
757* @mode data
758* @param url The URL to redirect to.
759* @param init The status code or a `ResponseInit` object to be included in the
760* response.
761* @returns A [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response)
762* object with the redirect status and [`Location`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Location)
763* header.
764*/
765const redirectDocument$1 = (url, init) => {
766 let response = redirect$1(url, init);
767 response.headers.set("X-Remix-Reload-Document", "true");
768 return response;
769};
770/**
771* A redirect [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response)
772* that will perform a [`history.replaceState`](https://developer.mozilla.org/en-US/docs/Web/API/History/replaceState)
773* instead of a [`history.pushState`](https://developer.mozilla.org/en-US/docs/Web/API/History/pushState)
774* for client-side navigation redirects. Sets the status code and the [`Location`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Location)
775* header. Defaults to [`302 Found`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/302).
776*
777* @example
778* import { replace } from "react-router";
779*
780* export async function loader() {
781* return replace("/new-location");
782* }
783*
784* @public
785* @category Utils
786* @mode framework
787* @mode data
788* @param url The URL to redirect to.
789* @param init The status code or a `ResponseInit` object to be included in the
790* response.
791* @returns A [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response)
792* object with the redirect status and [`Location`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Location)
793* header.
794*/
795const replace$1 = (url, init) => {
796 let response = redirect$1(url, init);
797 response.headers.set("X-Remix-Replace", "true");
798 return response;
799};
800var ErrorResponseImpl = class {
801 status;
802 statusText;
803 data;
804 error;
805 internal;
806 constructor(status, statusText, data, internal = false) {
807 this.status = status;
808 this.statusText = statusText || "";
809 this.internal = internal;
810 if (data instanceof Error) {
811 this.data = data.toString();
812 this.error = data;
813 } else this.data = data;
814 }
815};
816/**
817* Check if the given error is an {@link ErrorResponse} generated from a 4xx/5xx
818* [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response)
819* thrown from an [`action`](../../start/framework/route-module#action) or
820* [`loader`](../../start/framework/route-module#loader) function.
821*
822* @example
823* import { isRouteErrorResponse } from "react-router";
824*
825* export function ErrorBoundary({ error }: Route.ErrorBoundaryProps) {
826* if (isRouteErrorResponse(error)) {
827* return (
828* <>
829* <p>Error: `${error.status}: ${error.statusText}`</p>
830* <p>{error.data}</p>
831* </>
832* );
833* }
834*
835* return (
836* <p>Error: {error instanceof Error ? error.message : "Unknown Error"}</p>
837* );
838* }
839*
840* @public
841* @category Utils
842* @mode framework
843* @mode data
844* @param error The error to check.
845* @returns `true` if the error is an {@link ErrorResponse}, `false` otherwise.
846*/
847function isRouteErrorResponse(error) {
848 return error != null && typeof error.status === "number" && typeof error.statusText === "string" && typeof error.internal === "boolean" && "data" in error;
849}
850function getRoutePattern(matches) {
851 return joinPaths(matches.map((m) => m.route.path).filter(Boolean)) || "/";
852}
853function createDataFunctionUrl(request, path) {
854 let url = new URL(typeof request === "string" || request instanceof URL ? request : request.url);
855 let parsed = typeof path === "string" ? parsePath(path) : path;
856 url.pathname = parsed.pathname || "/";
857 if (parsed.search) {
858 let searchParams = new URLSearchParams(parsed.search);
859 let indexValues = searchParams.getAll("index");
860 searchParams.delete("index");
861 for (let value of indexValues.filter(Boolean)) searchParams.append("index", value);
862 let search = searchParams.toString();
863 url.search = search ? `?${search}` : "";
864 } else url.search = "";
865 url.hash = parsed.hash || "";
866 return url;
867}
868typeof window !== "undefined" && typeof window.document !== "undefined" && window.document.createElement;
869//#endregion
870//#region lib/router/instrumentation.ts
871const UninstrumentedSymbol = Symbol("Uninstrumented");
872function getRouteInstrumentationUpdates(fns, route) {
873 let aggregated = {
874 lazy: [],
875 "lazy.loader": [],
876 "lazy.action": [],
877 "lazy.middleware": [],
878 middleware: [],
879 loader: [],
880 action: []
881 };
882 fns.forEach((fn) => fn({
883 id: route.id,
884 index: route.index,
885 path: route.path,
886 instrument(i) {
887 if (i.lazy != null) aggregated.lazy.push(i.lazy);
888 if (i["lazy.loader"] != null) aggregated["lazy.loader"].push(i["lazy.loader"]);
889 if (i["lazy.action"] != null) aggregated["lazy.action"].push(i["lazy.action"]);
890 if (i["lazy.middleware"] != null) aggregated["lazy.middleware"].push(i["lazy.middleware"]);
891 if (i.middleware != null) aggregated.middleware.push(i.middleware);
892 if (i.loader != null) aggregated.loader.push(i.loader);
893 if (i.action != null) aggregated.action.push(i.action);
894 }
895 }));
896 let updates = {};
897 if (typeof route.lazy === "function" && aggregated.lazy.length > 0) {
898 let lazy = route.lazy;
899 updates.lazy = async (...args) => {
900 return throwOrReturnResult(await recurseRight(aggregated.lazy, void 0, () => lazy(...args), getInstrumentationInnerResult));
901 };
902 }
903 if (typeof route.lazy === "object") {
904 let lazyObject = route.lazy;
905 if (typeof lazyObject.middleware === "function" && aggregated["lazy.middleware"].length > 0) {
906 let middleware = lazyObject.middleware;
907 updates.lazy = Object.assign(updates.lazy || {}, { middleware: async (...args) => {
908 return throwOrReturnResult(await recurseRight(aggregated["lazy.middleware"], void 0, () => middleware(...args), getInstrumentationInnerResult));
909 } });
910 }
911 if (typeof lazyObject.loader === "function" && aggregated["lazy.loader"].length > 0) {
912 let loader = lazyObject.loader;
913 updates.lazy = Object.assign(updates.lazy || {}, { loader: async (...args) => {
914 return throwOrReturnResult(await recurseRight(aggregated["lazy.loader"], void 0, () => loader(...args), getInstrumentationInnerResult));
915 } });
916 }
917 if (typeof lazyObject.action === "function" && aggregated["lazy.action"].length > 0) {
918 let action = lazyObject.action;
919 updates.lazy = Object.assign(updates.lazy || {}, { action: async (...args) => {
920 return throwOrReturnResult(await recurseRight(aggregated["lazy.action"], void 0, () => action(...args), getInstrumentationInnerResult));
921 } });
922 }
923 }
924 if (typeof route.loader === "function" && aggregated.loader.length > 0) {
925 let original = getUninstrumentedHandler(route.loader);
926 let instrumented = async (...args) => {
927 return throwOrReturnResult(await recurseRight(aggregated.loader, getHandlerInfo(args[0]), () => original(...args), getInstrumentationInnerResult));
928 };
929 if (original.hydrate === true) instrumented.hydrate = true;
930 setUninstrumentedHandler(instrumented, original);
931 updates.loader = instrumented;
932 }
933 if (typeof route.action === "function" && aggregated.action.length > 0) {
934 let original = getUninstrumentedHandler(route.action);
935 let instrumented = async (...args) => {
936 return throwOrReturnResult(await recurseRight(aggregated.action, getHandlerInfo(args[0]), () => original(...args), getInstrumentationInnerResult));
937 };
938 setUninstrumentedHandler(instrumented, original);
939 updates.action = instrumented;
940 }
941 if (route.middleware && route.middleware.length > 0 && aggregated.middleware.length > 0) updates.middleware = route.middleware.map((middleware) => {
942 let original = getUninstrumentedHandler(middleware);
943 let instrumented = async (...args) => {
944 return throwOrReturnResult(await recurseRight(aggregated.middleware, getHandlerInfo(args[0]), () => original(...args), getInstrumentationInnerResult));
945 };
946 setUninstrumentedHandler(instrumented, original);
947 return instrumented;
948 });
949 return updates;
950}
951function getUninstrumentedHandler(handler) {
952 return handler[UninstrumentedSymbol] ?? handler;
953}
954function setUninstrumentedHandler(handler, uninstrumentedHandler) {
955 handler[UninstrumentedSymbol] = uninstrumentedHandler;
956}
957function throwOrReturnResult(result) {
958 if (result.type === "error") throw result.value;
959 return result.value;
960}
961async function recurseRight(impls, info, handler, getInnerResult, state = {
962 result: null,
963 innerResult: null
964}, index = impls.length - 1) {
965 let impl = impls[index];
966 if (!impl) {
967 try {
968 state.result = {
969 type: "success",
970 value: await handler()
971 };
972 } catch (e) {
973 state.result = {
974 type: "error",
975 value: e
976 };
977 }
978 state.innerResult = getInnerResult(state.result, info);
979 } else {
980 let handlerPromise = void 0;
981 let callHandler = async () => {
982 if (handlerPromise) console.error("You cannot call instrumented handlers more than once");
983 else handlerPromise = recurseRight(impls, info, handler, getInnerResult, state, index - 1);
984 await handlerPromise;
985 invariant$1(state.innerResult, "Expected an inner result");
986 return state.innerResult;
987 };
988 try {
989 await impl(callHandler, info);
990 } catch (e) {
991 console.error("An instrumentation function threw an error:", e);
992 }
993 if (!handlerPromise) await callHandler();
994 await handlerPromise;
995 }
996 if (state.result) return state.result;
997 state.result = {
998 type: "error",
999 value: /* @__PURE__ */ new Error("No result assigned in instrumentation chain.")
1000 };
1001 state.innerResult = getInnerResult(state.result, info);
1002 return state.result;
1003}
1004function getInstrumentationInnerResult(result) {
1005 if (result.type === "error" && result.value instanceof Error) return {
1006 status: "error",
1007 error: result.value
1008 };
1009 return {
1010 status: "success",
1011 error: void 0
1012 };
1013}
1014function getHandlerInfo(args) {
1015 let { request, context, params } = args;
1016 return {
1017 ...args,
1018 request: getReadonlyRequest(request),
1019 params: { ...params },
1020 context: getReadonlyContext(context)
1021 };
1022}
1023function getReadonlyRequest(request) {
1024 return {
1025 method: request.method,
1026 url: request.url,
1027 headers: { get: (...args) => request.headers.get(...args) }
1028 };
1029}
1030function getReadonlyContext(context) {
1031 return { get: (ctx) => context.get(ctx) };
1032}
1033//#endregion
1034//#region lib/router/router.ts
1035const validMutationMethodsArr = [
1036 "POST",
1037 "PUT",
1038 "PATCH",
1039 "DELETE"
1040];
1041const validMutationMethods = new Set(validMutationMethodsArr);
1042const validRequestMethodsArr = ["GET", ...validMutationMethodsArr];
1043const validRequestMethods = new Set(validRequestMethodsArr);
1044const redirectStatusCodes = new Set([
1045 301,
1046 302,
1047 303,
1048 307,
1049 308
1050]);
1051const ResetLoaderDataSymbol = Symbol("ResetLoaderData");
1052/**
1053* Create a static handler to perform server-side data loading
1054*
1055* @example
1056* export async function handleRequest(request: Request) {
1057* let { query, dataRoutes } = createStaticHandler(routes);
1058* let context = await query(request);
1059*
1060* if (context instanceof Response) {
1061* return context;
1062* }
1063*
1064* let router = createStaticRouter(dataRoutes, context);
1065* return new Response(
1066* ReactDOMServer.renderToString(<StaticRouterProvider ... />),
1067* { headers: { "Content-Type": "text/html" } }
1068* );
1069* }
1070*
1071* @public
1072* @category Data Routers
1073* @mode data
1074* @param routes The {@link RouteObject | route objects} to create a static
1075* handler for
1076* @param opts Options
1077* @param opts.basename The base URL for the static handler (default: `/`)
1078* @param opts.future Future flags for the static handler
1079* @returns A static handler that can be used to query data for the provided
1080* routes
1081*/
1082function createStaticHandler(routes, opts) {
1083 invariant$1(routes.length > 0, "You must provide a non-empty routes array to createStaticHandler");
1084 let manifest = {};
1085 let basename = (opts ? opts.basename : null) || "/";
1086 let _mapRouteProperties = opts?.mapRouteProperties;
1087 let mapRouteProperties = _mapRouteProperties ? _mapRouteProperties : () => ({});
1088 ({ ...opts?.future });
1089 if (opts?.instrumentations) {
1090 let instrumentations = opts.instrumentations;
1091 mapRouteProperties = (route) => {
1092 return {
1093 ..._mapRouteProperties?.(route),
1094 ...getRouteInstrumentationUpdates(instrumentations.map((i) => i.route).filter(Boolean), route)
1095 };
1096 };
1097 }
1098 let dataRoutes = convertRoutesToDataRoutes(routes, mapRouteProperties, void 0, manifest);
1099 let routeBranches = flattenAndRankRoutes(dataRoutes);
1100 /**
1101 * The query() method is intended for document requests, in which we want to
1102 * call an optional action and potentially multiple loaders for all nested
1103 * routes. It returns a StaticHandlerContext object, which is very similar
1104 * to the router state (location, loaderData, actionData, errors, etc.) and
1105 * also adds SSR-specific information such as the statusCode and headers
1106 * from action/loaders Responses.
1107 *
1108 * It _should_ never throw and should report all errors through the
1109 * returned handlerContext.errors object, properly associating errors to
1110 * their error boundary. Additionally, it tracks _deepestRenderedBoundaryId
1111 * which can be used to emulate React error boundaries during SSR by performing
1112 * a second pass only down to the boundaryId.
1113 *
1114 * The one exception where we do not return a StaticHandlerContext is when a
1115 * redirect response is returned or thrown from any action/loader. We
1116 * propagate that out and return the raw Response so the HTTP server can
1117 * return it directly.
1118 *
1119 * - `opts.requestContext` is an optional server context that will be passed
1120 * to actions/loaders in the `context` parameter
1121 * - `opts.skipLoaderErrorBubbling` is an optional parameter that will prevent
1122 * the bubbling of errors which allows single-fetch-type implementations
1123 * where the client will handle the bubbling and we may need to return data
1124 * for the handling route
1125 */
1126 async function query(request, { requestContext, filterMatchesToLoad, skipLoaderErrorBubbling, skipRevalidation, dataStrategy, generateMiddlewareResponse, normalizePath } = {}) {
1127 let normalizePathImpl = normalizePath || defaultNormalizePath;
1128 let method = request.method;
1129 let location = createLocation("", normalizePathImpl(request), null, "default");
1130 let matches = matchRoutesImpl(dataRoutes, location, basename, false, routeBranches);
1131 requestContext = requestContext != null ? requestContext : new RouterContextProvider();
1132 if (!isValidMethod(method) && method !== "HEAD") {
1133 let error = getInternalRouterError(405, { method });
1134 let { matches: methodNotAllowedMatches, route } = getShortCircuitMatches(dataRoutes);
1135 let staticContext = {
1136 basename,
1137 location,
1138 matches: methodNotAllowedMatches,
1139 loaderData: {},
1140 actionData: null,
1141 errors: { [route.id]: error },
1142 statusCode: error.status,
1143 loaderHeaders: {},
1144 actionHeaders: {}
1145 };
1146 return generateMiddlewareResponse ? generateMiddlewareResponse(() => Promise.resolve(staticContext)) : staticContext;
1147 } else if (!matches) {
1148 let error = getInternalRouterError(404, { pathname: location.pathname });
1149 let { matches: notFoundMatches, route } = getShortCircuitMatches(dataRoutes);
1150 let staticContext = {
1151 basename,
1152 location,
1153 matches: notFoundMatches,
1154 loaderData: {},
1155 actionData: null,
1156 errors: { [route.id]: error },
1157 statusCode: error.status,
1158 loaderHeaders: {},
1159 actionHeaders: {}
1160 };
1161 return generateMiddlewareResponse ? generateMiddlewareResponse(() => Promise.resolve(staticContext)) : staticContext;
1162 }
1163 if (generateMiddlewareResponse) {
1164 invariant$1(requestContext instanceof RouterContextProvider, "When using middleware in `staticHandler.query()`, any provided `requestContext` must be an instance of `RouterContextProvider`");
1165 try {
1166 await loadLazyMiddlewareForMatches(matches, manifest, mapRouteProperties);
1167 let renderedStaticContext;
1168 let response = await runServerMiddlewarePipeline({
1169 request,
1170 url: createDataFunctionUrl(request, location),
1171 pattern: getRoutePattern(matches),
1172 matches,
1173 params: matches[0].params,
1174 context: requestContext
1175 }, async () => {
1176 return await generateMiddlewareResponse(async (revalidationRequest, opts = {}) => {
1177 let result = await queryImpl(revalidationRequest, location, matches, requestContext, dataStrategy || null, skipLoaderErrorBubbling === true, null, "filterMatchesToLoad" in opts ? opts.filterMatchesToLoad ?? null : filterMatchesToLoad ?? null, skipRevalidation === true);
1178 if (isResponse(result)) return result;
1179 renderedStaticContext = {
1180 location,
1181 basename,
1182 ...result
1183 };
1184 return renderedStaticContext;
1185 });
1186 }, async (error, routeId) => {
1187 if (isRedirectResponse(error)) return error;
1188 if (isResponse(error)) try {
1189 error = new ErrorResponseImpl(error.status, error.statusText, await parseResponseBody(error));
1190 } catch (e) {
1191 error = e;
1192 }
1193 if (isDataWithResponseInit(error)) error = dataWithResponseInitToErrorResponse(error);
1194 if (renderedStaticContext) {
1195 if (routeId in renderedStaticContext.loaderData) renderedStaticContext.loaderData[routeId] = void 0;
1196 let staticContext = getStaticContextFromError(dataRoutes, renderedStaticContext, error, skipLoaderErrorBubbling ? routeId : findNearestBoundary(matches, routeId).route.id);
1197 return generateMiddlewareResponse(() => Promise.resolve(staticContext));
1198 } else {
1199 let staticContext = {
1200 matches,
1201 location,
1202 basename,
1203 loaderData: {},
1204 actionData: null,
1205 errors: { [skipLoaderErrorBubbling ? routeId : findNearestBoundary(matches, matches.find((m) => m.route.id === routeId || m.route.loader)?.route.id || routeId).route.id]: error },
1206 statusCode: isRouteErrorResponse(error) ? error.status : 500,
1207 actionHeaders: {},
1208 loaderHeaders: {}
1209 };
1210 return generateMiddlewareResponse(() => Promise.resolve(staticContext));
1211 }
1212 });
1213 invariant$1(isResponse(response), "Expected a response in query()");
1214 return response;
1215 } catch (e) {
1216 if (isResponse(e)) return e;
1217 throw e;
1218 }
1219 }
1220 let result = await queryImpl(request, location, matches, requestContext, dataStrategy || null, skipLoaderErrorBubbling === true, null, filterMatchesToLoad || null, skipRevalidation === true);
1221 if (isResponse(result)) return result;
1222 return {
1223 location,
1224 basename,
1225 ...result
1226 };
1227 }
1228 /**
1229 * The queryRoute() method is intended for targeted route requests, either
1230 * for fetch ?_data requests or resource route requests. In this case, we
1231 * are only ever calling a single action or loader, and we are returning the
1232 * returned value directly. In most cases, this will be a Response returned
1233 * from the action/loader, but it may be a primitive or other value as well -
1234 * and in such cases the calling context should handle that accordingly.
1235 *
1236 * We do respect the throw/return differentiation, so if an action/loader
1237 * throws, then this method will throw the value. This is important so we
1238 * can do proper boundary identification in Remix where a thrown Response
1239 * must go to the Catch Boundary but a returned Response is happy-path.
1240 *
1241 * One thing to note is that any Router-initiated Errors that make sense
1242 * to associate with a status code will be thrown as an ErrorResponse
1243 * instance which include the raw Error, such that the calling context can
1244 * serialize the error as they see fit while including the proper response
1245 * code. Examples here are 404 and 405 errors that occur prior to reaching
1246 * any user-defined loaders.
1247 *
1248 * - `opts.routeId` allows you to specify the specific route handler to call.
1249 * If not provided the handler will determine the proper route by matching
1250 * against `request.url`
1251 * - `opts.requestContext` is an optional server context that will be passed
1252 * to actions/loaders in the `context` parameter
1253 */
1254 async function queryRoute(request, { routeId, requestContext, dataStrategy, generateMiddlewareResponse, normalizePath } = {}) {
1255 let normalizePathImpl = normalizePath || defaultNormalizePath;
1256 let method = request.method;
1257 let location = createLocation("", normalizePathImpl(request), null, "default");
1258 let matches = matchRoutesImpl(dataRoutes, location, basename, false, routeBranches);
1259 requestContext = requestContext != null ? requestContext : new RouterContextProvider();
1260 if (!isValidMethod(method) && method !== "HEAD" && method !== "OPTIONS") throw getInternalRouterError(405, { method });
1261 else if (!matches) throw getInternalRouterError(404, { pathname: location.pathname });
1262 let match = routeId ? matches.find((m) => m.route.id === routeId) : getTargetMatch(matches, location);
1263 if (routeId && !match) throw getInternalRouterError(403, {
1264 pathname: location.pathname,
1265 routeId
1266 });
1267 else if (!match) throw getInternalRouterError(404, { pathname: location.pathname });
1268 if (generateMiddlewareResponse) {
1269 invariant$1(requestContext instanceof RouterContextProvider, "When using middleware in `staticHandler.queryRoute()`, any provided `requestContext` must be an instance of `RouterContextProvider`");
1270 await loadLazyMiddlewareForMatches(matches, manifest, mapRouteProperties);
1271 return await runServerMiddlewarePipeline({
1272 request,
1273 url: createDataFunctionUrl(request, location),
1274 pattern: getRoutePattern(matches),
1275 matches,
1276 params: matches[0].params,
1277 context: requestContext
1278 }, async () => {
1279 return await generateMiddlewareResponse(async (innerRequest) => {
1280 let processed = handleQueryResult(await queryImpl(innerRequest, location, matches, requestContext, dataStrategy || null, false, match, null, false));
1281 return isResponse(processed) ? processed : typeof processed === "string" ? new Response(processed) : Response.json(processed);
1282 });
1283 }, (error) => {
1284 if (isDataWithResponseInit(error)) return Promise.resolve(dataWithResponseInitToResponse(error));
1285 if (isResponse(error)) return Promise.resolve(error);
1286 throw error;
1287 });
1288 }
1289 return handleQueryResult(await queryImpl(request, location, matches, requestContext, dataStrategy || null, false, match, null, false));
1290 function handleQueryResult(result) {
1291 if (isResponse(result)) return result;
1292 let error = result.errors ? Object.values(result.errors)[0] : void 0;
1293 if (error !== void 0) throw error;
1294 if (result.actionData) return Object.values(result.actionData)[0];
1295 if (result.loaderData) return Object.values(result.loaderData)[0];
1296 }
1297 }
1298 async function queryImpl(request, location, matches, requestContext, dataStrategy, skipLoaderErrorBubbling, routeMatch, filterMatchesToLoad, skipRevalidation) {
1299 invariant$1(request.signal, "query()/queryRoute() requests must contain an AbortController signal");
1300 try {
1301 if (isMutationMethod(request.method)) return await submit(request, location, matches, routeMatch || getTargetMatch(matches, location), requestContext, dataStrategy, skipLoaderErrorBubbling, routeMatch != null, filterMatchesToLoad, skipRevalidation);
1302 let result = await loadRouteData(request, location, matches, requestContext, dataStrategy, skipLoaderErrorBubbling, routeMatch, filterMatchesToLoad);
1303 return isResponse(result) ? result : {
1304 ...result,
1305 actionData: null,
1306 actionHeaders: {}
1307 };
1308 } catch (e) {
1309 if (isDataStrategyResult(e) && isResponse(e.result)) {
1310 if (e.type === "error") throw e.result;
1311 return e.result;
1312 }
1313 if (isRedirectResponse(e)) return e;
1314 throw e;
1315 }
1316 }
1317 async function submit(request, location, matches, actionMatch, requestContext, dataStrategy, skipLoaderErrorBubbling, isRouteRequest, filterMatchesToLoad, skipRevalidation) {
1318 let result;
1319 if (!actionMatch.route.action && !actionMatch.route.lazy) {
1320 let error = getInternalRouterError(405, {
1321 method: request.method,
1322 pathname: new URL(request.url).pathname,
1323 routeId: actionMatch.route.id
1324 });
1325 if (isRouteRequest) throw error;
1326 result = {
1327 type: "error",
1328 error
1329 };
1330 } else {
1331 result = (await callDataStrategy(request, location, getTargetedDataStrategyMatches(mapRouteProperties, manifest, request, location, matches, actionMatch, [], requestContext), isRouteRequest, requestContext, dataStrategy))[actionMatch.route.id];
1332 if (request.signal.aborted) throwStaticHandlerAbortedError(request, isRouteRequest);
1333 }
1334 if (isRedirectResult(result)) throw new Response(null, {
1335 status: result.response.status,
1336 headers: { Location: result.response.headers.get("Location") }
1337 });
1338 if (isRouteRequest) {
1339 if (isErrorResult(result)) throw result.error;
1340 return {
1341 matches: [actionMatch],
1342 loaderData: {},
1343 actionData: { [actionMatch.route.id]: result.data },
1344 errors: null,
1345 statusCode: 200,
1346 loaderHeaders: {},
1347 actionHeaders: {}
1348 };
1349 }
1350 if (skipRevalidation) if (isErrorResult(result)) {
1351 let boundaryMatch = skipLoaderErrorBubbling ? actionMatch : findNearestBoundary(matches, actionMatch.route.id);
1352 return {
1353 statusCode: isRouteErrorResponse(result.error) ? result.error.status : result.statusCode != null ? result.statusCode : 500,
1354 actionData: null,
1355 actionHeaders: { ...result.headers ? { [actionMatch.route.id]: result.headers } : {} },
1356 matches,
1357 loaderData: {},
1358 errors: { [boundaryMatch.route.id]: result.error },
1359 loaderHeaders: {}
1360 };
1361 } else return {
1362 actionData: { [actionMatch.route.id]: result.data },
1363 actionHeaders: result.headers ? { [actionMatch.route.id]: result.headers } : {},
1364 matches,
1365 loaderData: {},
1366 errors: null,
1367 statusCode: result.statusCode || 200,
1368 loaderHeaders: {}
1369 };
1370 let loaderRequest = new Request(request.url, {
1371 headers: request.headers,
1372 redirect: request.redirect,
1373 signal: request.signal
1374 });
1375 if (isErrorResult(result)) return {
1376 ...await loadRouteData(loaderRequest, location, matches, requestContext, dataStrategy, skipLoaderErrorBubbling, null, filterMatchesToLoad, [(skipLoaderErrorBubbling ? actionMatch : findNearestBoundary(matches, actionMatch.route.id)).route.id, result]),
1377 statusCode: isRouteErrorResponse(result.error) ? result.error.status : result.statusCode != null ? result.statusCode : 500,
1378 actionData: null,
1379 actionHeaders: { ...result.headers ? { [actionMatch.route.id]: result.headers } : {} }
1380 };
1381 return {
1382 ...await loadRouteData(loaderRequest, location, matches, requestContext, dataStrategy, skipLoaderErrorBubbling, null, filterMatchesToLoad),
1383 actionData: { [actionMatch.route.id]: result.data },
1384 ...result.statusCode ? { statusCode: result.statusCode } : {},
1385 actionHeaders: result.headers ? { [actionMatch.route.id]: result.headers } : {}
1386 };
1387 }
1388 async function loadRouteData(request, location, matches, requestContext, dataStrategy, skipLoaderErrorBubbling, routeMatch, filterMatchesToLoad, pendingActionResult) {
1389 let isRouteRequest = routeMatch != null;
1390 if (isRouteRequest && !routeMatch?.route.loader && !routeMatch?.route.lazy) throw getInternalRouterError(400, {
1391 method: request.method,
1392 pathname: new URL(request.url).pathname,
1393 routeId: routeMatch?.route.id
1394 });
1395 let dsMatches;
1396 if (routeMatch) dsMatches = getTargetedDataStrategyMatches(mapRouteProperties, manifest, request, location, matches, routeMatch, [], requestContext);
1397 else {
1398 let maxIdx = pendingActionResult && isErrorResult(pendingActionResult[1]) ? matches.findIndex((m) => m.route.id === pendingActionResult[0]) - 1 : void 0;
1399 let pattern = getRoutePattern(matches);
1400 dsMatches = matches.map((match, index) => {
1401 if (maxIdx != null && index > maxIdx) return getDataStrategyMatch(mapRouteProperties, manifest, request, location, pattern, match, [], requestContext, false);
1402 return getDataStrategyMatch(mapRouteProperties, manifest, request, location, pattern, match, [], requestContext, (match.route.loader || match.route.lazy) != null && (!filterMatchesToLoad || filterMatchesToLoad(match)));
1403 });
1404 }
1405 if (!dataStrategy && !dsMatches.some((m) => m.shouldLoad)) return {
1406 matches,
1407 loaderData: {},
1408 errors: pendingActionResult && isErrorResult(pendingActionResult[1]) ? { [pendingActionResult[0]]: pendingActionResult[1].error } : null,
1409 statusCode: 200,
1410 loaderHeaders: {}
1411 };
1412 let results = await callDataStrategy(request, location, dsMatches, isRouteRequest, requestContext, dataStrategy);
1413 if (request.signal.aborted) throwStaticHandlerAbortedError(request, isRouteRequest);
1414 return {
1415 ...processRouteLoaderData(matches, results, pendingActionResult, true, skipLoaderErrorBubbling),
1416 matches
1417 };
1418 }
1419 async function callDataStrategy(request, location, matches, isRouteRequest, requestContext, dataStrategy) {
1420 let results = await callDataStrategyImpl(dataStrategy || defaultDataStrategy, request, location, matches, null, requestContext, true);
1421 let dataResults = {};
1422 await Promise.all(matches.map(async (match) => {
1423 if (!(match.route.id in results)) return;
1424 let result = results[match.route.id];
1425 if (isRedirectDataStrategyResult(result)) {
1426 let response = result.result;
1427 throw normalizeRelativeRoutingRedirectResponse(response, request, match.route.id, matches, basename);
1428 }
1429 if (isRouteRequest) {
1430 if (isResponse(result.result)) throw result;
1431 else if (isDataWithResponseInit(result.result)) throw dataWithResponseInitToResponse(result.result);
1432 }
1433 dataResults[match.route.id] = await convertDataStrategyResultToDataResult(result);
1434 }));
1435 return dataResults;
1436 }
1437 return {
1438 dataRoutes,
1439 _internalRouteBranches: routeBranches,
1440 query,
1441 queryRoute
1442 };
1443}
1444/**
1445* Given an existing StaticHandlerContext and an error thrown at render time,
1446* provide an updated StaticHandlerContext suitable for a second SSR render
1447*
1448* @category Utils
1449*/
1450function getStaticContextFromError(routes, handlerContext, error, boundaryId) {
1451 let errorBoundaryId = boundaryId || handlerContext._deepestRenderedBoundaryId || routes[0].id;
1452 return {
1453 ...handlerContext,
1454 statusCode: isRouteErrorResponse(error) ? error.status : 500,
1455 errors: { [errorBoundaryId]: error }
1456 };
1457}
1458function throwStaticHandlerAbortedError(request, isRouteRequest) {
1459 if (request.signal.reason !== void 0) throw request.signal.reason;
1460 throw new Error(`${isRouteRequest ? "queryRoute" : "query"}() call aborted without an \`AbortSignal.reason\`: ${request.method} ${request.url}`);
1461}
1462function defaultNormalizePath(request) {
1463 let url = new URL(request.url);
1464 return {
1465 pathname: url.pathname,
1466 search: url.search,
1467 hash: url.hash
1468 };
1469}
1470function normalizeTo(location, matches, basename, to, fromRouteId, relative) {
1471 let contextualMatches;
1472 let activeRouteMatch;
1473 if (fromRouteId) {
1474 contextualMatches = [];
1475 for (let match of matches) {
1476 contextualMatches.push(match);
1477 if (match.route.id === fromRouteId) {
1478 activeRouteMatch = match;
1479 break;
1480 }
1481 }
1482 } else {
1483 contextualMatches = matches;
1484 activeRouteMatch = matches[matches.length - 1];
1485 }
1486 let path = resolveTo(to ? to : ".", getResolveToMatches(contextualMatches), stripBasename(location.pathname, basename) || location.pathname, relative === "path");
1487 if (to == null) {
1488 path.search = location.search;
1489 path.hash = location.hash;
1490 }
1491 if ((to == null || to === "" || to === ".") && activeRouteMatch) {
1492 let nakedIndex = hasNakedIndexQuery(path.search);
1493 if (activeRouteMatch.route.index && !nakedIndex) path.search = path.search ? path.search.replace(/^\?/, "?index&") : "?index";
1494 else if (!activeRouteMatch.route.index && nakedIndex) {
1495 let params = new URLSearchParams(path.search);
1496 let indexValues = params.getAll("index");
1497 params.delete("index");
1498 indexValues.filter((v) => v).forEach((v) => params.append("index", v));
1499 let qs = params.toString();
1500 path.search = qs ? `?${qs}` : "";
1501 }
1502 }
1503 if (basename !== "/") path.pathname = prependBasename({
1504 basename,
1505 pathname: path.pathname
1506 });
1507 return createPath(path);
1508}
1509function shouldRevalidateLoader(loaderMatch, arg) {
1510 if (loaderMatch.route.shouldRevalidate) {
1511 let routeChoice = loaderMatch.route.shouldRevalidate(arg);
1512 if (typeof routeChoice === "boolean") return routeChoice;
1513 }
1514 return arg.defaultShouldRevalidate;
1515}
1516const lazyRoutePropertyCache = /* @__PURE__ */ new WeakMap();
1517const loadLazyRouteProperty = ({ key, route, manifest, mapRouteProperties }) => {
1518 let routeToUpdate = manifest[route.id];
1519 invariant$1(routeToUpdate, "No route found in manifest");
1520 if (!routeToUpdate.lazy || typeof routeToUpdate.lazy !== "object") return;
1521 let lazyFn = routeToUpdate.lazy[key];
1522 if (!lazyFn) return;
1523 let cache = lazyRoutePropertyCache.get(routeToUpdate);
1524 if (!cache) {
1525 cache = {};
1526 lazyRoutePropertyCache.set(routeToUpdate, cache);
1527 }
1528 let cachedPromise = cache[key];
1529 if (cachedPromise) return cachedPromise;
1530 let propertyPromise = (async () => {
1531 let isUnsupported = isUnsupportedLazyRouteObjectKey(key);
1532 let isStaticallyDefined = routeToUpdate[key] !== void 0;
1533 if (isUnsupported) {
1534 warning(!isUnsupported, "Route property " + key + " is not a supported lazy route property. This property will be ignored.");
1535 cache[key] = Promise.resolve();
1536 } else if (isStaticallyDefined) warning(false, `Route "${routeToUpdate.id}" has a static property "${key}" defined. The lazy property will be ignored.`);
1537 else {
1538 let value = await lazyFn();
1539 if (value != null) {
1540 Object.assign(routeToUpdate, { [key]: value });
1541 Object.assign(routeToUpdate, mapRouteProperties(routeToUpdate));
1542 }
1543 }
1544 if (typeof routeToUpdate.lazy === "object") {
1545 routeToUpdate.lazy[key] = void 0;
1546 if (Object.values(routeToUpdate.lazy).every((value) => value === void 0)) routeToUpdate.lazy = void 0;
1547 }
1548 })();
1549 cache[key] = propertyPromise;
1550 return propertyPromise;
1551};
1552const lazyRouteFunctionCache = /* @__PURE__ */ new WeakMap();
1553/**
1554* Execute route.lazy functions to lazily load route modules (loader, action,
1555* shouldRevalidate) and update the routeManifest in place which shares objects
1556* with dataRoutes so those get updated as well.
1557*/
1558function loadLazyRoute(route, type, manifest, mapRouteProperties, lazyRoutePropertiesToSkip) {
1559 let routeToUpdate = manifest[route.id];
1560 invariant$1(routeToUpdate, "No route found in manifest");
1561 if (!route.lazy) return {
1562 lazyRoutePromise: void 0,
1563 lazyHandlerPromise: void 0
1564 };
1565 if (typeof route.lazy === "function") {
1566 let cachedPromise = lazyRouteFunctionCache.get(routeToUpdate);
1567 if (cachedPromise) return {
1568 lazyRoutePromise: cachedPromise,
1569 lazyHandlerPromise: cachedPromise
1570 };
1571 let lazyRoutePromise = (async () => {
1572 invariant$1(typeof route.lazy === "function", "No lazy route function found");
1573 let lazyRoute = await route.lazy();
1574 let routeUpdates = {};
1575 for (let lazyRouteProperty in lazyRoute) {
1576 let lazyValue = lazyRoute[lazyRouteProperty];
1577 if (lazyValue === void 0) continue;
1578 let isUnsupported = isUnsupportedLazyRouteFunctionKey(lazyRouteProperty);
1579 let isStaticallyDefined = routeToUpdate[lazyRouteProperty] !== void 0;
1580 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.");
1581 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.`);
1582 else routeUpdates[lazyRouteProperty] = lazyValue;
1583 }
1584 Object.assign(routeToUpdate, routeUpdates);
1585 Object.assign(routeToUpdate, {
1586 ...mapRouteProperties(routeToUpdate),
1587 lazy: void 0
1588 });
1589 })();
1590 lazyRouteFunctionCache.set(routeToUpdate, lazyRoutePromise);
1591 lazyRoutePromise.catch(() => {});
1592 return {
1593 lazyRoutePromise,
1594 lazyHandlerPromise: lazyRoutePromise
1595 };
1596 }
1597 let lazyKeys = Object.keys(route.lazy);
1598 let lazyPropertyPromises = [];
1599 let lazyHandlerPromise = void 0;
1600 for (let key of lazyKeys) {
1601 if (lazyRoutePropertiesToSkip && lazyRoutePropertiesToSkip.includes(key)) continue;
1602 let promise = loadLazyRouteProperty({
1603 key,
1604 route,
1605 manifest,
1606 mapRouteProperties
1607 });
1608 if (promise) {
1609 lazyPropertyPromises.push(promise);
1610 if (key === type) lazyHandlerPromise = promise;
1611 }
1612 }
1613 let lazyRoutePromise = lazyPropertyPromises.length > 0 ? Promise.all(lazyPropertyPromises).then(() => {}) : void 0;
1614 lazyRoutePromise?.catch(() => {});
1615 lazyHandlerPromise?.catch(() => {});
1616 return {
1617 lazyRoutePromise,
1618 lazyHandlerPromise
1619 };
1620}
1621function isNonNullable(value) {
1622 return value !== void 0;
1623}
1624function loadLazyMiddlewareForMatches(matches, manifest, mapRouteProperties) {
1625 let promises = matches.map(({ route }) => {
1626 if (typeof route.lazy !== "object" || !route.lazy.middleware) return;
1627 return loadLazyRouteProperty({
1628 key: "middleware",
1629 route,
1630 manifest,
1631 mapRouteProperties
1632 });
1633 }).filter(isNonNullable);
1634 return promises.length > 0 ? Promise.all(promises) : void 0;
1635}
1636async function defaultDataStrategy(args) {
1637 let matchesToLoad = args.matches.filter((m) => m.shouldLoad);
1638 let keyedResults = {};
1639 (await Promise.all(matchesToLoad.map((m) => m.resolve()))).forEach((result, i) => {
1640 keyedResults[matchesToLoad[i].route.id] = result;
1641 });
1642 return keyedResults;
1643}
1644function runServerMiddlewarePipeline(args, handler, errorHandler) {
1645 return runMiddlewarePipeline(args, handler, processResult, isResponse, errorHandler);
1646 function processResult(result) {
1647 return isDataWithResponseInit(result) ? dataWithResponseInitToResponse(result) : result;
1648 }
1649}
1650function runClientMiddlewarePipeline(args, handler) {
1651 return runMiddlewarePipeline(args, handler, (r) => {
1652 if (isRedirectResponse(r)) throw r;
1653 return r;
1654 }, isDataStrategyResults, errorHandler);
1655 async function errorHandler(error, routeId, nextResult) {
1656 if (nextResult) return Object.assign(nextResult.value, { [routeId]: {
1657 type: "error",
1658 result: error
1659 } });
1660 else {
1661 let { matches } = args;
1662 let maxBoundaryIdx = Math.min(Math.max(matches.findIndex((m) => m.route.id === routeId), 0), Math.max(matches.findIndex((m) => m.shouldCallHandler()), 0));
1663 let deepestRouteId = matches[maxBoundaryIdx].route.id;
1664 for (let match of matches.slice(0, maxBoundaryIdx + 1)) try {
1665 await match._lazyPromises?.route;
1666 } catch {
1667 deepestRouteId = match.route.id;
1668 break;
1669 }
1670 return { [findNearestBoundary(matches, deepestRouteId).route.id]: {
1671 type: "error",
1672 result: error
1673 } };
1674 }
1675 }
1676}
1677async function runMiddlewarePipeline(args, handler, processResult, isResult, errorHandler) {
1678 let { matches, ...dataFnArgs } = args;
1679 return await callRouteMiddleware(dataFnArgs, matches.flatMap((m) => m.route.middleware ? m.route.middleware.map((fn) => [m.route.id, fn]) : []), handler, processResult, isResult, errorHandler);
1680}
1681async function callRouteMiddleware(args, middlewares, handler, processResult, isResult, errorHandler, idx = 0) {
1682 let { request } = args;
1683 if (request.signal.aborted) throw request.signal.reason ?? /* @__PURE__ */ new Error(`Request aborted: ${request.method} ${request.url}`);
1684 let tuple = middlewares[idx];
1685 if (!tuple) return await handler();
1686 let [routeId, middleware] = tuple;
1687 let nextResult;
1688 let next = async () => {
1689 if (nextResult) throw new Error("You may only call `next()` once per middleware");
1690 try {
1691 nextResult = { value: await callRouteMiddleware(args, middlewares, handler, processResult, isResult, errorHandler, idx + 1) };
1692 return nextResult.value;
1693 } catch (error) {
1694 nextResult = { value: await errorHandler(error, routeId, nextResult) };
1695 return nextResult.value;
1696 }
1697 };
1698 try {
1699 let value = await middleware(args, next);
1700 let result = value != null ? processResult(value) : void 0;
1701 if (isResult(result)) return result;
1702 else if (nextResult) return result ?? nextResult.value;
1703 else {
1704 nextResult = { value: await next() };
1705 return nextResult.value;
1706 }
1707 } catch (error) {
1708 return await errorHandler(error, routeId, nextResult);
1709 }
1710}
1711function getDataStrategyMatchLazyPromises(mapRouteProperties, manifest, request, match, lazyRoutePropertiesToSkip) {
1712 let lazyMiddlewarePromise = loadLazyRouteProperty({
1713 key: "middleware",
1714 route: match.route,
1715 manifest,
1716 mapRouteProperties
1717 });
1718 let lazyRoutePromises = loadLazyRoute(match.route, isMutationMethod(request.method) ? "action" : "loader", manifest, mapRouteProperties, lazyRoutePropertiesToSkip);
1719 return {
1720 middleware: lazyMiddlewarePromise,
1721 route: lazyRoutePromises.lazyRoutePromise,
1722 handler: lazyRoutePromises.lazyHandlerPromise
1723 };
1724}
1725function getDataStrategyMatch(mapRouteProperties, manifest, request, path, pattern, match, lazyRoutePropertiesToSkip, scopedContext, shouldLoad, shouldRevalidateArgs = null, callSiteDefaultShouldRevalidate) {
1726 let isUsingNewApi = false;
1727 let _lazyPromises = getDataStrategyMatchLazyPromises(mapRouteProperties, manifest, request, match, lazyRoutePropertiesToSkip);
1728 return {
1729 ...match,
1730 _lazyPromises,
1731 shouldLoad,
1732 shouldRevalidateArgs,
1733 shouldCallHandler(defaultShouldRevalidate) {
1734 isUsingNewApi = true;
1735 if (!shouldRevalidateArgs) return shouldLoad;
1736 if (typeof callSiteDefaultShouldRevalidate === "boolean") return shouldRevalidateLoader(match, {
1737 ...shouldRevalidateArgs,
1738 defaultShouldRevalidate: callSiteDefaultShouldRevalidate
1739 });
1740 if (typeof defaultShouldRevalidate === "boolean") return shouldRevalidateLoader(match, {
1741 ...shouldRevalidateArgs,
1742 defaultShouldRevalidate
1743 });
1744 return shouldRevalidateLoader(match, shouldRevalidateArgs);
1745 },
1746 resolve(handlerOverride) {
1747 let { lazy, loader, middleware } = match.route;
1748 let callHandler = isUsingNewApi || shouldLoad || handlerOverride && !isMutationMethod(request.method) && (lazy || loader);
1749 let isMiddlewareOnlyRoute = middleware && middleware.length > 0 && !loader && !lazy;
1750 if (callHandler && (isMutationMethod(request.method) || !isMiddlewareOnlyRoute)) return callLoaderOrAction({
1751 request,
1752 path,
1753 pattern,
1754 match,
1755 lazyHandlerPromise: _lazyPromises?.handler,
1756 lazyRoutePromise: _lazyPromises?.route,
1757 handlerOverride,
1758 scopedContext
1759 });
1760 return Promise.resolve({
1761 type: "data",
1762 result: void 0
1763 });
1764 }
1765 };
1766}
1767function getTargetedDataStrategyMatches(mapRouteProperties, manifest, request, path, matches, targetMatch, lazyRoutePropertiesToSkip, scopedContext, shouldRevalidateArgs = null) {
1768 return matches.map((match) => {
1769 if (match.route.id !== targetMatch.route.id) return {
1770 ...match,
1771 shouldLoad: false,
1772 shouldRevalidateArgs,
1773 shouldCallHandler: () => false,
1774 _lazyPromises: getDataStrategyMatchLazyPromises(mapRouteProperties, manifest, request, match, lazyRoutePropertiesToSkip),
1775 resolve: () => Promise.resolve({
1776 type: "data",
1777 result: void 0
1778 })
1779 };
1780 return getDataStrategyMatch(mapRouteProperties, manifest, request, path, getRoutePattern(matches), match, lazyRoutePropertiesToSkip, scopedContext, true, shouldRevalidateArgs);
1781 });
1782}
1783async function callDataStrategyImpl(dataStrategyImpl, request, path, matches, fetcherKey, scopedContext, isStaticHandler) {
1784 if (matches.some((m) => m._lazyPromises?.middleware)) await Promise.all(matches.map((m) => m._lazyPromises?.middleware));
1785 let dataStrategyArgs = {
1786 request,
1787 url: createDataFunctionUrl(request, path),
1788 pattern: getRoutePattern(matches),
1789 params: matches[0].params,
1790 context: scopedContext,
1791 matches
1792 };
1793 let runClientMiddleware = isStaticHandler ? () => {
1794 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`");
1795 } : (cb) => {
1796 let typedDataStrategyArgs = dataStrategyArgs;
1797 return runClientMiddlewarePipeline(typedDataStrategyArgs, () => {
1798 return cb({
1799 ...typedDataStrategyArgs,
1800 fetcherKey,
1801 runClientMiddleware: () => {
1802 throw new Error("Cannot call `runClientMiddleware()` from within an `runClientMiddleware` handler");
1803 }
1804 });
1805 });
1806 };
1807 let results = await dataStrategyImpl({
1808 ...dataStrategyArgs,
1809 fetcherKey,
1810 runClientMiddleware
1811 });
1812 try {
1813 await Promise.all(matches.flatMap((m) => [m._lazyPromises?.handler, m._lazyPromises?.route]));
1814 } catch {}
1815 return results;
1816}
1817async function callLoaderOrAction({ request, path, pattern, match, lazyHandlerPromise, lazyRoutePromise, handlerOverride, scopedContext }) {
1818 let result;
1819 let onReject;
1820 let isAction = isMutationMethod(request.method);
1821 let type = isAction ? "action" : "loader";
1822 let runHandler = (handler) => {
1823 let reject;
1824 let abortPromise = new Promise((_, r) => reject = r);
1825 onReject = () => reject();
1826 request.signal.addEventListener("abort", onReject);
1827 let actualHandler = (ctx) => {
1828 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}]`));
1829 return handler({
1830 request,
1831 url: createDataFunctionUrl(request, path),
1832 pattern,
1833 params: match.params,
1834 context: scopedContext
1835 }, ...ctx !== void 0 ? [ctx] : []);
1836 };
1837 let handlerPromise = (async () => {
1838 try {
1839 return {
1840 type: "data",
1841 result: await (handlerOverride ? handlerOverride((ctx) => actualHandler(ctx)) : actualHandler())
1842 };
1843 } catch (e) {
1844 return {
1845 type: "error",
1846 result: e
1847 };
1848 }
1849 })();
1850 return Promise.race([handlerPromise, abortPromise]);
1851 };
1852 try {
1853 let handler = isAction ? match.route.action : match.route.loader;
1854 if (lazyHandlerPromise || lazyRoutePromise) if (handler) {
1855 let handlerError;
1856 let [value] = await Promise.all([
1857 runHandler(handler).catch((e) => {
1858 handlerError = e;
1859 }),
1860 lazyHandlerPromise,
1861 lazyRoutePromise
1862 ]);
1863 if (handlerError !== void 0) throw handlerError;
1864 result = value;
1865 } else {
1866 await lazyHandlerPromise;
1867 let handler = isAction ? match.route.action : match.route.loader;
1868 if (handler) [result] = await Promise.all([runHandler(handler), lazyRoutePromise]);
1869 else if (type === "action") {
1870 let url = new URL(request.url);
1871 let pathname = url.pathname + url.search;
1872 throw getInternalRouterError(405, {
1873 method: request.method,
1874 pathname,
1875 routeId: match.route.id
1876 });
1877 } else return {
1878 type: "data",
1879 result: void 0
1880 };
1881 }
1882 else if (!handler) {
1883 let url = new URL(request.url);
1884 throw getInternalRouterError(404, { pathname: url.pathname + url.search });
1885 } else result = await runHandler(handler);
1886 } catch (e) {
1887 return {
1888 type: "error",
1889 result: e
1890 };
1891 } finally {
1892 if (onReject) request.signal.removeEventListener("abort", onReject);
1893 }
1894 return result;
1895}
1896async function parseResponseBody(response) {
1897 let contentType = response.headers.get("Content-Type");
1898 if (contentType && /\bapplication\/json\b/.test(contentType)) return response.body == null ? null : response.json();
1899 return response.text();
1900}
1901async function convertDataStrategyResultToDataResult(dataStrategyResult) {
1902 let { result, type } = dataStrategyResult;
1903 if (isResponse(result)) {
1904 let data;
1905 try {
1906 data = await parseResponseBody(result);
1907 } catch (e) {
1908 return {
1909 type: "error",
1910 error: e
1911 };
1912 }
1913 if (type === "error") return {
1914 type: "error",
1915 error: new ErrorResponseImpl(result.status, result.statusText, data),
1916 statusCode: result.status,
1917 headers: result.headers
1918 };
1919 return {
1920 type: "data",
1921 data,
1922 statusCode: result.status,
1923 headers: result.headers
1924 };
1925 }
1926 if (type === "error") {
1927 if (isDataWithResponseInit(result)) {
1928 if (result.data instanceof Error) return {
1929 type: "error",
1930 error: result.data,
1931 statusCode: result.init?.status,
1932 headers: result.init?.headers ? new Headers(result.init.headers) : void 0
1933 };
1934 return {
1935 type: "error",
1936 error: dataWithResponseInitToErrorResponse(result),
1937 statusCode: isRouteErrorResponse(result) ? result.status : void 0,
1938 headers: result.init?.headers ? new Headers(result.init.headers) : void 0
1939 };
1940 }
1941 return {
1942 type: "error",
1943 error: result,
1944 statusCode: isRouteErrorResponse(result) ? result.status : void 0
1945 };
1946 }
1947 if (isDataWithResponseInit(result)) return {
1948 type: "data",
1949 data: result.data,
1950 statusCode: result.init?.status,
1951 headers: result.init?.headers ? new Headers(result.init.headers) : void 0
1952 };
1953 return {
1954 type: "data",
1955 data: result
1956 };
1957}
1958function normalizeRelativeRoutingRedirectResponse(response, request, routeId, matches, basename) {
1959 let location = response.headers.get("Location");
1960 invariant$1(location, "Redirects returned/thrown from loaders/actions must have a Location header");
1961 if (!isAbsoluteUrl(location)) {
1962 let trimmedMatches = matches.slice(0, matches.findIndex((m) => m.route.id === routeId) + 1);
1963 location = normalizeTo(new URL(request.url), trimmedMatches, basename, location);
1964 response.headers.set("Location", location);
1965 }
1966 return response;
1967}
1968function processRouteLoaderData(matches, results, pendingActionResult, isStaticHandler = false, skipLoaderErrorBubbling = false) {
1969 let loaderData = {};
1970 let errors = null;
1971 let statusCode;
1972 let foundError = false;
1973 let loaderHeaders = {};
1974 let pendingError = pendingActionResult && isErrorResult(pendingActionResult[1]) ? pendingActionResult[1].error : void 0;
1975 matches.forEach((match) => {
1976 if (!(match.route.id in results)) return;
1977 let id = match.route.id;
1978 let result = results[id];
1979 invariant$1(!isRedirectResult(result), "Cannot handle redirect results in processLoaderData");
1980 if (isErrorResult(result)) {
1981 let error = result.error;
1982 if (pendingError !== void 0) {
1983 error = pendingError;
1984 pendingError = void 0;
1985 }
1986 errors = errors || {};
1987 if (skipLoaderErrorBubbling) errors[id] = error;
1988 else {
1989 let boundaryMatch = findNearestBoundary(matches, id);
1990 if (errors[boundaryMatch.route.id] == null) errors[boundaryMatch.route.id] = error;
1991 }
1992 if (!isStaticHandler) loaderData[id] = ResetLoaderDataSymbol;
1993 if (!foundError) {
1994 foundError = true;
1995 statusCode = isRouteErrorResponse(result.error) ? result.error.status : 500;
1996 }
1997 if (result.headers) loaderHeaders[id] = result.headers;
1998 } else {
1999 loaderData[id] = result.data;
2000 if (result.statusCode && result.statusCode !== 200 && !foundError) statusCode = result.statusCode;
2001 if (result.headers) loaderHeaders[id] = result.headers;
2002 }
2003 });
2004 if (pendingError !== void 0 && pendingActionResult) {
2005 errors = { [pendingActionResult[0]]: pendingError };
2006 if (pendingActionResult[2]) loaderData[pendingActionResult[2]] = void 0;
2007 }
2008 return {
2009 loaderData,
2010 errors,
2011 statusCode: statusCode || 200,
2012 loaderHeaders
2013 };
2014}
2015function findNearestBoundary(matches, routeId) {
2016 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];
2017}
2018function getShortCircuitMatches(routes) {
2019 let route = routes.length === 1 ? routes[0] : routes.find((r) => r.index || !r.path || r.path === "/") || { id: `__shim-error-route__` };
2020 return {
2021 matches: [{
2022 params: {},
2023 pathname: "",
2024 pathnameBase: "",
2025 route
2026 }],
2027 route
2028 };
2029}
2030function getInternalRouterError(status, { pathname, routeId, method, type, message } = {}) {
2031 let statusText = "Unknown Server Error";
2032 let errorMessage = "Unknown @remix-run/router error";
2033 if (status === 400) {
2034 statusText = "Bad Request";
2035 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.`;
2036 else if (type === "invalid-body") errorMessage = "Unable to encode submission body";
2037 } else if (status === 403) {
2038 statusText = "Forbidden";
2039 errorMessage = `Route "${routeId}" does not match URL "${pathname}"`;
2040 } else if (status === 404) {
2041 statusText = "Not Found";
2042 errorMessage = `No route matches URL "${pathname}"`;
2043 } else if (status === 405) {
2044 statusText = "Method Not Allowed";
2045 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.`;
2046 else if (method) errorMessage = `Invalid request method "${method.toUpperCase()}"`;
2047 }
2048 return new ErrorResponseImpl(status || 500, statusText, new Error(errorMessage), true);
2049}
2050function dataWithResponseInitToResponse(data) {
2051 return Response.json(data.data, data.init ?? void 0);
2052}
2053function dataWithResponseInitToErrorResponse(data) {
2054 return new ErrorResponseImpl(data.init?.status ?? 500, data.init?.statusText ?? "Internal Server Error", data.data);
2055}
2056function isDataStrategyResults(result) {
2057 return result != null && typeof result === "object" && Object.entries(result).every(([key, value]) => typeof key === "string" && isDataStrategyResult(value));
2058}
2059function isDataStrategyResult(result) {
2060 return result != null && typeof result === "object" && "type" in result && "result" in result && (result.type === "data" || result.type === "error");
2061}
2062function isRedirectDataStrategyResult(result) {
2063 return isResponse(result.result) && redirectStatusCodes.has(result.result.status);
2064}
2065function isErrorResult(result) {
2066 return result.type === "error";
2067}
2068function isRedirectResult(result) {
2069 return (result && result.type) === "redirect";
2070}
2071function isDataWithResponseInit(value) {
2072 return typeof value === "object" && value != null && "type" in value && "data" in value && "init" in value && value.type === "DataWithResponseInit";
2073}
2074function isResponse(value) {
2075 return value != null && typeof value.status === "number" && typeof value.statusText === "string" && typeof value.headers === "object" && typeof value.body !== "undefined";
2076}
2077function isRedirectStatusCode(statusCode) {
2078 return redirectStatusCodes.has(statusCode);
2079}
2080function isRedirectResponse(result) {
2081 return isResponse(result) && isRedirectStatusCode(result.status) && result.headers.has("Location");
2082}
2083function isValidMethod(method) {
2084 return validRequestMethods.has(method.toUpperCase());
2085}
2086function isMutationMethod(method) {
2087 return validMutationMethods.has(method.toUpperCase());
2088}
2089function hasNakedIndexQuery(search) {
2090 return new URLSearchParams(search).getAll("index").some((v) => v === "");
2091}
2092function getTargetMatch(matches, location) {
2093 let search = typeof location === "string" ? parsePath(location).search : location.search;
2094 if (matches[matches.length - 1].route.index && hasNakedIndexQuery(search || "")) return matches[matches.length - 1];
2095 let pathMatches = getPathContributingMatches(matches);
2096 return pathMatches[pathMatches.length - 1];
2097}
2098//#endregion
2099//#region lib/server-runtime/invariant.ts
2100function invariant(value, message) {
2101 if (value === false || value === null || typeof value === "undefined") {
2102 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");
2103 throw new Error(message);
2104 }
2105}
2106//#endregion
2107//#region lib/server-runtime/headers.ts
2108function getDocumentHeadersImpl(context, getRouteHeadersFn, _defaultHeaders) {
2109 let boundaryIdx = context.errors ? context.matches.findIndex((m) => context.errors[m.route.id]) : -1;
2110 let matches = boundaryIdx >= 0 ? context.matches.slice(0, boundaryIdx + 1) : context.matches;
2111 let errorHeaders;
2112 if (boundaryIdx >= 0) {
2113 let { actionHeaders, actionData, loaderHeaders, loaderData } = context;
2114 context.matches.slice(boundaryIdx).some((match) => {
2115 let id = match.route.id;
2116 if (actionHeaders[id] && (!actionData || !actionData.hasOwnProperty(id))) errorHeaders = actionHeaders[id];
2117 else if (loaderHeaders[id] && !loaderData.hasOwnProperty(id)) errorHeaders = loaderHeaders[id];
2118 return errorHeaders != null;
2119 });
2120 }
2121 const defaultHeaders = new Headers(_defaultHeaders);
2122 return matches.reduce((parentHeaders, match, idx) => {
2123 let { id } = match.route;
2124 let loaderHeaders = context.loaderHeaders[id] || new Headers();
2125 let actionHeaders = context.actionHeaders[id] || new Headers();
2126 let includeErrorHeaders = errorHeaders != null && idx === matches.length - 1;
2127 let includeErrorCookies = includeErrorHeaders && errorHeaders !== loaderHeaders && errorHeaders !== actionHeaders;
2128 let headersFn = getRouteHeadersFn(match);
2129 if (headersFn == null) {
2130 let headers = new Headers(parentHeaders);
2131 if (includeErrorCookies) prependCookies(errorHeaders, headers);
2132 prependCookies(actionHeaders, headers);
2133 prependCookies(loaderHeaders, headers);
2134 return headers;
2135 }
2136 let headers = new Headers(typeof headersFn === "function" ? headersFn({
2137 loaderHeaders,
2138 parentHeaders,
2139 actionHeaders,
2140 errorHeaders: includeErrorHeaders ? errorHeaders : void 0
2141 }) : headersFn);
2142 if (includeErrorCookies) prependCookies(errorHeaders, headers);
2143 prependCookies(actionHeaders, headers);
2144 prependCookies(loaderHeaders, headers);
2145 prependCookies(parentHeaders, headers);
2146 return headers;
2147 }, new Headers(defaultHeaders));
2148}
2149function prependCookies(parentHeaders, childHeaders) {
2150 let parentSetCookieString = parentHeaders.get("Set-Cookie");
2151 if (parentSetCookieString) {
2152 let cookies = splitSetCookieString(parentSetCookieString);
2153 let childCookies = new Set(childHeaders.getSetCookie());
2154 cookies.forEach((cookie) => {
2155 if (!childCookies.has(cookie)) childHeaders.append("Set-Cookie", cookie);
2156 });
2157 }
2158}
2159//#endregion
2160//#region lib/server-runtime/warnings.ts
2161const alreadyWarned = {};
2162function warnOnce(condition, message) {
2163 if (!condition && !alreadyWarned[message]) {
2164 alreadyWarned[message] = true;
2165 console.warn(message);
2166 }
2167}
2168//#endregion
2169//#region lib/errors.ts
2170const ERROR_DIGEST_BASE = "REACT_ROUTER_ERROR";
2171const ERROR_DIGEST_REDIRECT = "REDIRECT";
2172const ERROR_DIGEST_ROUTE_ERROR_RESPONSE = "ROUTE_ERROR_RESPONSE";
2173function createRedirectErrorDigest(response) {
2174 return `${ERROR_DIGEST_BASE}:${ERROR_DIGEST_REDIRECT}:${JSON.stringify({
2175 status: response.status,
2176 statusText: response.statusText,
2177 location: response.headers.get("Location"),
2178 reloadDocument: response.headers.get("X-Remix-Reload-Document") === "true",
2179 replace: response.headers.get("X-Remix-Replace") === "true"
2180 })}`;
2181}
2182function createRouteErrorResponseDigest(response) {
2183 let status = 500;
2184 let statusText = "";
2185 let data;
2186 if (isDataWithResponseInit(response)) {
2187 status = response.init?.status ?? status;
2188 statusText = response.init?.statusText ?? statusText;
2189 data = response.data;
2190 } else {
2191 status = response.status;
2192 statusText = response.statusText;
2193 data = void 0;
2194 }
2195 return `${ERROR_DIGEST_BASE}:${ERROR_DIGEST_ROUTE_ERROR_RESPONSE}:${JSON.stringify({
2196 status,
2197 statusText,
2198 data
2199 })}`;
2200}
2201function getPathsWithAncestors(paths) {
2202 let result = /* @__PURE__ */ new Set();
2203 paths.forEach((path) => {
2204 if (!path.startsWith("/")) path = `/${path}`;
2205 for (let i = 1; i < path.length; i++) if (path[i] === "/") result.add(path.slice(0, i));
2206 result.add(path);
2207 });
2208 return Array.from(result);
2209}
2210//#endregion
2211//#region lib/actions.ts
2212function throwIfPotentialCSRFAttack(request, allowedActionOrigins) {
2213 let originHeader = request.headers.get("origin");
2214 let originDomain = null;
2215 let originUrl = null;
2216 try {
2217 if (typeof originHeader === "string" && originHeader !== "null") {
2218 originUrl = new URL(originHeader);
2219 originDomain = originUrl.host;
2220 } else originDomain = originHeader;
2221 } catch {
2222 throw new Error(`\`origin\` header is not a valid URL. Aborting the action.`);
2223 }
2224 let requestUrl = new URL(request.url);
2225 let originMatchesRequest = originUrl ? originUrl.origin === requestUrl.origin : originDomain === requestUrl.host;
2226 if (originDomain && !originMatchesRequest) {
2227 if (!isAllowedOrigin(originDomain, allowedActionOrigins)) throw new Error("The `request.url` origin 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 {
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 {
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 };