UNPKG

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