INDIE UNPKG

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