UNPKG

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