UNPKG

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