UNPKG

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