UNPKG

132 kBJavaScriptView Raw
1/**
2 * react-router v8.4.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(/\/([\w-]+)\?(?=\/|$|\()/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, 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, scopedContext, isStaticHandler) {
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 };
1835 let runClientMiddleware = isStaticHandler ? () => {
1836 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`");
1837 } : (cb) => {
1838 let typedDataStrategyArgs = dataStrategyArgs;
1839 return runClientMiddlewarePipeline(typedDataStrategyArgs, () => {
1840 return cb({
1841 ...typedDataStrategyArgs,
1842 fetcherKey,
1843 runClientMiddleware: () => {
1844 throw new Error("Cannot call `runClientMiddleware()` from within an `runClientMiddleware` handler");
1845 }
1846 });
1847 });
1848 };
1849 let results = await dataStrategyImpl({
1850 ...dataStrategyArgs,
1851 fetcherKey,
1852 runClientMiddleware
1853 });
1854 try {
1855 await Promise.all(matches.flatMap((m) => [m._lazyPromises?.handler, m._lazyPromises?.route]));
1856 } catch {}
1857 return results;
1858}
1859async function callLoaderOrAction({ request, path, pattern, match, lazyHandlerPromise, lazyRoutePromise, handlerOverride, scopedContext }) {
1860 let result;
1861 let onReject;
1862 let isAction = isMutationMethod(request.method);
1863 let type = isAction ? "action" : "loader";
1864 let runHandler = (handler) => {
1865 let reject;
1866 let abortPromise = new Promise((_, r) => reject = r);
1867 onReject = () => reject();
1868 request.signal.addEventListener("abort", onReject);
1869 let actualHandler = (ctx) => {
1870 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}]`));
1871 return handler({
1872 request,
1873 url: createDataFunctionUrl(request, path),
1874 pattern,
1875 params: match.params,
1876 context: scopedContext
1877 }, ...ctx !== void 0 ? [ctx] : []);
1878 };
1879 let handlerPromise = (async () => {
1880 try {
1881 return {
1882 type: "data",
1883 result: await (handlerOverride ? handlerOverride((ctx) => actualHandler(ctx)) : actualHandler())
1884 };
1885 } catch (e) {
1886 return {
1887 type: "error",
1888 result: e
1889 };
1890 }
1891 })();
1892 return Promise.race([handlerPromise, abortPromise]);
1893 };
1894 try {
1895 let handler = isAction ? match.route.action : match.route.loader;
1896 if (lazyHandlerPromise || lazyRoutePromise) if (handler) {
1897 let handlerError;
1898 let [value] = await Promise.all([
1899 runHandler(handler).catch((e) => {
1900 handlerError = e;
1901 }),
1902 lazyHandlerPromise,
1903 lazyRoutePromise
1904 ]);
1905 if (handlerError !== void 0) throw handlerError;
1906 result = value;
1907 } else {
1908 await lazyHandlerPromise;
1909 let handler = isAction ? match.route.action : match.route.loader;
1910 if (handler) [result] = await Promise.all([runHandler(handler), lazyRoutePromise]);
1911 else if (type === "action") {
1912 let url = new URL(request.url);
1913 let pathname = url.pathname + url.search;
1914 throw getInternalRouterError(405, {
1915 method: request.method,
1916 pathname,
1917 routeId: match.route.id
1918 });
1919 } else return {
1920 type: "data",
1921 result: void 0
1922 };
1923 }
1924 else if (!handler) {
1925 let url = new URL(request.url);
1926 throw getInternalRouterError(404, { pathname: url.pathname + url.search });
1927 } else result = await runHandler(handler);
1928 } catch (e) {
1929 return {
1930 type: "error",
1931 result: e
1932 };
1933 } finally {
1934 if (onReject) request.signal.removeEventListener("abort", onReject);
1935 }
1936 return result;
1937}
1938async function parseResponseBody(response) {
1939 let contentType = response.headers.get("Content-Type");
1940 if (contentType && /\bapplication\/json\b/.test(contentType)) return response.body == null ? null : response.json();
1941 return response.text();
1942}
1943async function convertDataStrategyResultToDataResult(dataStrategyResult) {
1944 let { result, type } = dataStrategyResult;
1945 if (isResponse(result)) {
1946 let data;
1947 try {
1948 data = await parseResponseBody(result);
1949 } catch (e) {
1950 return {
1951 type: "error",
1952 error: e
1953 };
1954 }
1955 if (type === "error") return {
1956 type: "error",
1957 error: new ErrorResponseImpl(result.status, result.statusText, data),
1958 statusCode: result.status,
1959 headers: result.headers
1960 };
1961 return {
1962 type: "data",
1963 data,
1964 statusCode: result.status,
1965 headers: result.headers
1966 };
1967 }
1968 if (type === "error") {
1969 if (isDataWithResponseInit(result)) {
1970 if (result.data instanceof Error) return {
1971 type: "error",
1972 error: result.data,
1973 statusCode: result.init?.status,
1974 headers: result.init?.headers ? new Headers(result.init.headers) : void 0
1975 };
1976 return {
1977 type: "error",
1978 error: dataWithResponseInitToErrorResponse(result),
1979 statusCode: isRouteErrorResponse(result) ? result.status : void 0,
1980 headers: result.init?.headers ? new Headers(result.init.headers) : void 0
1981 };
1982 }
1983 return {
1984 type: "error",
1985 error: result,
1986 statusCode: isRouteErrorResponse(result) ? result.status : void 0
1987 };
1988 }
1989 if (isDataWithResponseInit(result)) return {
1990 type: "data",
1991 data: result.data,
1992 statusCode: result.init?.status,
1993 headers: result.init?.headers ? new Headers(result.init.headers) : void 0
1994 };
1995 return {
1996 type: "data",
1997 data: result
1998 };
1999}
2000function normalizeRelativeRoutingRedirectResponse(response, request, routeId, matches, basename) {
2001 let location = response.headers.get("Location");
2002 invariant$1(location, "Redirects returned/thrown from loaders/actions must have a Location header");
2003 if (!isAbsoluteUrl(location)) {
2004 let trimmedMatches = matches.slice(0, matches.findIndex((m) => m.route.id === routeId) + 1);
2005 location = normalizeTo(new URL(request.url), trimmedMatches, basename, location);
2006 response.headers.set("Location", location);
2007 }
2008 return response;
2009}
2010function processRouteLoaderData(matches, results, pendingActionResult, isStaticHandler = false, skipLoaderErrorBubbling = false) {
2011 let loaderData = {};
2012 let errors = null;
2013 let statusCode;
2014 let foundError = false;
2015 let loaderHeaders = {};
2016 let pendingError = pendingActionResult && isErrorResult(pendingActionResult[1]) ? pendingActionResult[1].error : void 0;
2017 matches.forEach((match) => {
2018 if (!(match.route.id in results)) return;
2019 let id = match.route.id;
2020 let result = results[id];
2021 invariant$1(!isRedirectResult(result), "Cannot handle redirect results in processLoaderData");
2022 if (isErrorResult(result)) {
2023 let error = result.error;
2024 if (pendingError !== void 0) {
2025 error = pendingError;
2026 pendingError = void 0;
2027 }
2028 errors = errors || {};
2029 if (skipLoaderErrorBubbling) errors[id] = error;
2030 else {
2031 let boundaryMatch = findNearestBoundary(matches, id);
2032 if (errors[boundaryMatch.route.id] == null) errors[boundaryMatch.route.id] = error;
2033 }
2034 if (!isStaticHandler) loaderData[id] = ResetLoaderDataSymbol;
2035 if (!foundError) {
2036 foundError = true;
2037 statusCode = isRouteErrorResponse(result.error) ? result.error.status : 500;
2038 }
2039 if (result.headers) loaderHeaders[id] = result.headers;
2040 } else {
2041 loaderData[id] = result.data;
2042 if (result.statusCode && result.statusCode !== 200 && !foundError) statusCode = result.statusCode;
2043 if (result.headers) loaderHeaders[id] = result.headers;
2044 }
2045 });
2046 if (pendingError !== void 0 && pendingActionResult) {
2047 errors = { [pendingActionResult[0]]: pendingError };
2048 if (pendingActionResult[2]) loaderData[pendingActionResult[2]] = void 0;
2049 }
2050 return {
2051 loaderData,
2052 errors,
2053 statusCode: statusCode || 200,
2054 loaderHeaders
2055 };
2056}
2057function findNearestBoundary(matches, routeId) {
2058 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];
2059}
2060function getShortCircuitMatches(routes) {
2061 let route = routes.length === 1 ? routes[0] : routes.find((r) => r.index || !r.path || r.path === "/") || { id: `__shim-error-route__` };
2062 return {
2063 matches: [{
2064 params: {},
2065 pathname: "",
2066 pathnameBase: "",
2067 route
2068 }],
2069 route
2070 };
2071}
2072function getInternalRouterError(status, { pathname, routeId, method, type, message } = {}) {
2073 let statusText = "Unknown Server Error";
2074 let errorMessage = "Unknown @remix-run/router error";
2075 if (status === 400) {
2076 statusText = "Bad Request";
2077 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.`;
2078 else if (type === "invalid-body") errorMessage = "Unable to encode submission body";
2079 } else if (status === 403) {
2080 statusText = "Forbidden";
2081 errorMessage = `Route "${routeId}" does not match URL "${pathname}"`;
2082 } else if (status === 404) {
2083 statusText = "Not Found";
2084 errorMessage = `No route matches URL "${pathname}"`;
2085 } else if (status === 405) {
2086 statusText = "Method Not Allowed";
2087 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.`;
2088 else if (method) errorMessage = `Invalid request method "${method.toUpperCase()}"`;
2089 }
2090 return new ErrorResponseImpl(status || 500, statusText, new Error(errorMessage), true);
2091}
2092function dataWithResponseInitToResponse(data) {
2093 return Response.json(data.data, data.init ?? void 0);
2094}
2095function dataWithResponseInitToErrorResponse(data) {
2096 return new ErrorResponseImpl(data.init?.status ?? 500, data.init?.statusText ?? "Internal Server Error", data.data);
2097}
2098function isDataStrategyResults(result) {
2099 return result != null && typeof result === "object" && Object.entries(result).every(([key, value]) => typeof key === "string" && isDataStrategyResult(value));
2100}
2101function isDataStrategyResult(result) {
2102 return result != null && typeof result === "object" && "type" in result && "result" in result && (result.type === "data" || result.type === "error");
2103}
2104function isRedirectDataStrategyResult(result) {
2105 return isResponse(result.result) && redirectStatusCodes.has(result.result.status);
2106}
2107function isErrorResult(result) {
2108 return result.type === "error";
2109}
2110function isRedirectResult(result) {
2111 return (result && result.type) === "redirect";
2112}
2113function isDataWithResponseInit(value) {
2114 return typeof value === "object" && value != null && "type" in value && "data" in value && "init" in value && value.type === "DataWithResponseInit";
2115}
2116function isResponse(value) {
2117 return value != null && typeof value.status === "number" && typeof value.statusText === "string" && typeof value.headers === "object" && typeof value.body !== "undefined";
2118}
2119function isRedirectStatusCode(statusCode) {
2120 return redirectStatusCodes.has(statusCode);
2121}
2122function isRedirectResponse(result) {
2123 return isResponse(result) && isRedirectStatusCode(result.status) && result.headers.has("Location");
2124}
2125function isValidMethod(method) {
2126 return validRequestMethods.has(method.toUpperCase());
2127}
2128function isMutationMethod(method) {
2129 return validMutationMethods.has(method.toUpperCase());
2130}
2131function hasNakedIndexQuery(search) {
2132 return new URLSearchParams(search).getAll("index").some((v) => v === "");
2133}
2134function getTargetMatch(matches, location) {
2135 let search = typeof location === "string" ? parsePath(location).search : location.search;
2136 if (matches[matches.length - 1].route.index && hasNakedIndexQuery(search || "")) return matches[matches.length - 1];
2137 let pathMatches = getPathContributingMatches(matches);
2138 return pathMatches[pathMatches.length - 1];
2139}
2140//#endregion
2141//#region lib/server-runtime/invariant.ts
2142function invariant(value, message) {
2143 if (value === false || value === null || typeof value === "undefined") {
2144 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");
2145 throw new Error(message);
2146 }
2147}
2148//#endregion
2149//#region lib/server-runtime/headers.ts
2150function getDocumentHeadersImpl(context, getRouteHeadersFn, _defaultHeaders) {
2151 let boundaryIdx = context.errors ? context.matches.findIndex((m) => context.errors[m.route.id]) : -1;
2152 let matches = boundaryIdx >= 0 ? context.matches.slice(0, boundaryIdx + 1) : context.matches;
2153 let errorHeaders;
2154 if (boundaryIdx >= 0) {
2155 let { actionHeaders, actionData, loaderHeaders, loaderData } = context;
2156 context.matches.slice(boundaryIdx).some((match) => {
2157 let id = match.route.id;
2158 if (actionHeaders[id] && (!actionData || !actionData.hasOwnProperty(id))) errorHeaders = actionHeaders[id];
2159 else if (loaderHeaders[id] && !loaderData.hasOwnProperty(id)) errorHeaders = loaderHeaders[id];
2160 return errorHeaders != null;
2161 });
2162 }
2163 const defaultHeaders = new Headers(_defaultHeaders);
2164 return matches.reduce((parentHeaders, match, idx) => {
2165 let { id } = match.route;
2166 let loaderHeaders = context.loaderHeaders[id] || new Headers();
2167 let actionHeaders = context.actionHeaders[id] || new Headers();
2168 let includeErrorHeaders = errorHeaders != null && idx === matches.length - 1;
2169 let includeErrorCookies = includeErrorHeaders && errorHeaders !== loaderHeaders && errorHeaders !== actionHeaders;
2170 let headersFn = getRouteHeadersFn(match);
2171 if (headersFn == null) {
2172 let headers = new Headers(parentHeaders);
2173 if (includeErrorCookies) prependCookies(errorHeaders, headers);
2174 prependCookies(actionHeaders, headers);
2175 prependCookies(loaderHeaders, headers);
2176 return headers;
2177 }
2178 let headers = new Headers(typeof headersFn === "function" ? headersFn({
2179 loaderHeaders,
2180 parentHeaders,
2181 actionHeaders,
2182 errorHeaders: includeErrorHeaders ? errorHeaders : void 0
2183 }) : headersFn);
2184 if (includeErrorCookies) prependCookies(errorHeaders, headers);
2185 prependCookies(actionHeaders, headers);
2186 prependCookies(loaderHeaders, headers);
2187 prependCookies(parentHeaders, headers);
2188 return headers;
2189 }, new Headers(defaultHeaders));
2190}
2191function prependCookies(parentHeaders, childHeaders) {
2192 let parentSetCookieString = parentHeaders.get("Set-Cookie");
2193 if (parentSetCookieString) {
2194 let cookies = splitSetCookieString(parentSetCookieString);
2195 let childCookies = new Set(childHeaders.getSetCookie());
2196 cookies.forEach((cookie) => {
2197 if (!childCookies.has(cookie)) childHeaders.append("Set-Cookie", cookie);
2198 });
2199 }
2200}
2201//#endregion
2202//#region lib/server-runtime/warnings.ts
2203const alreadyWarned = {};
2204function warnOnce(condition, message) {
2205 if (!condition && !alreadyWarned[message]) {
2206 alreadyWarned[message] = true;
2207 console.warn(message);
2208 }
2209}
2210//#endregion
2211//#region lib/errors.ts
2212const ERROR_DIGEST_BASE = "REACT_ROUTER_ERROR";
2213const ERROR_DIGEST_REDIRECT = "REDIRECT";
2214const ERROR_DIGEST_ROUTE_ERROR_RESPONSE = "ROUTE_ERROR_RESPONSE";
2215function createRedirectErrorDigest(response) {
2216 return `${ERROR_DIGEST_BASE}:${ERROR_DIGEST_REDIRECT}:${JSON.stringify({
2217 status: response.status,
2218 statusText: response.statusText,
2219 location: response.headers.get("Location"),
2220 reloadDocument: response.headers.get("X-Remix-Reload-Document") === "true",
2221 replace: response.headers.get("X-Remix-Replace") === "true"
2222 })}`;
2223}
2224function createRouteErrorResponseDigest(response) {
2225 let status = 500;
2226 let statusText = "";
2227 let data;
2228 if (isDataWithResponseInit(response)) {
2229 status = response.init?.status ?? status;
2230 statusText = response.init?.statusText ?? statusText;
2231 data = response.data;
2232 } else {
2233 status = response.status;
2234 statusText = response.statusText;
2235 data = void 0;
2236 }
2237 return `${ERROR_DIGEST_BASE}:${ERROR_DIGEST_ROUTE_ERROR_RESPONSE}:${JSON.stringify({
2238 status,
2239 statusText,
2240 data
2241 })}`;
2242}
2243function getPathsWithAncestors(paths) {
2244 let result = /* @__PURE__ */ new Set();
2245 paths.forEach((path) => {
2246 if (!path.startsWith("/")) path = `/${path}`;
2247 for (let i = 1; i < path.length; i++) if (path[i] === "/") result.add(path.slice(0, i));
2248 result.add(path);
2249 });
2250 return Array.from(result);
2251}
2252//#endregion
2253//#region lib/actions.ts
2254function throwIfPotentialCSRFAttack(request, allowedActionOrigins) {
2255 let originHeader = request.headers.get("origin");
2256 let originDomain = null;
2257 let originUrl = null;
2258 try {
2259 if (typeof originHeader === "string" && originHeader !== "null") {
2260 originUrl = new URL(originHeader);
2261 originDomain = originUrl.host;
2262 } else originDomain = originHeader;
2263 } catch {
2264 throw new Error(`\`origin\` header is not a valid URL. Aborting the action.`);
2265 }
2266 let requestUrl = new URL(request.url);
2267 let originMatchesRequest = originUrl ? originUrl.origin === requestUrl.origin : originDomain === requestUrl.host;
2268 if (originDomain && !originMatchesRequest) {
2269 if (!isAllowedOrigin(originDomain, allowedActionOrigins)) throw new Error("The `request.url` origin does not match `origin` header from a forwarded action request. Aborting the action.");
2270 }
2271}
2272function matchWildcardDomain(domain, pattern) {
2273 const domainParts = domain.split(".");
2274 const patternParts = pattern.split(".");
2275 if (patternParts.length < 1) return false;
2276 if (domainParts.length < patternParts.length) return false;
2277 while (patternParts.length) {
2278 const patternPart = patternParts.pop();
2279 const domainPart = domainParts.pop();
2280 switch (patternPart) {
2281 case "": return false;
2282 case "*": if (domainPart) continue;
2283 else return false;
2284 case "**":
2285 if (patternParts.length > 0) return false;
2286 return domainPart !== void 0;
2287 case void 0:
2288 default: if (domainPart !== patternPart) return false;
2289 }
2290 }
2291 return domainParts.length === 0;
2292}
2293function isAllowedOrigin(originDomain, allowedActionOrigins = []) {
2294 return allowedActionOrigins.some((allowedOrigin) => allowedOrigin && (allowedOrigin === originDomain || matchWildcardDomain(originDomain, allowedOrigin)));
2295}
2296//#endregion
2297//#region lib/server-runtime/urls.ts
2298function getNormalizedPath(request) {
2299 let url = new URL(request.url);
2300 let pathname = url.pathname;
2301 if (pathname.endsWith("/_.data")) pathname = pathname.replace(/_\.data$/, "");
2302 else pathname = pathname.replace(/\.data$/, "");
2303 let searchParams = new URLSearchParams(url.search);
2304 searchParams.delete("_routes");
2305 let search = searchParams.toString();
2306 if (search) search = `?${search}`;
2307 return {
2308 pathname,
2309 search,
2310 hash: ""
2311 };
2312}
2313//#endregion
2314//#region lib/rsc/server.rsc.ts
2315const Outlet$2 = Outlet$1;
2316const WithComponentProps = UNSAFE_WithComponentProps;
2317const WithErrorBoundaryProps = UNSAFE_WithErrorBoundaryProps;
2318const WithHydrateFallbackProps = UNSAFE_WithHydrateFallbackProps;
2319const globalVar = typeof globalThis !== "undefined" ? globalThis : global;
2320const ServerStorage = globalVar.___reactRouterServerStorage___ ??= new AsyncLocalStorage();
2321function getRequest() {
2322 const ctx = ServerStorage.getStore();
2323 if (!ctx) throw new Error("getRequest must be called from within a React Server render context");
2324 return ctx.request;
2325}
2326const redirect = (...args) => {
2327 const response = redirect$1(...args);
2328 const ctx = ServerStorage.getStore();
2329 if (ctx && ctx.runningAction) ctx.redirect = response;
2330 return response;
2331};
2332const redirectDocument = (...args) => {
2333 const response = redirectDocument$1(...args);
2334 const ctx = ServerStorage.getStore();
2335 if (ctx && ctx.runningAction) ctx.redirect = response;
2336 return response;
2337};
2338const replace = (...args) => {
2339 const response = replace$1(...args);
2340 const ctx = ServerStorage.getStore();
2341 if (ctx && ctx.runningAction) ctx.redirect = response;
2342 return response;
2343};
2344const cachedResolvePromise = React.cache(async (resolve) => {
2345 return Promise.allSettled([resolve]).then((r) => r[0]);
2346});
2347const Await = (async ({ children, resolve, errorElement }) => {
2348 let resolved = await cachedResolvePromise(resolve);
2349 if (resolved.status === "rejected" && !errorElement) throw resolved.reason;
2350 if (resolved.status === "rejected") return React.createElement(UNSAFE_AwaitContextProvider, {
2351 children: React.createElement(React.Fragment, null, errorElement),
2352 value: {
2353 _tracked: true,
2354 _error: resolved.reason
2355 }
2356 });
2357 const toRender = typeof children === "function" ? children(resolved.value) : children;
2358 return React.createElement(UNSAFE_AwaitContextProvider, {
2359 children: toRender,
2360 value: {
2361 _tracked: true,
2362 _data: resolved.value
2363 }
2364 });
2365});
2366/**
2367* Matches the given routes to a [`Request`](https://developer.mozilla.org/en-US/docs/Web/API/Request)
2368* and returns an [RSC](https://react.dev/reference/rsc/server-components)
2369* [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response)
2370* encoding an {@link unstable_RSCPayload} for consumption by an [RSC](https://react.dev/reference/rsc/server-components)
2371* enabled client router.
2372*
2373* Treat every React Server Function as a public endpoint. Server Functions are
2374* not inherently associated with a route. Any route middleware that runs is
2375* selected from the URL used to call a Server Function, but the client controls
2376* both the Server Function identifier and the URL. Perform all access control
2377* checks within each Server Function, or use a route action for
2378* middleware-driven access control.
2379*
2380* @example
2381* import {
2382* createTemporaryReferenceSet,
2383* decodeAction,
2384* decodeReply,
2385* loadServerAction,
2386* renderToReadableStream,
2387* } from "@vitejs/plugin-rsc/rsc";
2388* import { unstable_matchRSCServerRequest as matchRSCServerRequest } from "react-router";
2389*
2390* matchRSCServerRequest({
2391* createTemporaryReferenceSet,
2392* decodeAction,
2393* decodeFormState,
2394* decodeReply,
2395* loadServerAction,
2396* request,
2397* routes: routes(),
2398* generateResponse(match) {
2399* return new Response(
2400* renderToReadableStream(match.payload),
2401* {
2402* status: match.statusCode,
2403* headers: match.headers,
2404* }
2405* );
2406* },
2407* });
2408*
2409* @name unstable_matchRSCServerRequest
2410* @public
2411* @category RSC
2412* @mode data
2413* @param opts Options
2414* @param opts.allowedActionOrigins Origin patterns that are allowed to execute actions.
2415* @param opts.basename The basename to use when matching the request.
2416* @param opts.createTemporaryReferenceSet A function that returns a temporary
2417* reference set for the request, used to track temporary references in the [RSC](https://react.dev/reference/rsc/server-components)
2418* stream.
2419* @param opts.decodeAction Your `react-server-dom-xyz/server`'s `decodeAction`
2420* function, responsible for loading a server action.
2421* @param opts.decodeFormState A function responsible for decoding form state for
2422* progressively enhanceable forms with React's [`useActionState`](https://react.dev/reference/react/useActionState)
2423* using your `react-server-dom-xyz/server`'s `decodeFormState`.
2424* @param opts.decodeReply Your `react-server-dom-xyz/server`'s `decodeReply`
2425* function, used to decode the server function's arguments and bind them to the
2426* implementation for invocation by the router.
2427* @param opts.generateResponse A function responsible for using your
2428* `renderToReadableStream` to generate a [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response)
2429* encoding the {@link unstable_RSCPayload}.
2430* @param opts.loadServerAction Your `react-server-dom-xyz/server`'s
2431* `loadServerAction` function, used to load a server action by ID.
2432* @param opts.clientVersion A version derived from the client build output used
2433* to detect stale clients during lazy route discovery.
2434* @param opts.onError An optional error handler that will be called with any
2435* errors that occur during the request processing.
2436* @param opts.request The [`Request`](https://developer.mozilla.org/en-US/docs/Web/API/Request)
2437* to match against.
2438* @param opts.requestContext An instance of {@link RouterContextProvider}
2439* that should be created per request, to be passed to [`action`](../../start/data/route-object#action)s,
2440* [`loader`](../../start/data/route-object#loader)s and [middleware](../../how-to/middleware).
2441* @param opts.routeDiscovery The route discovery configuration, used to determine how the router should discover new routes during navigations.
2442* @param opts.routes Your {@link unstable_RSCRouteConfigEntry | route definitions}.
2443* @returns A [`Response`](https://developer.mozilla.org/en-US/docs/Web/API/Response)
2444* that contains the [RSC](https://react.dev/reference/rsc/server-components)
2445* data for hydration.
2446*/
2447async function matchRSCServerRequest({ allowedActionOrigins, createTemporaryReferenceSet, basename, decodeReply, requestContext, routeDiscovery, loadServerAction, decodeAction, decodeFormState, clientVersion, onError, request, routes, generateResponse }) {
2448 let url = new URL(request.url);
2449 basename = basename || "/";
2450 let normalizedPath = url.pathname;
2451 if (url.pathname.endsWith("/_.rsc")) normalizedPath = url.pathname.replace(/_\.rsc$/, "");
2452 else if (url.pathname.endsWith(".rsc")) normalizedPath = url.pathname.replace(/\.rsc$/, "");
2453 if (stripBasename(normalizedPath, basename) !== "/" && normalizedPath.endsWith("/")) normalizedPath = normalizedPath.slice(0, -1);
2454 url.pathname = normalizedPath;
2455 basename = basename.length > normalizedPath.length ? normalizedPath : basename;
2456 let routerRequest = new Request(url.toString(), {
2457 method: request.method,
2458 headers: request.headers,
2459 body: request.body,
2460 signal: request.signal,
2461 duplex: request.body ? "half" : void 0
2462 });
2463 const temporaryReferences = createTemporaryReferenceSet();
2464 const requestUrl = new URL(request.url);
2465 if (isManifestRequest(requestUrl)) return await generateManifestResponse(routes, basename, request, generateResponse, temporaryReferences, routeDiscovery, clientVersion);
2466 let isDataRequest = isReactServerRequest(requestUrl);
2467 let staticHandler = createStaticHandler(routes, { basename });
2468 let matches = staticHandler.match(url.pathname);
2469 if (matches) await Promise.all(matches.map((m) => explodeLazyRoute(m.route)));
2470 const leafMatch = matches?.[matches.length - 1];
2471 if (!isDataRequest && leafMatch && !leafMatch.route.Component && !leafMatch.route.ErrorBoundary) return generateResourceResponse(routerRequest, staticHandler, leafMatch.route.id, requestContext, onError);
2472 let response = await generateRenderResponse(routerRequest, staticHandler, basename, isDataRequest, decodeReply, requestContext, loadServerAction, decodeAction, decodeFormState, onError, generateResponse, temporaryReferences, allowedActionOrigins, routeDiscovery, clientVersion);
2473 response.headers.set("X-Remix-Response", "yes");
2474 return response;
2475}
2476async function generateManifestResponse(routes, basename, request, generateResponse, temporaryReferences, routeDiscovery, clientVersion) {
2477 let url = new URL(request.url);
2478 if (url.toString().length > 7680) return new Response(null, {
2479 statusText: "Bad Request",
2480 status: 400
2481 });
2482 if (clientVersion !== void 0 && clientVersion !== url.searchParams.get("version")) return new Response(null, {
2483 status: 204,
2484 headers: { "X-Remix-Reload-Document": "true" }
2485 });
2486 if (routeDiscovery?.mode === "initial") {
2487 let payload = {
2488 type: "manifest",
2489 patches: getAllRoutePatches(routes, basename)
2490 };
2491 return generateResponse({
2492 statusCode: 200,
2493 headers: new Headers({
2494 "Content-Type": "text/x-component",
2495 Vary: "Content-Type"
2496 }),
2497 payload
2498 }, {
2499 temporaryReferences,
2500 onError: defaultOnError
2501 });
2502 }
2503 let pathParam = url.searchParams.get("paths");
2504 let pathnames = pathParam ? pathParam.split(",").filter(Boolean) : [url.pathname.replace(/\.manifest$/, "")];
2505 let staticHandler = routes.length > 0 ? createStaticHandler(routes, { basename }) : void 0;
2506 let routeIds = /* @__PURE__ */ new Set();
2507 let matchedRoutes = staticHandler ? pathnames.flatMap((pathname) => {
2508 let pathnameMatches = staticHandler.match(pathname);
2509 return pathnameMatches?.map((m, i) => ({
2510 ...m.route,
2511 parentId: pathnameMatches[i - 1]?.route.id
2512 })) ?? [];
2513 }).filter((route) => {
2514 if (!routeIds.has(route.id)) {
2515 routeIds.add(route.id);
2516 return true;
2517 }
2518 return false;
2519 }) : [];
2520 let payload = {
2521 type: "manifest",
2522 patches: Promise.all([...matchedRoutes.map((route) => getManifestRoute(route)), staticHandler ? getAdditionalRoutePatches(pathnames, staticHandler, Array.from(routeIds)) : Promise.resolve([])]).then((r) => r.flat(1))
2523 };
2524 return generateResponse({
2525 statusCode: 200,
2526 headers: new Headers({ "Content-Type": "text/x-component" }),
2527 payload
2528 }, {
2529 temporaryReferences,
2530 onError: defaultOnError
2531 });
2532}
2533function prependBasenameToRedirectResponse(response, basename = "/") {
2534 if (basename === "/") return response;
2535 let redirect = response.headers.get("Location");
2536 if (!redirect || isAbsoluteUrl(redirect)) return response;
2537 response.headers.set("Location", prependBasename({
2538 basename,
2539 pathname: redirect
2540 }));
2541 return response;
2542}
2543async function processServerAction(request, basename, decodeReply, loadServerAction, decodeAction, decodeFormState, onError, temporaryReferences) {
2544 const getRevalidationRequest = () => new Request(request.url, {
2545 method: "GET",
2546 headers: request.headers,
2547 signal: request.signal
2548 });
2549 const isFormRequest = canDecodeWithFormData(request.headers.get("Content-Type"));
2550 const actionId = request.headers.get("rsc-action-id");
2551 if (actionId) {
2552 if (!decodeReply || !loadServerAction) throw new Error("Cannot handle enhanced server action without decodeReply and loadServerAction functions");
2553 const actionArgs = await decodeReply(isFormRequest ? await request.formData() : await request.text(), { temporaryReferences });
2554 const serverAction = (await loadServerAction(actionId)).bind(null, ...actionArgs);
2555 let actionResult = Promise.resolve(serverAction());
2556 try {
2557 await actionResult;
2558 } catch (error) {
2559 if (isResponse(error)) return error;
2560 onError?.(error);
2561 }
2562 let maybeFormData = actionArgs.length === 1 ? actionArgs[0] : actionArgs[1];
2563 let skipRevalidation = (maybeFormData && typeof maybeFormData === "object" && maybeFormData instanceof FormData ? maybeFormData : null)?.has("$SKIP_REVALIDATION") ?? false;
2564 return {
2565 actionResult,
2566 revalidationRequest: getRevalidationRequest(),
2567 skipRevalidation
2568 };
2569 } else if (isFormRequest) {
2570 const formData = await request.clone().formData();
2571 if (Array.from(formData.keys()).some((k) => k.startsWith("$ACTION_"))) {
2572 if (!decodeAction) throw new Error("Cannot handle form actions without a decodeAction function");
2573 const action = await decodeAction(formData);
2574 let formState = void 0;
2575 try {
2576 let result = await action();
2577 if (isRedirectResponse(result)) result = prependBasenameToRedirectResponse(result, basename);
2578 formState = await decodeFormState?.(result, formData);
2579 } catch (error) {
2580 if (isRedirectResponse(error)) return prependBasenameToRedirectResponse(error, basename);
2581 if (isResponse(error)) return error;
2582 onError?.(error);
2583 }
2584 return {
2585 formState,
2586 revalidationRequest: getRevalidationRequest(),
2587 skipRevalidation: false
2588 };
2589 }
2590 }
2591}
2592async function generateResourceResponse(request, staticHandler, routeId, requestContext, onError) {
2593 try {
2594 return await staticHandler.queryRoute(request, {
2595 routeId,
2596 requestContext,
2597 async generateMiddlewareResponse(queryRoute) {
2598 try {
2599 return generateResourceResponse(await queryRoute(request));
2600 } catch (error) {
2601 return generateErrorResponse(error);
2602 }
2603 },
2604 normalizePath: (r) => getNormalizedPath(r)
2605 });
2606 } catch (error) {
2607 return generateErrorResponse(error);
2608 }
2609 function generateErrorResponse(error) {
2610 let response;
2611 if (isResponse(error)) response = error;
2612 else if (isRouteErrorResponse(error)) {
2613 onError?.(error);
2614 const errorMessage = typeof error.data === "string" ? error.data : error.statusText;
2615 response = new Response(errorMessage, {
2616 status: error.status,
2617 statusText: error.statusText
2618 });
2619 } else {
2620 onError?.(error);
2621 response = new Response("Internal Server Error", { status: 500 });
2622 }
2623 return generateResourceResponse(response);
2624 }
2625 function generateResourceResponse(response) {
2626 const headers = new Headers(response.headers);
2627 headers.set("React-Router-Resource", "true");
2628 return new Response(response.body, {
2629 status: response.status,
2630 statusText: response.statusText,
2631 headers
2632 });
2633 }
2634}
2635async function generateRenderResponse(request, staticHandler, basename, isDataRequest, decodeReply, requestContext, loadServerAction, decodeAction, decodeFormState, onError, generateResponse, temporaryReferences, allowedActionOrigins, routeDiscovery, clientVersion) {
2636 let statusCode = 200;
2637 let url = new URL(request.url);
2638 let isSubmission = isMutationMethod(request.method);
2639 let routeIdsToLoad = !isSubmission && url.searchParams.has("_routes") ? url.searchParams.get("_routes").split(",") : null;
2640 let actionResult;
2641 const ctx = {
2642 request,
2643 runningAction: false
2644 };
2645 const result = await ServerStorage.run(ctx, () => staticHandler.query(request, {
2646 requestContext,
2647 skipLoaderErrorBubbling: isDataRequest,
2648 skipRevalidation: isSubmission,
2649 ...routeIdsToLoad ? { filterMatchesToLoad: (m) => routeIdsToLoad.includes(m.route.id) } : {},
2650 normalizePath: (r) => getNormalizedPath(r),
2651 async generateMiddlewareResponse(query) {
2652 let formState;
2653 let skipRevalidation = false;
2654 let potentialCSRFAttackError;
2655 if (isMutationMethod(request.method)) {
2656 try {
2657 throwIfPotentialCSRFAttack(request, allowedActionOrigins);
2658 } catch (error) {
2659 onError?.(error);
2660 potentialCSRFAttackError = error;
2661 request = new Request(request.url, {
2662 method: "GET",
2663 headers: request.headers,
2664 signal: request.signal
2665 });
2666 }
2667 if (!potentialCSRFAttackError) {
2668 ctx.runningAction = true;
2669 let result = await processServerAction(request, basename, decodeReply, loadServerAction, decodeAction, decodeFormState, onError, temporaryReferences).finally(() => {
2670 ctx.runningAction = false;
2671 });
2672 if (isResponse(result)) return generateRedirectResponse(result, actionResult, basename, isDataRequest, generateResponse, temporaryReferences, ctx.redirect?.headers);
2673 skipRevalidation = result?.skipRevalidation ?? false;
2674 actionResult = result?.actionResult;
2675 formState = result?.formState;
2676 request = result?.revalidationRequest ?? request;
2677 if (ctx.redirect) return generateRedirectResponse(ctx.redirect, actionResult, basename, isDataRequest, generateResponse, temporaryReferences, void 0);
2678 }
2679 }
2680 let staticContext = await query(request, skipRevalidation ? { filterMatchesToLoad: () => false } : void 0);
2681 if (isResponse(staticContext)) return generateRedirectResponse(staticContext, actionResult, basename, isDataRequest, generateResponse, temporaryReferences, ctx.redirect?.headers);
2682 if (potentialCSRFAttackError) {
2683 staticContext.errors ??= {};
2684 staticContext.errors[staticContext.matches[0].route.id] = potentialCSRFAttackError;
2685 staticContext.statusCode = 400;
2686 }
2687 return generateStaticContextResponse(staticHandler, basename, generateResponse, statusCode, routeIdsToLoad, isDataRequest, isSubmission, actionResult, formState, staticContext, temporaryReferences, skipRevalidation, ctx.redirect?.headers, routeDiscovery, clientVersion);
2688 }
2689 }));
2690 if (isRedirectResponse(result)) return generateRedirectResponse(result, actionResult, basename, isDataRequest, generateResponse, temporaryReferences, ctx.redirect?.headers);
2691 invariant(isResponse(result), "Expected a response from query");
2692 return result;
2693}
2694function generateRedirectResponse(response, actionResult, basename, isDataRequest, generateResponse, temporaryReferences, sideEffectRedirectHeaders) {
2695 let redirect = response.headers.get("Location");
2696 if (isDataRequest && basename) redirect = stripBasename(redirect, basename) || redirect;
2697 let payload = {
2698 type: "redirect",
2699 location: redirect,
2700 reload: response.headers.get("X-Remix-Reload-Document") === "true",
2701 replace: response.headers.get("X-Remix-Replace") === "true",
2702 status: response.status,
2703 actionResult
2704 };
2705 let headers = new Headers(sideEffectRedirectHeaders);
2706 for (const [key, value] of response.headers.entries()) headers.append(key, value);
2707 headers.delete("Location");
2708 headers.delete("X-Remix-Reload-Document");
2709 headers.delete("X-Remix-Replace");
2710 headers.delete("Content-Length");
2711 headers.set("Content-Type", "text/x-component");
2712 return generateResponse({
2713 statusCode: 202,
2714 headers,
2715 payload
2716 }, {
2717 temporaryReferences,
2718 onError: defaultOnError
2719 });
2720}
2721async function generateStaticContextResponse(staticHandler, basename, generateResponse, statusCode, routeIdsToLoad, isDataRequest, isSubmission, actionResult, formState, staticContext, temporaryReferences, skipRevalidation, sideEffectRedirectHeaders, routeDiscovery, clientVersion) {
2722 statusCode = staticContext.statusCode ?? statusCode;
2723 if (staticContext.errors) staticContext.errors = Object.fromEntries(Object.entries(staticContext.errors).map(([key, error]) => [key, isRouteErrorResponse(error) ? Object.fromEntries(Object.entries(error)) : error]));
2724 staticContext.matches.forEach((m) => {
2725 const routeHasNoLoaderData = staticContext.loaderData[m.route.id] === void 0;
2726 const routeHasError = Boolean(staticContext.errors && m.route.id in staticContext.errors);
2727 if (routeHasNoLoaderData && !routeHasError) staticContext.loaderData[m.route.id] = null;
2728 });
2729 let headers = getDocumentHeadersImpl(staticContext, (match) => match.route.headers, sideEffectRedirectHeaders);
2730 headers.delete("Content-Length");
2731 const baseRenderPayload = {
2732 type: "render",
2733 basename: staticContext.basename,
2734 clientVersion,
2735 routeDiscovery: routeDiscovery ?? { mode: "lazy" },
2736 actionData: staticContext.actionData,
2737 errors: staticContext.errors,
2738 loaderData: staticContext.loaderData,
2739 location: staticContext.location,
2740 formState
2741 };
2742 const renderPayloadPromise = () => getRenderPayload(baseRenderPayload, staticHandler, basename, routeIdsToLoad, isDataRequest, staticContext, routeDiscovery);
2743 let payload;
2744 if (actionResult) payload = {
2745 type: "action",
2746 actionResult,
2747 rerender: skipRevalidation ? void 0 : renderPayloadPromise()
2748 };
2749 else if (isSubmission && isDataRequest) payload = {
2750 ...baseRenderPayload,
2751 matches: [],
2752 patches: Promise.resolve([])
2753 };
2754 else payload = await renderPayloadPromise();
2755 return generateResponse({
2756 statusCode,
2757 headers,
2758 payload
2759 }, {
2760 temporaryReferences,
2761 onError: defaultOnError
2762 });
2763}
2764async function getRenderPayload(baseRenderPayload, staticHandler, basename, routeIdsToLoad, isDataRequest, staticContext, routeDiscovery) {
2765 let routes = staticHandler.dataRoutes;
2766 let deepestRenderedRouteIdx = staticContext.matches.length - 1;
2767 let parentIds = {};
2768 staticContext.matches.forEach((m, i) => {
2769 if (i > 0) parentIds[m.route.id] = staticContext.matches[i - 1].route.id;
2770 if (staticContext.errors && m.route.id in staticContext.errors && deepestRenderedRouteIdx > i) deepestRenderedRouteIdx = i;
2771 });
2772 let matchesPromise = Promise.all(staticContext.matches.map((match, i) => {
2773 let isBelowErrorBoundary = i > deepestRenderedRouteIdx;
2774 let parentId = parentIds[match.route.id];
2775 return getRSCRouteMatch({
2776 staticContext,
2777 match,
2778 routeIdsToLoad,
2779 isBelowErrorBoundary,
2780 parentId
2781 });
2782 }));
2783 let patches;
2784 if (routeDiscovery?.mode === "initial" && !isDataRequest) patches = getAllRoutePatches(routes, basename).then((patches) => patches.filter((patch) => !staticContext.matches.some((m) => m.route.id === patch.id)));
2785 else patches = getAdditionalRoutePatches(getPathsWithAncestors([staticContext.location.pathname]), staticHandler, staticContext.matches.map((m) => m.route.id));
2786 return {
2787 ...baseRenderPayload,
2788 matches: await matchesPromise,
2789 patches
2790 };
2791}
2792async function getRSCRouteMatch({ staticContext, match, isBelowErrorBoundary, routeIdsToLoad, parentId }) {
2793 const route = match.route;
2794 await explodeLazyRoute(route);
2795 const Layout = route.Layout || React.Fragment;
2796 const Component = route.Component;
2797 const ErrorBoundary = route.ErrorBoundary;
2798 const HydrateFallback = route.HydrateFallback;
2799 const loaderData = staticContext.loaderData[route.id];
2800 const actionData = staticContext.actionData?.[route.id];
2801 const params = match.params;
2802 let element = void 0;
2803 let shouldLoadRoute = !routeIdsToLoad || routeIdsToLoad.includes(route.id);
2804 if (Component && shouldLoadRoute) element = !isBelowErrorBoundary ? React.createElement(Layout, null, isClientReference(Component) ? React.createElement(WithComponentProps, { children: React.createElement(Component) }) : React.createElement(Component, {
2805 loaderData,
2806 actionData,
2807 params,
2808 matches: staticContext.matches.map((match) => convertRouteMatchToUiMatch(match, staticContext.loaderData))
2809 })) : React.createElement(Outlet$2);
2810 let error = void 0;
2811 if (ErrorBoundary && staticContext.errors) error = staticContext.errors[route.id];
2812 const errorElement = ErrorBoundary ? React.createElement(Layout, null, isClientReference(ErrorBoundary) ? React.createElement(WithErrorBoundaryProps, { children: React.createElement(ErrorBoundary) }) : React.createElement(ErrorBoundary, {
2813 loaderData,
2814 actionData,
2815 params,
2816 error
2817 })) : void 0;
2818 const hydrateFallbackElement = HydrateFallback ? React.createElement(Layout, null, isClientReference(HydrateFallback) ? React.createElement(WithHydrateFallbackProps, { children: React.createElement(HydrateFallback) }) : React.createElement(HydrateFallback, {
2819 loaderData,
2820 actionData,
2821 params
2822 })) : void 0;
2823 const hmrRoute = route;
2824 return {
2825 clientAction: route.clientAction,
2826 clientLoader: route.clientLoader,
2827 element,
2828 errorElement,
2829 handle: route.handle,
2830 hasAction: !!route.action,
2831 hasComponent: !!Component,
2832 hasLoader: !!route.loader,
2833 hydrateFallbackElement,
2834 id: route.id,
2835 index: "index" in route ? route.index : void 0,
2836 links: route.links,
2837 meta: route.meta,
2838 params,
2839 parentId,
2840 path: route.path,
2841 pathname: match.pathname,
2842 pathnameBase: match.pathnameBase,
2843 shouldRevalidate: route.shouldRevalidate,
2844 ...hmrRoute.__ensureClientRouteModuleForHMR ? { __ensureClientRouteModuleForHMR: hmrRoute.__ensureClientRouteModuleForHMR } : {}
2845 };
2846}
2847async function getManifestRoute(route) {
2848 await explodeLazyRoute(route);
2849 const Layout = route.Layout || React.Fragment;
2850 const errorElement = route.ErrorBoundary ? React.createElement(Layout, null, React.createElement(route.ErrorBoundary)) : void 0;
2851 return {
2852 clientAction: route.clientAction,
2853 clientLoader: route.clientLoader,
2854 handle: route.handle,
2855 hasAction: !!route.action,
2856 hasComponent: !!route.Component,
2857 errorElement,
2858 hasLoader: !!route.loader,
2859 id: route.id,
2860 parentId: route.parentId,
2861 path: route.path,
2862 index: "index" in route ? route.index : void 0,
2863 links: route.links,
2864 meta: route.meta
2865 };
2866}
2867async function explodeLazyRoute(route) {
2868 if ("lazy" in route && route.lazy) {
2869 let { default: lazyDefaultExport, Component: lazyComponentExport, ...lazyProperties } = await route.lazy();
2870 let Component = lazyComponentExport || lazyDefaultExport;
2871 if (Component && !route.Component) route.Component = Component;
2872 for (let [k, v] of Object.entries(lazyProperties)) if (k !== "id" && k !== "path" && k !== "index" && k !== "children" && route[k] == null) route[k] = v;
2873 route.lazy = void 0;
2874 }
2875}
2876async function getAllRoutePatches(routes, basename) {
2877 let patches = [];
2878 async function traverse(route, parentId) {
2879 let manifestRoute = await getManifestRoute({
2880 ...route,
2881 parentId
2882 });
2883 patches.push(manifestRoute);
2884 if ("children" in route && route.children?.length) for (let child of route.children) await traverse(child, route.id);
2885 }
2886 for (let route of routes) await traverse(route, void 0);
2887 return patches.filter((p) => !!p.parentId);
2888}
2889async function getAdditionalRoutePatches(pathnames, staticHandler, matchedRouteIds) {
2890 let patchRouteMatches = /* @__PURE__ */ new Map();
2891 let matchedPaths = /* @__PURE__ */ new Set();
2892 for (const pathname of pathnames) {
2893 if (matchedPaths.has(pathname)) continue;
2894 matchedPaths.add(pathname);
2895 let matches = staticHandler.match(pathname) || [];
2896 matches.forEach((m, i) => {
2897 if (patchRouteMatches.get(m.route.id)) return;
2898 patchRouteMatches.set(m.route.id, {
2899 ...m.route,
2900 parentId: matches[i - 1]?.route.id
2901 });
2902 });
2903 }
2904 return await Promise.all([...patchRouteMatches.values()].filter((route) => !matchedRouteIds.some((id) => id === route.id)).map((route) => getManifestRoute(route)));
2905}
2906function isReactServerRequest(url) {
2907 return url.pathname.endsWith(".rsc");
2908}
2909function isManifestRequest(url) {
2910 return url.pathname.endsWith(".manifest");
2911}
2912function defaultOnError(error) {
2913 if (isRedirectResponse(error)) return createRedirectErrorDigest(error);
2914 if (isResponse(error) || isDataWithResponseInit(error)) return createRouteErrorResponseDigest(error);
2915}
2916function isClientReference(x) {
2917 try {
2918 return x.$$typeof === Symbol.for("react.client.reference");
2919 } catch {
2920 return false;
2921 }
2922}
2923function canDecodeWithFormData(contentType) {
2924 if (!contentType) return false;
2925 return contentType.match(/\bapplication\/x-www-form-urlencoded\b/) || contentType.match(/\bmultipart\/form-data\b/);
2926}
2927//#endregion
2928//#region lib/href.ts
2929function stringify(p) {
2930 return p == null ? "" : typeof p === "string" ? p : String(p);
2931}
2932/**
2933* Returns a resolved URL path for the specified route.
2934*
2935* Param values are percent-encoded for use in a path segment: characters that
2936* would change the URL structure (`/`, `?`, `#`, `%`, whitespace, non-ASCII)
2937* are escaped, while characters that RFC 3986 allows literally in a path
2938* segment (`$ & + , ; = : @`) are kept as-is. Note this differs from query-string
2939* encoding (`encodeURIComponent`/`URLSearchParams`), where those characters are
2940* delimiters and must be escaped. Splat (`*`) values are encoded per segment,
2941* preserving `/` separators.
2942*
2943* See [RFC 3986 §3.3](https://datatracker.ietf.org/doc/html/rfc3986#section-3.3)
2944*
2945* @example
2946* const h = href("/:lang?/about", { lang: "en" })
2947* // -> `/en/about`
2948*
2949* <Link to={href("/products/:id", { id: "abc123" })} />
2950*
2951* @public
2952* @category Utils
2953* @mode framework
2954* @param path The route path to resolve
2955* @param args The route params to use when resolving the path
2956* @returns The resolved URL path
2957*/
2958function href(path, ...args) {
2959 let params = args[0];
2960 let result = trimTrailingSplat(path).replace(/\/:([\w-]+)(\?)?/g, (_, param, questionMark) => {
2961 const isRequired = questionMark === void 0;
2962 const value = params?.[param];
2963 if (isRequired && value === void 0) throw new Error(`Path '${path}' requires param '${param}' but it was not provided`);
2964 return value == null ? "" : "/" + encodePathParam(stringify(value));
2965 });
2966 if (path.endsWith("*")) {
2967 const value = params?.["*"];
2968 if (value !== void 0) result += "/" + stringify(value).split("/").map(encodePathParam).join("/");
2969 }
2970 return result || "/";
2971}
2972/**
2973* Removes a trailing splat and any number of slashes from the end of the path.
2974*
2975* Benchmarked to be faster than `path.replace(/\/*\*?$/, "")`, which backtracks.
2976*/
2977function trimTrailingSplat(path) {
2978 let i = path.length - 1;
2979 let char = path[i];
2980 if (char !== "*" && char !== "/") return path;
2981 i--;
2982 for (; i >= 0; i--) if (path[i] !== "/") break;
2983 return path.slice(0, i + 1);
2984}
2985//#endregion
2986//#region lib/server-runtime/crypto.ts
2987const encoder = /* @__PURE__ */ new TextEncoder();
2988const sign = async (value, secret) => {
2989 let data = encoder.encode(value);
2990 let key = await createKey(secret, ["sign"]);
2991 let signature = await crypto.subtle.sign("HMAC", key, data);
2992 let hash = btoa(String.fromCharCode(...new Uint8Array(signature))).replace(/=+$/, "");
2993 return value + "." + hash;
2994};
2995const unsign = async (cookie, secret) => {
2996 let index = cookie.lastIndexOf(".");
2997 let value = cookie.slice(0, index);
2998 let hash = cookie.slice(index + 1);
2999 let data = encoder.encode(value);
3000 let key = await createKey(secret, ["verify"]);
3001 try {
3002 let signature = byteStringToUint8Array(atob(hash));
3003 return await crypto.subtle.verify("HMAC", key, signature, data) ? value : false;
3004 } catch {
3005 return false;
3006 }
3007};
3008const createKey = async (secret, usages) => crypto.subtle.importKey("raw", encoder.encode(secret), {
3009 name: "HMAC",
3010 hash: "SHA-256"
3011}, false, usages);
3012function byteStringToUint8Array(byteString) {
3013 let array = new Uint8Array(byteString.length);
3014 for (let i = 0; i < byteString.length; i++) array[i] = byteString.charCodeAt(i);
3015 return array;
3016}
3017//#endregion
3018//#region lib/server-runtime/cookies.ts
3019/**
3020* Creates a logical container for managing a browser cookie from the server.
3021*
3022* @public
3023* @category Utils
3024* @mode framework
3025* @mode data
3026* @param name The name of the cookie.
3027* @param cookieOptions Options for parsing and serializing the cookie.
3028* @returns A {@link Cookie} object for parsing and serializing the cookie.
3029*/
3030const createCookie = (name, cookieOptions = {}) => {
3031 let { secrets = [], ...options } = {
3032 path: "/",
3033 sameSite: "lax",
3034 ...cookieOptions
3035 };
3036 warnOnceAboutExpiresCookie(name, options.expires);
3037 return {
3038 get name() {
3039 return name;
3040 },
3041 get isSigned() {
3042 return secrets.length > 0;
3043 },
3044 get expires() {
3045 return typeof options.maxAge !== "undefined" ? new Date(Date.now() + options.maxAge * 1e3) : options.expires;
3046 },
3047 async parse(cookieHeader, parseOptions) {
3048 if (!cookieHeader) return null;
3049 let cookies = parse(cookieHeader, {
3050 ...options,
3051 ...parseOptions
3052 });
3053 if (name in cookies) {
3054 let value = cookies[name];
3055 if (typeof value === "string" && value !== "") return await decodeCookieValue(value, secrets);
3056 else return "";
3057 } else return null;
3058 },
3059 async serialize(value, serializeOptions) {
3060 return serialize(name, value === "" ? "" : await encodeCookieValue(value, secrets), {
3061 ...options,
3062 ...serializeOptions
3063 });
3064 }
3065 };
3066};
3067/**
3068* Returns `true` if a value is a React Router {@link Cookie} object.
3069*
3070* @public
3071* @category Utils
3072* @mode framework
3073* @mode data
3074* @param object The value to check.
3075* @returns `true` if the value is a React Router {@link Cookie} object;
3076* otherwise, `false`.
3077*/
3078const isCookie = (object) => {
3079 return object != null && typeof object.name === "string" && typeof object.isSigned === "boolean" && typeof object.parse === "function" && typeof object.serialize === "function";
3080};
3081async function encodeCookieValue(value, secrets) {
3082 let encoded = encodeData(value);
3083 if (secrets.length > 0) encoded = await sign(encoded, secrets[0]);
3084 return encoded;
3085}
3086async function decodeCookieValue(value, secrets) {
3087 if (secrets.length > 0) {
3088 for (let secret of secrets) {
3089 let unsignedValue = await unsign(value, secret);
3090 if (unsignedValue !== false) return decodeData(unsignedValue);
3091 }
3092 return null;
3093 }
3094 return decodeData(value);
3095}
3096function encodeData(value) {
3097 return btoa(myUnescape(encodeURIComponent(JSON.stringify(value))));
3098}
3099function decodeData(value) {
3100 try {
3101 return JSON.parse(decodeURIComponent(myEscape(atob(value))));
3102 } catch {
3103 return {};
3104 }
3105}
3106function myEscape(value) {
3107 let str = value.toString();
3108 let result = "";
3109 let index = 0;
3110 let chr, code;
3111 while (index < str.length) {
3112 chr = str.charAt(index++);
3113 if (/[\w*+\-./@]/.exec(chr)) result += chr;
3114 else {
3115 code = chr.charCodeAt(0);
3116 if (code < 256) result += "%" + hex(code, 2);
3117 else result += "%u" + hex(code, 4).toUpperCase();
3118 }
3119 }
3120 return result;
3121}
3122function hex(code, length) {
3123 let result = code.toString(16);
3124 while (result.length < length) result = "0" + result;
3125 return result;
3126}
3127function myUnescape(value) {
3128 let str = value.toString();
3129 let result = "";
3130 let index = 0;
3131 let chr, part;
3132 while (index < str.length) {
3133 chr = str.charAt(index++);
3134 if (chr === "%") if (str.charAt(index) === "u") {
3135 part = str.slice(index + 1, index + 5);
3136 if (/^[\da-f]{4}$/i.exec(part)) {
3137 result += String.fromCharCode(parseInt(part, 16));
3138 index += 5;
3139 continue;
3140 }
3141 } else {
3142 part = str.slice(index, index + 2);
3143 if (/^[\da-f]{2}$/i.exec(part)) {
3144 result += String.fromCharCode(parseInt(part, 16));
3145 index += 2;
3146 continue;
3147 }
3148 }
3149 result += chr;
3150 }
3151 return result;
3152}
3153function warnOnceAboutExpiresCookie(name, expires) {
3154 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.`);
3155}
3156//#endregion
3157//#region lib/server-runtime/sessions.ts
3158function flash(name) {
3159 return `__flash_${name}__`;
3160}
3161/**
3162* Creates a new Session object.
3163*
3164* Note: This function is typically not invoked directly by application code.
3165* Instead, use a `SessionStorage` object's `getSession` method.
3166*
3167* @category Utils
3168* @param initialData The initial data for the session.
3169* @param id The identifier for the session. Defaults to an empty string for a
3170* new session.
3171* @returns A new {@link Session} object.
3172*/
3173const createSession = (initialData = {}, id = "") => {
3174 let map = new Map(Object.entries(initialData));
3175 return {
3176 get id() {
3177 return id;
3178 },
3179 get data() {
3180 return Object.fromEntries(map);
3181 },
3182 has(name) {
3183 return map.has(name) || map.has(flash(name));
3184 },
3185 get(name) {
3186 if (map.has(name)) return map.get(name);
3187 let flashName = flash(name);
3188 if (map.has(flashName)) {
3189 let value = map.get(flashName);
3190 map.delete(flashName);
3191 return value;
3192 }
3193 },
3194 set(name, value) {
3195 map.set(name, value);
3196 },
3197 flash(name, value) {
3198 map.set(flash(name), value);
3199 },
3200 unset(name) {
3201 map.delete(name);
3202 }
3203 };
3204};
3205/**
3206* Returns `true` if a value is a React Router {@link Session} object.
3207*
3208* @public
3209* @category Utils
3210* @mode framework
3211* @mode data
3212* @param object The value to check.
3213* @returns `true` if the value is a React Router {@link Session} object;
3214* otherwise, `false`.
3215*/
3216const isSession = (object) => {
3217 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";
3218};
3219/**
3220* Creates a SessionStorage object using a SessionIdStorageStrategy.
3221*
3222* Note: This is a low-level API that should only be used if none of the
3223* existing session storage options meet your requirements.
3224*
3225* @category Utils
3226* @param strategy The strategy used to store session identifiers and data.
3227* @returns A {@link SessionStorage} object that persists session data using the
3228* provided strategy.
3229*/
3230function createSessionStorage({ cookie: cookieArg, createData, readData, updateData, deleteData }) {
3231 let cookie = isCookie(cookieArg) ? cookieArg : createCookie(cookieArg?.name || "__session", cookieArg);
3232 warnOnceAboutSigningSessionCookie(cookie);
3233 return {
3234 async getSession(cookieHeader, options) {
3235 let id = cookieHeader && await cookie.parse(cookieHeader, options);
3236 return createSession(id && await readData(id) || {}, id || "");
3237 },
3238 async commitSession(session, options) {
3239 let { id, data } = session;
3240 let expires = options?.maxAge != null ? new Date(Date.now() + options.maxAge * 1e3) : options?.expires != null ? options.expires : cookie.expires;
3241 if (id) await updateData(id, data, expires);
3242 else id = await createData(data, expires);
3243 return cookie.serialize(id, options);
3244 },
3245 async destroySession(session, options) {
3246 await deleteData(session.id);
3247 return cookie.serialize("", {
3248 ...options,
3249 maxAge: void 0,
3250 expires: /* @__PURE__ */ new Date(0)
3251 });
3252 }
3253 };
3254}
3255function warnOnceAboutSigningSessionCookie(cookie) {
3256 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.`);
3257}
3258//#endregion
3259//#region lib/server-runtime/sessions/cookieStorage.ts
3260/**
3261* Creates and returns a SessionStorage object that stores all session data
3262* directly in the session cookie itself.
3263*
3264* This has the advantage that no database or other backend services are
3265* needed, and can help to simplify some load-balanced scenarios. However, it
3266* also has the limitation that serialized session data may not exceed the
3267* browser's maximum cookie size. Trade-offs!
3268*
3269* @public
3270* @category Utils
3271* @mode framework
3272* @mode data
3273* @param options Options for creating the cookie-backed session storage.
3274* @returns A {@link SessionStorage} object that stores all session data in its
3275* cookie.
3276*/
3277function createCookieSessionStorage({ cookie: cookieArg } = {}) {
3278 let cookie = isCookie(cookieArg) ? cookieArg : createCookie(cookieArg?.name || "__session", cookieArg);
3279 warnOnceAboutSigningSessionCookie(cookie);
3280 return {
3281 async getSession(cookieHeader, options) {
3282 return createSession(cookieHeader && await cookie.parse(cookieHeader, options) || {});
3283 },
3284 async commitSession(session, options) {
3285 let serializedCookie = await cookie.serialize(session.data, options);
3286 if (serializedCookie.length > 4096) throw new Error("Cookie length will exceed browser maximum. Length: " + serializedCookie.length);
3287 return serializedCookie;
3288 },
3289 async destroySession(_session, options) {
3290 return cookie.serialize("", {
3291 ...options,
3292 maxAge: void 0,
3293 expires: /* @__PURE__ */ new Date(0)
3294 });
3295 }
3296 };
3297}
3298//#endregion
3299//#region lib/server-runtime/sessions/memoryStorage.ts
3300/**
3301* Creates and returns a simple in-memory SessionStorage object.
3302*
3303* Intended for local development and testing. It does not scale beyond a single
3304* process, and all session data is lost when the server process stops/restarts.
3305*
3306* @public
3307* @category Utils
3308* @mode framework
3309* @mode data
3310* @param options Options for creating the in-memory session storage.
3311* @returns A {@link SessionStorage} object that stores session data in memory.
3312*/
3313function createMemorySessionStorage({ cookie } = {}) {
3314 let map = /* @__PURE__ */ new Map();
3315 return createSessionStorage({
3316 cookie,
3317 async createData(data, expires) {
3318 let id = crypto.randomUUID();
3319 map.set(id, {
3320 data,
3321 expires
3322 });
3323 return id;
3324 },
3325 async readData(id) {
3326 if (map.has(id)) {
3327 let { data, expires } = map.get(id);
3328 if (!expires || expires > /* @__PURE__ */ new Date()) return data;
3329 if (expires) map.delete(id);
3330 }
3331 return null;
3332 },
3333 async updateData(id, data, expires) {
3334 map.set(id, {
3335 data,
3336 expires
3337 });
3338 },
3339 async deleteData(id) {
3340 map.delete(id);
3341 }
3342 });
3343}
3344//#endregion
3345export { 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 };