UNPKG

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