UNPKG

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