UNPKG

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