UNPKG

119 kBJavaScriptView Raw
1import { AsyncLocalStorage } from 'node:async_hooks';
2import * as React2 from 'react';
3import { splitCookiesString } from 'set-cookie-parser';
4import { UNSAFE_AwaitContextProvider, UNSAFE_WithComponentProps, Outlet as Outlet$1, UNSAFE_WithErrorBoundaryProps, UNSAFE_WithHydrateFallbackProps } from 'react-router/internal/react-server-client';
5export { BrowserRouter, Form, HashRouter, Link, Links, MemoryRouter, Meta, NavLink, Navigate, Outlet, Route, Router, RouterProvider, Routes, ScrollRestoration, StaticRouter, StaticRouterProvider, unstable_HistoryRouter } from 'react-router/internal/react-server-client';
6import { serialize, parse } from 'cookie';
7
8/**
9 * react-router v7.14.0
10 *
11 * Copyright (c) Remix Software Inc.
12 *
13 * This source code is licensed under the MIT license found in the
14 * LICENSE.md file in the root directory of this source tree.
15 *
16 * @license MIT
17 */
18var __typeError = (msg) => {
19 throw TypeError(msg);
20};
21var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
22var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
23var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
24
25// lib/router/history.ts
26function invariant(value, message) {
27 if (value === false || value === null || typeof value === "undefined") {
28 throw new Error(message);
29 }
30}
31function warning(cond, message) {
32 if (!cond) {
33 if (typeof console !== "undefined") console.warn(message);
34 try {
35 throw new Error(message);
36 } catch (e) {
37 }
38 }
39}
40function createKey() {
41 return Math.random().toString(36).substring(2, 10);
42}
43function createLocation(current, to, state = null, key, unstable_mask) {
44 let location = {
45 pathname: typeof current === "string" ? current : current.pathname,
46 search: "",
47 hash: "",
48 ...typeof to === "string" ? parsePath(to) : to,
49 state,
50 // TODO: This could be cleaned up. push/replace should probably just take
51 // full Locations now and avoid the need to run through this flow at all
52 // But that's a pretty big refactor to the current test suite so going to
53 // keep as is for the time being and just let any incoming keys take precedence
54 key: to && to.key || key || createKey(),
55 unstable_mask
56 };
57 return location;
58}
59function createPath({
60 pathname = "/",
61 search = "",
62 hash = ""
63}) {
64 if (search && search !== "?")
65 pathname += search.charAt(0) === "?" ? search : "?" + search;
66 if (hash && hash !== "#")
67 pathname += hash.charAt(0) === "#" ? hash : "#" + hash;
68 return pathname;
69}
70function parsePath(path) {
71 let parsedPath = {};
72 if (path) {
73 let hashIndex = path.indexOf("#");
74 if (hashIndex >= 0) {
75 parsedPath.hash = path.substring(hashIndex);
76 path = path.substring(0, hashIndex);
77 }
78 let searchIndex = path.indexOf("?");
79 if (searchIndex >= 0) {
80 parsedPath.search = path.substring(searchIndex);
81 path = path.substring(0, searchIndex);
82 }
83 if (path) {
84 parsedPath.pathname = path;
85 }
86 }
87 return parsedPath;
88}
89
90// lib/router/instrumentation.ts
91var UninstrumentedSymbol = Symbol("Uninstrumented");
92function getRouteInstrumentationUpdates(fns, route) {
93 let aggregated = {
94 lazy: [],
95 "lazy.loader": [],
96 "lazy.action": [],
97 "lazy.middleware": [],
98 middleware: [],
99 loader: [],
100 action: []
101 };
102 fns.forEach(
103 (fn) => fn({
104 id: route.id,
105 index: route.index,
106 path: route.path,
107 instrument(i) {
108 let keys = Object.keys(aggregated);
109 for (let key of keys) {
110 if (i[key]) {
111 aggregated[key].push(i[key]);
112 }
113 }
114 }
115 })
116 );
117 let updates = {};
118 if (typeof route.lazy === "function" && aggregated.lazy.length > 0) {
119 let instrumented = wrapImpl(aggregated.lazy, route.lazy, () => void 0);
120 if (instrumented) {
121 updates.lazy = instrumented;
122 }
123 }
124 if (typeof route.lazy === "object") {
125 let lazyObject = route.lazy;
126 ["middleware", "loader", "action"].forEach((key) => {
127 let lazyFn = lazyObject[key];
128 let instrumentations = aggregated[`lazy.${key}`];
129 if (typeof lazyFn === "function" && instrumentations.length > 0) {
130 let instrumented = wrapImpl(instrumentations, lazyFn, () => void 0);
131 if (instrumented) {
132 updates.lazy = Object.assign(updates.lazy || {}, {
133 [key]: instrumented
134 });
135 }
136 }
137 });
138 }
139 ["loader", "action"].forEach((key) => {
140 let handler = route[key];
141 if (typeof handler === "function" && aggregated[key].length > 0) {
142 let original = handler[UninstrumentedSymbol] ?? handler;
143 let instrumented = wrapImpl(
144 aggregated[key],
145 original,
146 (...args) => getHandlerInfo(args[0])
147 );
148 if (instrumented) {
149 if (key === "loader" && original.hydrate === true) {
150 instrumented.hydrate = true;
151 }
152 instrumented[UninstrumentedSymbol] = original;
153 updates[key] = instrumented;
154 }
155 }
156 });
157 if (route.middleware && route.middleware.length > 0 && aggregated.middleware.length > 0) {
158 updates.middleware = route.middleware.map((middleware) => {
159 let original = middleware[UninstrumentedSymbol] ?? middleware;
160 let instrumented = wrapImpl(
161 aggregated.middleware,
162 original,
163 (...args) => getHandlerInfo(args[0])
164 );
165 if (instrumented) {
166 instrumented[UninstrumentedSymbol] = original;
167 return instrumented;
168 }
169 return middleware;
170 });
171 }
172 return updates;
173}
174function wrapImpl(impls, handler, getInfo) {
175 if (impls.length === 0) {
176 return null;
177 }
178 return async (...args) => {
179 let result = await recurseRight(
180 impls,
181 getInfo(...args),
182 () => handler(...args),
183 impls.length - 1
184 );
185 if (result.type === "error") {
186 throw result.value;
187 }
188 return result.value;
189 };
190}
191async function recurseRight(impls, info, handler, index) {
192 let impl = impls[index];
193 let result;
194 if (!impl) {
195 try {
196 let value = await handler();
197 result = { type: "success", value };
198 } catch (e) {
199 result = { type: "error", value: e };
200 }
201 } else {
202 let handlerPromise = void 0;
203 let callHandler = async () => {
204 if (handlerPromise) {
205 console.error("You cannot call instrumented handlers more than once");
206 } else {
207 handlerPromise = recurseRight(impls, info, handler, index - 1);
208 }
209 result = await handlerPromise;
210 invariant(result, "Expected a result");
211 if (result.type === "error" && result.value instanceof Error) {
212 return { status: "error", error: result.value };
213 }
214 return { status: "success", error: void 0 };
215 };
216 try {
217 await impl(callHandler, info);
218 } catch (e) {
219 console.error("An instrumentation function threw an error:", e);
220 }
221 if (!handlerPromise) {
222 await callHandler();
223 }
224 await handlerPromise;
225 }
226 if (result) {
227 return result;
228 }
229 return {
230 type: "error",
231 value: new Error("No result assigned in instrumentation chain.")
232 };
233}
234function getHandlerInfo(args) {
235 let { request, context, params, unstable_pattern } = args;
236 return {
237 request: getReadonlyRequest(request),
238 params: { ...params },
239 unstable_pattern,
240 context: getReadonlyContext(context)
241 };
242}
243function getReadonlyRequest(request) {
244 return {
245 method: request.method,
246 url: request.url,
247 headers: {
248 get: (...args) => request.headers.get(...args)
249 }
250 };
251}
252function getReadonlyContext(context) {
253 if (isPlainObject(context)) {
254 let frozen = { ...context };
255 Object.freeze(frozen);
256 return frozen;
257 } else {
258 return {
259 get: (ctx) => context.get(ctx)
260 };
261 }
262}
263var objectProtoNames = Object.getOwnPropertyNames(Object.prototype).sort().join("\0");
264function isPlainObject(thing) {
265 if (thing === null || typeof thing !== "object") {
266 return false;
267 }
268 const proto = Object.getPrototypeOf(thing);
269 return proto === Object.prototype || proto === null || Object.getOwnPropertyNames(proto).sort().join("\0") === objectProtoNames;
270}
271
272// lib/router/utils.ts
273function createContext(defaultValue) {
274 return { defaultValue };
275}
276var _map;
277var RouterContextProvider = class {
278 /**
279 * Create a new `RouterContextProvider` instance
280 * @param init An optional initial context map to populate the provider with
281 */
282 constructor(init) {
283 __privateAdd(this, _map, /* @__PURE__ */ new Map());
284 if (init) {
285 for (let [context, value] of init) {
286 this.set(context, value);
287 }
288 }
289 }
290 /**
291 * Access a value from the context. If no value has been set for the context,
292 * it will return the context's `defaultValue` if provided, or throw an error
293 * if no `defaultValue` was set.
294 * @param context The context to get the value for
295 * @returns The value for the context, or the context's `defaultValue` if no
296 * value was set
297 */
298 get(context) {
299 if (__privateGet(this, _map).has(context)) {
300 return __privateGet(this, _map).get(context);
301 }
302 if (context.defaultValue !== void 0) {
303 return context.defaultValue;
304 }
305 throw new Error("No value found for context");
306 }
307 /**
308 * Set a value for the context. If the context already has a value set, this
309 * will overwrite it.
310 *
311 * @param context The context to set the value for
312 * @param value The value to set for the context
313 * @returns {void}
314 */
315 set(context, value) {
316 __privateGet(this, _map).set(context, value);
317 }
318};
319_map = new WeakMap();
320var unsupportedLazyRouteObjectKeys = /* @__PURE__ */ new Set([
321 "lazy",
322 "caseSensitive",
323 "path",
324 "id",
325 "index",
326 "children"
327]);
328function isUnsupportedLazyRouteObjectKey(key) {
329 return unsupportedLazyRouteObjectKeys.has(
330 key
331 );
332}
333var unsupportedLazyRouteFunctionKeys = /* @__PURE__ */ new Set([
334 "lazy",
335 "caseSensitive",
336 "path",
337 "id",
338 "index",
339 "middleware",
340 "children"
341]);
342function isUnsupportedLazyRouteFunctionKey(key) {
343 return unsupportedLazyRouteFunctionKeys.has(
344 key
345 );
346}
347function isIndexRoute(route) {
348 return route.index === true;
349}
350function convertRoutesToDataRoutes(routes, mapRouteProperties, parentPath = [], manifest = {}, allowInPlaceMutations = false) {
351 return routes.map((route, index) => {
352 let treePath = [...parentPath, String(index)];
353 let id = typeof route.id === "string" ? route.id : treePath.join("-");
354 invariant(
355 route.index !== true || !route.children,
356 `Cannot specify children on an index route`
357 );
358 invariant(
359 allowInPlaceMutations || !manifest[id],
360 `Found a route id collision on id "${id}". Route id's must be globally unique within Data Router usages`
361 );
362 if (isIndexRoute(route)) {
363 let indexRoute = {
364 ...route,
365 id
366 };
367 manifest[id] = mergeRouteUpdates(
368 indexRoute,
369 mapRouteProperties(indexRoute)
370 );
371 return indexRoute;
372 } else {
373 let pathOrLayoutRoute = {
374 ...route,
375 id,
376 children: void 0
377 };
378 manifest[id] = mergeRouteUpdates(
379 pathOrLayoutRoute,
380 mapRouteProperties(pathOrLayoutRoute)
381 );
382 if (route.children) {
383 pathOrLayoutRoute.children = convertRoutesToDataRoutes(
384 route.children,
385 mapRouteProperties,
386 treePath,
387 manifest,
388 allowInPlaceMutations
389 );
390 }
391 return pathOrLayoutRoute;
392 }
393 });
394}
395function mergeRouteUpdates(route, updates) {
396 return Object.assign(route, {
397 ...updates,
398 ...typeof updates.lazy === "object" && updates.lazy != null ? {
399 lazy: {
400 ...route.lazy,
401 ...updates.lazy
402 }
403 } : {}
404 });
405}
406function matchRoutes(routes, locationArg, basename = "/") {
407 return matchRoutesImpl(routes, locationArg, basename, false);
408}
409function matchRoutesImpl(routes, locationArg, basename, allowPartial) {
410 let location = typeof locationArg === "string" ? parsePath(locationArg) : locationArg;
411 let pathname = stripBasename(location.pathname || "/", basename);
412 if (pathname == null) {
413 return null;
414 }
415 let branches = flattenRoutes(routes);
416 rankRouteBranches(branches);
417 let matches = null;
418 for (let i = 0; matches == null && i < branches.length; ++i) {
419 let decoded = decodePath(pathname);
420 matches = matchRouteBranch(
421 branches[i],
422 decoded,
423 allowPartial
424 );
425 }
426 return matches;
427}
428function convertRouteMatchToUiMatch(match, loaderData) {
429 let { route, pathname, params } = match;
430 return {
431 id: route.id,
432 pathname,
433 params,
434 data: loaderData[route.id],
435 loaderData: loaderData[route.id],
436 handle: route.handle
437 };
438}
439function flattenRoutes(routes, branches = [], parentsMeta = [], parentPath = "", _hasParentOptionalSegments = false) {
440 let flattenRoute = (route, index, hasParentOptionalSegments = _hasParentOptionalSegments, relativePath) => {
441 let meta = {
442 relativePath: relativePath === void 0 ? route.path || "" : relativePath,
443 caseSensitive: route.caseSensitive === true,
444 childrenIndex: index,
445 route
446 };
447 if (meta.relativePath.startsWith("/")) {
448 if (!meta.relativePath.startsWith(parentPath) && hasParentOptionalSegments) {
449 return;
450 }
451 invariant(
452 meta.relativePath.startsWith(parentPath),
453 `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.`
454 );
455 meta.relativePath = meta.relativePath.slice(parentPath.length);
456 }
457 let path = joinPaths([parentPath, meta.relativePath]);
458 let routesMeta = parentsMeta.concat(meta);
459 if (route.children && route.children.length > 0) {
460 invariant(
461 // Our types know better, but runtime JS may not!
462 // @ts-expect-error
463 route.index !== true,
464 `Index routes must not have child routes. Please remove all child routes from route path "${path}".`
465 );
466 flattenRoutes(
467 route.children,
468 branches,
469 routesMeta,
470 path,
471 hasParentOptionalSegments
472 );
473 }
474 if (route.path == null && !route.index) {
475 return;
476 }
477 branches.push({
478 path,
479 score: computeScore(path, route.index),
480 routesMeta
481 });
482 };
483 routes.forEach((route, index) => {
484 if (route.path === "" || !route.path?.includes("?")) {
485 flattenRoute(route, index);
486 } else {
487 for (let exploded of explodeOptionalSegments(route.path)) {
488 flattenRoute(route, index, true, exploded);
489 }
490 }
491 });
492 return branches;
493}
494function explodeOptionalSegments(path) {
495 let segments = path.split("/");
496 if (segments.length === 0) return [];
497 let [first, ...rest] = segments;
498 let isOptional = first.endsWith("?");
499 let required = first.replace(/\?$/, "");
500 if (rest.length === 0) {
501 return isOptional ? [required, ""] : [required];
502 }
503 let restExploded = explodeOptionalSegments(rest.join("/"));
504 let result = [];
505 result.push(
506 ...restExploded.map(
507 (subpath) => subpath === "" ? required : [required, subpath].join("/")
508 )
509 );
510 if (isOptional) {
511 result.push(...restExploded);
512 }
513 return result.map(
514 (exploded) => path.startsWith("/") && exploded === "" ? "/" : exploded
515 );
516}
517function rankRouteBranches(branches) {
518 branches.sort(
519 (a, b) => a.score !== b.score ? b.score - a.score : compareIndexes(
520 a.routesMeta.map((meta) => meta.childrenIndex),
521 b.routesMeta.map((meta) => meta.childrenIndex)
522 )
523 );
524}
525var paramRe = /^:[\w-]+$/;
526var dynamicSegmentValue = 3;
527var indexRouteValue = 2;
528var emptySegmentValue = 1;
529var staticSegmentValue = 10;
530var splatPenalty = -2;
531var isSplat = (s) => s === "*";
532function computeScore(path, index) {
533 let segments = path.split("/");
534 let initialScore = segments.length;
535 if (segments.some(isSplat)) {
536 initialScore += splatPenalty;
537 }
538 if (index) {
539 initialScore += indexRouteValue;
540 }
541 return segments.filter((s) => !isSplat(s)).reduce(
542 (score, segment) => score + (paramRe.test(segment) ? dynamicSegmentValue : segment === "" ? emptySegmentValue : staticSegmentValue),
543 initialScore
544 );
545}
546function compareIndexes(a, b) {
547 let siblings = a.length === b.length && a.slice(0, -1).every((n, i) => n === b[i]);
548 return siblings ? (
549 // If two routes are siblings, we should try to match the earlier sibling
550 // first. This allows people to have fine-grained control over the matching
551 // behavior by simply putting routes with identical paths in the order they
552 // want them tried.
553 a[a.length - 1] - b[b.length - 1]
554 ) : (
555 // Otherwise, it doesn't really make sense to rank non-siblings by index,
556 // so they sort equally.
557 0
558 );
559}
560function matchRouteBranch(branch, pathname, allowPartial = false) {
561 let { routesMeta } = branch;
562 let matchedParams = {};
563 let matchedPathname = "/";
564 let matches = [];
565 for (let i = 0; i < routesMeta.length; ++i) {
566 let meta = routesMeta[i];
567 let end = i === routesMeta.length - 1;
568 let remainingPathname = matchedPathname === "/" ? pathname : pathname.slice(matchedPathname.length) || "/";
569 let match = matchPath(
570 { path: meta.relativePath, caseSensitive: meta.caseSensitive, end },
571 remainingPathname
572 );
573 let route = meta.route;
574 if (!match && end && allowPartial && !routesMeta[routesMeta.length - 1].route.index) {
575 match = matchPath(
576 {
577 path: meta.relativePath,
578 caseSensitive: meta.caseSensitive,
579 end: false
580 },
581 remainingPathname
582 );
583 }
584 if (!match) {
585 return null;
586 }
587 Object.assign(matchedParams, match.params);
588 matches.push({
589 // TODO: Can this as be avoided?
590 params: matchedParams,
591 pathname: joinPaths([matchedPathname, match.pathname]),
592 pathnameBase: normalizePathname(
593 joinPaths([matchedPathname, match.pathnameBase])
594 ),
595 route
596 });
597 if (match.pathnameBase !== "/") {
598 matchedPathname = joinPaths([matchedPathname, match.pathnameBase]);
599 }
600 }
601 return matches;
602}
603function matchPath(pattern, pathname) {
604 if (typeof pattern === "string") {
605 pattern = { path: pattern, caseSensitive: false, end: true };
606 }
607 let [matcher, compiledParams] = compilePath(
608 pattern.path,
609 pattern.caseSensitive,
610 pattern.end
611 );
612 let match = pathname.match(matcher);
613 if (!match) return null;
614 let matchedPathname = match[0];
615 let pathnameBase = matchedPathname.replace(/(.)\/+$/, "$1");
616 let captureGroups = match.slice(1);
617 let params = compiledParams.reduce(
618 (memo, { paramName, isOptional }, index) => {
619 if (paramName === "*") {
620 let splatValue = captureGroups[index] || "";
621 pathnameBase = matchedPathname.slice(0, matchedPathname.length - splatValue.length).replace(/(.)\/+$/, "$1");
622 }
623 const value = captureGroups[index];
624 if (isOptional && !value) {
625 memo[paramName] = void 0;
626 } else {
627 memo[paramName] = (value || "").replace(/%2F/g, "/");
628 }
629 return memo;
630 },
631 {}
632 );
633 return {
634 params,
635 pathname: matchedPathname,
636 pathnameBase,
637 pattern
638 };
639}
640function compilePath(path, caseSensitive = false, end = true) {
641 warning(
642 path === "*" || !path.endsWith("*") || path.endsWith("/*"),
643 `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(/\*$/, "/*")}".`
644 );
645 let params = [];
646 let regexpSource = "^" + path.replace(/\/*\*?$/, "").replace(/^\/*/, "/").replace(/[\\.*+^${}|()[\]]/g, "\\$&").replace(
647 /\/:([\w-]+)(\?)?/g,
648 (match, paramName, isOptional, index, str) => {
649 params.push({ paramName, isOptional: isOptional != null });
650 if (isOptional) {
651 let nextChar = str.charAt(index + match.length);
652 if (nextChar && nextChar !== "/") {
653 return "/([^\\/]*)";
654 }
655 return "(?:/([^\\/]*))?";
656 }
657 return "/([^\\/]+)";
658 }
659 ).replace(/\/([\w-]+)\?(\/|$)/g, "(/$1)?$2");
660 if (path.endsWith("*")) {
661 params.push({ paramName: "*" });
662 regexpSource += path === "*" || path === "/*" ? "(.*)$" : "(?:\\/(.+)|\\/*)$";
663 } else if (end) {
664 regexpSource += "\\/*$";
665 } else if (path !== "" && path !== "/") {
666 regexpSource += "(?:(?=\\/|$))";
667 } else ;
668 let matcher = new RegExp(regexpSource, caseSensitive ? void 0 : "i");
669 return [matcher, params];
670}
671function decodePath(value) {
672 try {
673 return value.split("/").map((v) => decodeURIComponent(v).replace(/\//g, "%2F")).join("/");
674 } catch (error) {
675 warning(
676 false,
677 `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}).`
678 );
679 return value;
680 }
681}
682function stripBasename(pathname, basename) {
683 if (basename === "/") return pathname;
684 if (!pathname.toLowerCase().startsWith(basename.toLowerCase())) {
685 return null;
686 }
687 let startIndex = basename.endsWith("/") ? basename.length - 1 : basename.length;
688 let nextChar = pathname.charAt(startIndex);
689 if (nextChar && nextChar !== "/") {
690 return null;
691 }
692 return pathname.slice(startIndex) || "/";
693}
694function prependBasename({
695 basename,
696 pathname
697}) {
698 return pathname === "/" ? basename : joinPaths([basename, pathname]);
699}
700var ABSOLUTE_URL_REGEX = /^(?:[a-z][a-z0-9+.-]*:|\/\/)/i;
701var isAbsoluteUrl = (url) => ABSOLUTE_URL_REGEX.test(url);
702function resolvePath(to, fromPathname = "/") {
703 let {
704 pathname: toPathname,
705 search = "",
706 hash = ""
707 } = typeof to === "string" ? parsePath(to) : to;
708 let pathname;
709 if (toPathname) {
710 toPathname = toPathname.replace(/\/\/+/g, "/");
711 if (toPathname.startsWith("/")) {
712 pathname = resolvePathname(toPathname.substring(1), "/");
713 } else {
714 pathname = resolvePathname(toPathname, fromPathname);
715 }
716 } else {
717 pathname = fromPathname;
718 }
719 return {
720 pathname,
721 search: normalizeSearch(search),
722 hash: normalizeHash(hash)
723 };
724}
725function resolvePathname(relativePath, fromPathname) {
726 let segments = fromPathname.replace(/\/+$/, "").split("/");
727 let relativeSegments = relativePath.split("/");
728 relativeSegments.forEach((segment) => {
729 if (segment === "..") {
730 if (segments.length > 1) segments.pop();
731 } else if (segment !== ".") {
732 segments.push(segment);
733 }
734 });
735 return segments.length > 1 ? segments.join("/") : "/";
736}
737function getInvalidPathError(char, field, dest, path) {
738 return `Cannot include a '${char}' character in a manually specified \`to.${field}\` field [${JSON.stringify(
739 path
740 )}]. 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.`;
741}
742function getPathContributingMatches(matches) {
743 return matches.filter(
744 (match, index) => index === 0 || match.route.path && match.route.path.length > 0
745 );
746}
747function getResolveToMatches(matches) {
748 let pathMatches = getPathContributingMatches(matches);
749 return pathMatches.map(
750 (match, idx) => idx === pathMatches.length - 1 ? match.pathname : match.pathnameBase
751 );
752}
753function resolveTo(toArg, routePathnames, locationPathname, isPathRelative = false) {
754 let to;
755 if (typeof toArg === "string") {
756 to = parsePath(toArg);
757 } else {
758 to = { ...toArg };
759 invariant(
760 !to.pathname || !to.pathname.includes("?"),
761 getInvalidPathError("?", "pathname", "search", to)
762 );
763 invariant(
764 !to.pathname || !to.pathname.includes("#"),
765 getInvalidPathError("#", "pathname", "hash", to)
766 );
767 invariant(
768 !to.search || !to.search.includes("#"),
769 getInvalidPathError("#", "search", "hash", to)
770 );
771 }
772 let isEmptyPath = toArg === "" || to.pathname === "";
773 let toPathname = isEmptyPath ? "/" : to.pathname;
774 let from;
775 if (toPathname == null) {
776 from = locationPathname;
777 } else {
778 let routePathnameIndex = routePathnames.length - 1;
779 if (!isPathRelative && toPathname.startsWith("..")) {
780 let toSegments = toPathname.split("/");
781 while (toSegments[0] === "..") {
782 toSegments.shift();
783 routePathnameIndex -= 1;
784 }
785 to.pathname = toSegments.join("/");
786 }
787 from = routePathnameIndex >= 0 ? routePathnames[routePathnameIndex] : "/";
788 }
789 let path = resolvePath(to, from);
790 let hasExplicitTrailingSlash = toPathname && toPathname !== "/" && toPathname.endsWith("/");
791 let hasCurrentTrailingSlash = (isEmptyPath || toPathname === ".") && locationPathname.endsWith("/");
792 if (!path.pathname.endsWith("/") && (hasExplicitTrailingSlash || hasCurrentTrailingSlash)) {
793 path.pathname += "/";
794 }
795 return path;
796}
797var joinPaths = (paths) => paths.join("/").replace(/\/\/+/g, "/");
798var normalizePathname = (pathname) => pathname.replace(/\/+$/, "").replace(/^\/*/, "/");
799var normalizeSearch = (search) => !search || search === "?" ? "" : search.startsWith("?") ? search : "?" + search;
800var normalizeHash = (hash) => !hash || hash === "#" ? "" : hash.startsWith("#") ? hash : "#" + hash;
801var DataWithResponseInit = class {
802 constructor(data2, init) {
803 this.type = "DataWithResponseInit";
804 this.data = data2;
805 this.init = init || null;
806 }
807};
808function data(data2, init) {
809 return new DataWithResponseInit(
810 data2,
811 typeof init === "number" ? { status: init } : init
812 );
813}
814var redirect = (url, init = 302) => {
815 let responseInit = init;
816 if (typeof responseInit === "number") {
817 responseInit = { status: responseInit };
818 } else if (typeof responseInit.status === "undefined") {
819 responseInit.status = 302;
820 }
821 let headers = new Headers(responseInit.headers);
822 headers.set("Location", url);
823 return new Response(null, { ...responseInit, headers });
824};
825var redirectDocument = (url, init) => {
826 let response = redirect(url, init);
827 response.headers.set("X-Remix-Reload-Document", "true");
828 return response;
829};
830var replace = (url, init) => {
831 let response = redirect(url, init);
832 response.headers.set("X-Remix-Replace", "true");
833 return response;
834};
835var ErrorResponseImpl = class {
836 constructor(status, statusText, data2, internal = false) {
837 this.status = status;
838 this.statusText = statusText || "";
839 this.internal = internal;
840 if (data2 instanceof Error) {
841 this.data = data2.toString();
842 this.error = data2;
843 } else {
844 this.data = data2;
845 }
846 }
847};
848function isRouteErrorResponse(error) {
849 return error != null && typeof error.status === "number" && typeof error.statusText === "string" && typeof error.internal === "boolean" && "data" in error;
850}
851function getRoutePattern(matches) {
852 return matches.map((m) => m.route.path).filter(Boolean).join("/").replace(/\/\/*/g, "/") || "/";
853}
854
855// lib/router/router.ts
856var validMutationMethodsArr = [
857 "POST",
858 "PUT",
859 "PATCH",
860 "DELETE"
861];
862var validMutationMethods = new Set(
863 validMutationMethodsArr
864);
865var validRequestMethodsArr = [
866 "GET",
867 ...validMutationMethodsArr
868];
869var validRequestMethods = new Set(validRequestMethodsArr);
870var redirectStatusCodes = /* @__PURE__ */ new Set([301, 302, 303, 307, 308]);
871var defaultMapRouteProperties = (route) => ({
872 hasErrorBoundary: Boolean(route.hasErrorBoundary)
873});
874var ResetLoaderDataSymbol = Symbol("ResetLoaderData");
875function createStaticHandler(routes, opts) {
876 invariant(
877 routes.length > 0,
878 "You must provide a non-empty routes array to createStaticHandler"
879 );
880 let manifest = {};
881 let basename = (opts ? opts.basename : null) || "/";
882 let _mapRouteProperties = opts?.mapRouteProperties || defaultMapRouteProperties;
883 let mapRouteProperties = _mapRouteProperties;
884 ({
885 // unused in static handler
886 ...opts?.future
887 });
888 if (opts?.unstable_instrumentations) {
889 let instrumentations = opts.unstable_instrumentations;
890 mapRouteProperties = (route) => {
891 return {
892 ..._mapRouteProperties(route),
893 ...getRouteInstrumentationUpdates(
894 instrumentations.map((i) => i.route).filter(Boolean),
895 route
896 )
897 };
898 };
899 }
900 let dataRoutes = convertRoutesToDataRoutes(
901 routes,
902 mapRouteProperties,
903 void 0,
904 manifest
905 );
906 async function query(request, {
907 requestContext,
908 filterMatchesToLoad,
909 skipLoaderErrorBubbling,
910 skipRevalidation,
911 dataStrategy,
912 generateMiddlewareResponse,
913 unstable_normalizePath
914 } = {}) {
915 let normalizePath = unstable_normalizePath || defaultNormalizePath;
916 let method = request.method;
917 let location = createLocation("", normalizePath(request), null, "default");
918 let matches = matchRoutes(dataRoutes, location, basename);
919 requestContext = requestContext != null ? requestContext : new RouterContextProvider();
920 if (!isValidMethod(method) && method !== "HEAD") {
921 let error = getInternalRouterError(405, { method });
922 let { matches: methodNotAllowedMatches, route } = getShortCircuitMatches(dataRoutes);
923 let staticContext = {
924 basename,
925 location,
926 matches: methodNotAllowedMatches,
927 loaderData: {},
928 actionData: null,
929 errors: {
930 [route.id]: error
931 },
932 statusCode: error.status,
933 loaderHeaders: {},
934 actionHeaders: {}
935 };
936 return generateMiddlewareResponse ? generateMiddlewareResponse(() => Promise.resolve(staticContext)) : staticContext;
937 } else if (!matches) {
938 let error = getInternalRouterError(404, { pathname: location.pathname });
939 let { matches: notFoundMatches, route } = getShortCircuitMatches(dataRoutes);
940 let staticContext = {
941 basename,
942 location,
943 matches: notFoundMatches,
944 loaderData: {},
945 actionData: null,
946 errors: {
947 [route.id]: error
948 },
949 statusCode: error.status,
950 loaderHeaders: {},
951 actionHeaders: {}
952 };
953 return generateMiddlewareResponse ? generateMiddlewareResponse(() => Promise.resolve(staticContext)) : staticContext;
954 }
955 if (generateMiddlewareResponse) {
956 invariant(
957 requestContext instanceof RouterContextProvider,
958 "When using middleware in `staticHandler.query()`, any provided `requestContext` must be an instance of `RouterContextProvider`"
959 );
960 try {
961 await loadLazyMiddlewareForMatches(
962 matches,
963 manifest,
964 mapRouteProperties
965 );
966 let renderedStaticContext;
967 let response = await runServerMiddlewarePipeline(
968 {
969 request,
970 unstable_url: createDataFunctionUrl(request, location),
971 unstable_pattern: getRoutePattern(matches),
972 matches,
973 params: matches[0].params,
974 // If we're calling middleware then it must be enabled so we can cast
975 // this to the proper type knowing it's not an `AppLoadContext`
976 context: requestContext
977 },
978 async () => {
979 let res = await generateMiddlewareResponse(
980 async (revalidationRequest, opts2 = {}) => {
981 let result2 = await queryImpl(
982 revalidationRequest,
983 location,
984 matches,
985 requestContext,
986 dataStrategy || null,
987 skipLoaderErrorBubbling === true,
988 null,
989 "filterMatchesToLoad" in opts2 ? opts2.filterMatchesToLoad ?? null : filterMatchesToLoad ?? null,
990 skipRevalidation === true
991 );
992 if (isResponse(result2)) {
993 return result2;
994 }
995 renderedStaticContext = { location, basename, ...result2 };
996 return renderedStaticContext;
997 }
998 );
999 return res;
1000 },
1001 async (error, routeId) => {
1002 if (isRedirectResponse(error)) {
1003 return error;
1004 }
1005 if (isResponse(error)) {
1006 try {
1007 error = new ErrorResponseImpl(
1008 error.status,
1009 error.statusText,
1010 await parseResponseBody(error)
1011 );
1012 } catch (e) {
1013 error = e;
1014 }
1015 }
1016 if (isDataWithResponseInit(error)) {
1017 error = dataWithResponseInitToErrorResponse(error);
1018 }
1019 if (renderedStaticContext) {
1020 if (routeId in renderedStaticContext.loaderData) {
1021 renderedStaticContext.loaderData[routeId] = void 0;
1022 }
1023 let staticContext = getStaticContextFromError(
1024 dataRoutes,
1025 renderedStaticContext,
1026 error,
1027 skipLoaderErrorBubbling ? routeId : findNearestBoundary(matches, routeId).route.id
1028 );
1029 return generateMiddlewareResponse(
1030 () => Promise.resolve(staticContext)
1031 );
1032 } else {
1033 let boundaryRouteId = skipLoaderErrorBubbling ? routeId : findNearestBoundary(
1034 matches,
1035 matches.find(
1036 (m) => m.route.id === routeId || m.route.loader
1037 )?.route.id || routeId
1038 ).route.id;
1039 let staticContext = {
1040 matches,
1041 location,
1042 basename,
1043 loaderData: {},
1044 actionData: null,
1045 errors: {
1046 [boundaryRouteId]: error
1047 },
1048 statusCode: isRouteErrorResponse(error) ? error.status : 500,
1049 actionHeaders: {},
1050 loaderHeaders: {}
1051 };
1052 return generateMiddlewareResponse(
1053 () => Promise.resolve(staticContext)
1054 );
1055 }
1056 }
1057 );
1058 invariant(isResponse(response), "Expected a response in query()");
1059 return response;
1060 } catch (e) {
1061 if (isResponse(e)) {
1062 return e;
1063 }
1064 throw e;
1065 }
1066 }
1067 let result = await queryImpl(
1068 request,
1069 location,
1070 matches,
1071 requestContext,
1072 dataStrategy || null,
1073 skipLoaderErrorBubbling === true,
1074 null,
1075 filterMatchesToLoad || null,
1076 skipRevalidation === true
1077 );
1078 if (isResponse(result)) {
1079 return result;
1080 }
1081 return { location, basename, ...result };
1082 }
1083 async function queryRoute(request, {
1084 routeId,
1085 requestContext,
1086 dataStrategy,
1087 generateMiddlewareResponse,
1088 unstable_normalizePath
1089 } = {}) {
1090 let normalizePath = unstable_normalizePath || defaultNormalizePath;
1091 let method = request.method;
1092 let location = createLocation("", normalizePath(request), null, "default");
1093 let matches = matchRoutes(dataRoutes, location, basename);
1094 requestContext = requestContext != null ? requestContext : new RouterContextProvider();
1095 if (!isValidMethod(method) && method !== "HEAD" && method !== "OPTIONS") {
1096 throw getInternalRouterError(405, { method });
1097 } else if (!matches) {
1098 throw getInternalRouterError(404, { pathname: location.pathname });
1099 }
1100 let match = routeId ? matches.find((m) => m.route.id === routeId) : getTargetMatch(matches, location);
1101 if (routeId && !match) {
1102 throw getInternalRouterError(403, {
1103 pathname: location.pathname,
1104 routeId
1105 });
1106 } else if (!match) {
1107 throw getInternalRouterError(404, { pathname: location.pathname });
1108 }
1109 if (generateMiddlewareResponse) {
1110 invariant(
1111 requestContext instanceof RouterContextProvider,
1112 "When using middleware in `staticHandler.queryRoute()`, any provided `requestContext` must be an instance of `RouterContextProvider`"
1113 );
1114 await loadLazyMiddlewareForMatches(matches, manifest, mapRouteProperties);
1115 let response = await runServerMiddlewarePipeline(
1116 {
1117 request,
1118 unstable_url: createDataFunctionUrl(request, location),
1119 unstable_pattern: getRoutePattern(matches),
1120 matches,
1121 params: matches[0].params,
1122 // If we're calling middleware then it must be enabled so we can cast
1123 // this to the proper type knowing it's not an `AppLoadContext`
1124 context: requestContext
1125 },
1126 async () => {
1127 let res = await generateMiddlewareResponse(
1128 async (innerRequest) => {
1129 let result2 = await queryImpl(
1130 innerRequest,
1131 location,
1132 matches,
1133 requestContext,
1134 dataStrategy || null,
1135 false,
1136 match,
1137 null,
1138 false
1139 );
1140 let processed = handleQueryResult(result2);
1141 return isResponse(processed) ? processed : typeof processed === "string" ? new Response(processed) : Response.json(processed);
1142 }
1143 );
1144 return res;
1145 },
1146 (error) => {
1147 if (isDataWithResponseInit(error)) {
1148 return Promise.resolve(dataWithResponseInitToResponse(error));
1149 }
1150 if (isResponse(error)) {
1151 return Promise.resolve(error);
1152 }
1153 throw error;
1154 }
1155 );
1156 return response;
1157 }
1158 let result = await queryImpl(
1159 request,
1160 location,
1161 matches,
1162 requestContext,
1163 dataStrategy || null,
1164 false,
1165 match,
1166 null,
1167 false
1168 );
1169 return handleQueryResult(result);
1170 function handleQueryResult(result2) {
1171 if (isResponse(result2)) {
1172 return result2;
1173 }
1174 let error = result2.errors ? Object.values(result2.errors)[0] : void 0;
1175 if (error !== void 0) {
1176 throw error;
1177 }
1178 if (result2.actionData) {
1179 return Object.values(result2.actionData)[0];
1180 }
1181 if (result2.loaderData) {
1182 return Object.values(result2.loaderData)[0];
1183 }
1184 return void 0;
1185 }
1186 }
1187 async function queryImpl(request, location, matches, requestContext, dataStrategy, skipLoaderErrorBubbling, routeMatch, filterMatchesToLoad, skipRevalidation) {
1188 invariant(
1189 request.signal,
1190 "query()/queryRoute() requests must contain an AbortController signal"
1191 );
1192 try {
1193 if (isMutationMethod(request.method)) {
1194 let result2 = await submit(
1195 request,
1196 location,
1197 matches,
1198 routeMatch || getTargetMatch(matches, location),
1199 requestContext,
1200 dataStrategy,
1201 skipLoaderErrorBubbling,
1202 routeMatch != null,
1203 filterMatchesToLoad,
1204 skipRevalidation
1205 );
1206 return result2;
1207 }
1208 let result = await loadRouteData(
1209 request,
1210 location,
1211 matches,
1212 requestContext,
1213 dataStrategy,
1214 skipLoaderErrorBubbling,
1215 routeMatch,
1216 filterMatchesToLoad
1217 );
1218 return isResponse(result) ? result : {
1219 ...result,
1220 actionData: null,
1221 actionHeaders: {}
1222 };
1223 } catch (e) {
1224 if (isDataStrategyResult(e) && isResponse(e.result)) {
1225 if (e.type === "error" /* error */) {
1226 throw e.result;
1227 }
1228 return e.result;
1229 }
1230 if (isRedirectResponse(e)) {
1231 return e;
1232 }
1233 throw e;
1234 }
1235 }
1236 async function submit(request, location, matches, actionMatch, requestContext, dataStrategy, skipLoaderErrorBubbling, isRouteRequest, filterMatchesToLoad, skipRevalidation) {
1237 let result;
1238 if (!actionMatch.route.action && !actionMatch.route.lazy) {
1239 let error = getInternalRouterError(405, {
1240 method: request.method,
1241 pathname: new URL(request.url).pathname,
1242 routeId: actionMatch.route.id
1243 });
1244 if (isRouteRequest) {
1245 throw error;
1246 }
1247 result = {
1248 type: "error" /* error */,
1249 error
1250 };
1251 } else {
1252 let dsMatches = getTargetedDataStrategyMatches(
1253 mapRouteProperties,
1254 manifest,
1255 request,
1256 location,
1257 matches,
1258 actionMatch,
1259 [],
1260 requestContext
1261 );
1262 let results = await callDataStrategy(
1263 request,
1264 location,
1265 dsMatches,
1266 isRouteRequest,
1267 requestContext,
1268 dataStrategy
1269 );
1270 result = results[actionMatch.route.id];
1271 if (request.signal.aborted) {
1272 throwStaticHandlerAbortedError(request, isRouteRequest);
1273 }
1274 }
1275 if (isRedirectResult(result)) {
1276 throw new Response(null, {
1277 status: result.response.status,
1278 headers: {
1279 Location: result.response.headers.get("Location")
1280 }
1281 });
1282 }
1283 if (isRouteRequest) {
1284 if (isErrorResult(result)) {
1285 throw result.error;
1286 }
1287 return {
1288 matches: [actionMatch],
1289 loaderData: {},
1290 actionData: { [actionMatch.route.id]: result.data },
1291 errors: null,
1292 // Note: statusCode + headers are unused here since queryRoute will
1293 // return the raw Response or value
1294 statusCode: 200,
1295 loaderHeaders: {},
1296 actionHeaders: {}
1297 };
1298 }
1299 if (skipRevalidation) {
1300 if (isErrorResult(result)) {
1301 let boundaryMatch = skipLoaderErrorBubbling ? actionMatch : findNearestBoundary(matches, actionMatch.route.id);
1302 return {
1303 statusCode: isRouteErrorResponse(result.error) ? result.error.status : result.statusCode != null ? result.statusCode : 500,
1304 actionData: null,
1305 actionHeaders: {
1306 ...result.headers ? { [actionMatch.route.id]: result.headers } : {}
1307 },
1308 matches,
1309 loaderData: {},
1310 errors: {
1311 [boundaryMatch.route.id]: result.error
1312 },
1313 loaderHeaders: {}
1314 };
1315 } else {
1316 return {
1317 actionData: {
1318 [actionMatch.route.id]: result.data
1319 },
1320 actionHeaders: result.headers ? { [actionMatch.route.id]: result.headers } : {},
1321 matches,
1322 loaderData: {},
1323 errors: null,
1324 statusCode: result.statusCode || 200,
1325 loaderHeaders: {}
1326 };
1327 }
1328 }
1329 let loaderRequest = new Request(request.url, {
1330 headers: request.headers,
1331 redirect: request.redirect,
1332 signal: request.signal
1333 });
1334 if (isErrorResult(result)) {
1335 let boundaryMatch = skipLoaderErrorBubbling ? actionMatch : findNearestBoundary(matches, actionMatch.route.id);
1336 let handlerContext2 = await loadRouteData(
1337 loaderRequest,
1338 location,
1339 matches,
1340 requestContext,
1341 dataStrategy,
1342 skipLoaderErrorBubbling,
1343 null,
1344 filterMatchesToLoad,
1345 [boundaryMatch.route.id, result]
1346 );
1347 return {
1348 ...handlerContext2,
1349 statusCode: isRouteErrorResponse(result.error) ? result.error.status : result.statusCode != null ? result.statusCode : 500,
1350 actionData: null,
1351 actionHeaders: {
1352 ...result.headers ? { [actionMatch.route.id]: result.headers } : {}
1353 }
1354 };
1355 }
1356 let handlerContext = await loadRouteData(
1357 loaderRequest,
1358 location,
1359 matches,
1360 requestContext,
1361 dataStrategy,
1362 skipLoaderErrorBubbling,
1363 null,
1364 filterMatchesToLoad
1365 );
1366 return {
1367 ...handlerContext,
1368 actionData: {
1369 [actionMatch.route.id]: result.data
1370 },
1371 // action status codes take precedence over loader status codes
1372 ...result.statusCode ? { statusCode: result.statusCode } : {},
1373 actionHeaders: result.headers ? { [actionMatch.route.id]: result.headers } : {}
1374 };
1375 }
1376 async function loadRouteData(request, location, matches, requestContext, dataStrategy, skipLoaderErrorBubbling, routeMatch, filterMatchesToLoad, pendingActionResult) {
1377 let isRouteRequest = routeMatch != null;
1378 if (isRouteRequest && !routeMatch?.route.loader && !routeMatch?.route.lazy) {
1379 throw getInternalRouterError(400, {
1380 method: request.method,
1381 pathname: new URL(request.url).pathname,
1382 routeId: routeMatch?.route.id
1383 });
1384 }
1385 let dsMatches;
1386 if (routeMatch) {
1387 dsMatches = getTargetedDataStrategyMatches(
1388 mapRouteProperties,
1389 manifest,
1390 request,
1391 location,
1392 matches,
1393 routeMatch,
1394 [],
1395 requestContext
1396 );
1397 } else {
1398 let maxIdx = pendingActionResult && isErrorResult(pendingActionResult[1]) ? (
1399 // Up to but not including the boundary
1400 matches.findIndex((m) => m.route.id === pendingActionResult[0]) - 1
1401 ) : void 0;
1402 let pattern = getRoutePattern(matches);
1403 dsMatches = matches.map((match, index) => {
1404 if (maxIdx != null && index > maxIdx) {
1405 return getDataStrategyMatch(
1406 mapRouteProperties,
1407 manifest,
1408 request,
1409 location,
1410 pattern,
1411 match,
1412 [],
1413 requestContext,
1414 false
1415 );
1416 }
1417 return getDataStrategyMatch(
1418 mapRouteProperties,
1419 manifest,
1420 request,
1421 location,
1422 pattern,
1423 match,
1424 [],
1425 requestContext,
1426 (match.route.loader || match.route.lazy) != null && (!filterMatchesToLoad || filterMatchesToLoad(match))
1427 );
1428 });
1429 }
1430 if (!dataStrategy && !dsMatches.some((m) => m.shouldLoad)) {
1431 return {
1432 matches,
1433 loaderData: {},
1434 errors: pendingActionResult && isErrorResult(pendingActionResult[1]) ? {
1435 [pendingActionResult[0]]: pendingActionResult[1].error
1436 } : null,
1437 statusCode: 200,
1438 loaderHeaders: {}
1439 };
1440 }
1441 let results = await callDataStrategy(
1442 request,
1443 location,
1444 dsMatches,
1445 isRouteRequest,
1446 requestContext,
1447 dataStrategy
1448 );
1449 if (request.signal.aborted) {
1450 throwStaticHandlerAbortedError(request, isRouteRequest);
1451 }
1452 let handlerContext = processRouteLoaderData(
1453 matches,
1454 results,
1455 pendingActionResult,
1456 true,
1457 skipLoaderErrorBubbling
1458 );
1459 return {
1460 ...handlerContext,
1461 matches
1462 };
1463 }
1464 async function callDataStrategy(request, location, matches, isRouteRequest, requestContext, dataStrategy) {
1465 let results = await callDataStrategyImpl(
1466 dataStrategy || defaultDataStrategy,
1467 request,
1468 location,
1469 matches,
1470 null,
1471 requestContext);
1472 let dataResults = {};
1473 await Promise.all(
1474 matches.map(async (match) => {
1475 if (!(match.route.id in results)) {
1476 return;
1477 }
1478 let result = results[match.route.id];
1479 if (isRedirectDataStrategyResult(result)) {
1480 let response = result.result;
1481 throw normalizeRelativeRoutingRedirectResponse(
1482 response,
1483 request,
1484 match.route.id,
1485 matches,
1486 basename
1487 );
1488 }
1489 if (isRouteRequest) {
1490 if (isResponse(result.result)) {
1491 throw result;
1492 } else if (isDataWithResponseInit(result.result)) {
1493 throw dataWithResponseInitToResponse(result.result);
1494 }
1495 }
1496 dataResults[match.route.id] = await convertDataStrategyResultToDataResult(result);
1497 })
1498 );
1499 return dataResults;
1500 }
1501 return {
1502 dataRoutes,
1503 query,
1504 queryRoute
1505 };
1506}
1507function getStaticContextFromError(routes, handlerContext, error, boundaryId) {
1508 let errorBoundaryId = boundaryId || handlerContext._deepestRenderedBoundaryId || routes[0].id;
1509 return {
1510 ...handlerContext,
1511 statusCode: isRouteErrorResponse(error) ? error.status : 500,
1512 errors: {
1513 [errorBoundaryId]: error
1514 }
1515 };
1516}
1517function throwStaticHandlerAbortedError(request, isRouteRequest) {
1518 if (request.signal.reason !== void 0) {
1519 throw request.signal.reason;
1520 }
1521 let method = isRouteRequest ? "queryRoute" : "query";
1522 throw new Error(
1523 `${method}() call aborted without an \`AbortSignal.reason\`: ${request.method} ${request.url}`
1524 );
1525}
1526function defaultNormalizePath(request) {
1527 let url = new URL(request.url);
1528 return {
1529 pathname: url.pathname,
1530 search: url.search,
1531 hash: url.hash
1532 };
1533}
1534function normalizeTo(location, matches, basename, to, fromRouteId, relative) {
1535 let contextualMatches;
1536 let activeRouteMatch;
1537 {
1538 contextualMatches = matches;
1539 activeRouteMatch = matches[matches.length - 1];
1540 }
1541 let path = resolveTo(
1542 to ? to : ".",
1543 getResolveToMatches(contextualMatches),
1544 stripBasename(location.pathname, basename) || location.pathname,
1545 relative === "path"
1546 );
1547 if (to == null) {
1548 path.search = location.search;
1549 path.hash = location.hash;
1550 }
1551 if ((to == null || to === "" || to === ".") && activeRouteMatch) {
1552 let nakedIndex = hasNakedIndexQuery(path.search);
1553 if (activeRouteMatch.route.index && !nakedIndex) {
1554 path.search = path.search ? path.search.replace(/^\?/, "?index&") : "?index";
1555 } else if (!activeRouteMatch.route.index && nakedIndex) {
1556 let params = new URLSearchParams(path.search);
1557 let indexValues = params.getAll("index");
1558 params.delete("index");
1559 indexValues.filter((v) => v).forEach((v) => params.append("index", v));
1560 let qs = params.toString();
1561 path.search = qs ? `?${qs}` : "";
1562 }
1563 }
1564 if (basename !== "/") {
1565 path.pathname = prependBasename({ basename, pathname: path.pathname });
1566 }
1567 return createPath(path);
1568}
1569function shouldRevalidateLoader(loaderMatch, arg) {
1570 if (loaderMatch.route.shouldRevalidate) {
1571 let routeChoice = loaderMatch.route.shouldRevalidate(arg);
1572 if (typeof routeChoice === "boolean") {
1573 return routeChoice;
1574 }
1575 }
1576 return arg.defaultShouldRevalidate;
1577}
1578var lazyRoutePropertyCache = /* @__PURE__ */ new WeakMap();
1579var loadLazyRouteProperty = ({
1580 key,
1581 route,
1582 manifest,
1583 mapRouteProperties
1584}) => {
1585 let routeToUpdate = manifest[route.id];
1586 invariant(routeToUpdate, "No route found in manifest");
1587 if (!routeToUpdate.lazy || typeof routeToUpdate.lazy !== "object") {
1588 return;
1589 }
1590 let lazyFn = routeToUpdate.lazy[key];
1591 if (!lazyFn) {
1592 return;
1593 }
1594 let cache2 = lazyRoutePropertyCache.get(routeToUpdate);
1595 if (!cache2) {
1596 cache2 = {};
1597 lazyRoutePropertyCache.set(routeToUpdate, cache2);
1598 }
1599 let cachedPromise = cache2[key];
1600 if (cachedPromise) {
1601 return cachedPromise;
1602 }
1603 let propertyPromise = (async () => {
1604 let isUnsupported = isUnsupportedLazyRouteObjectKey(key);
1605 let staticRouteValue = routeToUpdate[key];
1606 let isStaticallyDefined = staticRouteValue !== void 0 && key !== "hasErrorBoundary";
1607 if (isUnsupported) {
1608 warning(
1609 !isUnsupported,
1610 "Route property " + key + " is not a supported lazy route property. This property will be ignored."
1611 );
1612 cache2[key] = Promise.resolve();
1613 } else if (isStaticallyDefined) {
1614 warning(
1615 false,
1616 `Route "${routeToUpdate.id}" has a static property "${key}" defined. The lazy property will be ignored.`
1617 );
1618 } else {
1619 let value = await lazyFn();
1620 if (value != null) {
1621 Object.assign(routeToUpdate, { [key]: value });
1622 Object.assign(routeToUpdate, mapRouteProperties(routeToUpdate));
1623 }
1624 }
1625 if (typeof routeToUpdate.lazy === "object") {
1626 routeToUpdate.lazy[key] = void 0;
1627 if (Object.values(routeToUpdate.lazy).every((value) => value === void 0)) {
1628 routeToUpdate.lazy = void 0;
1629 }
1630 }
1631 })();
1632 cache2[key] = propertyPromise;
1633 return propertyPromise;
1634};
1635var lazyRouteFunctionCache = /* @__PURE__ */ new WeakMap();
1636function loadLazyRoute(route, type, manifest, mapRouteProperties, lazyRoutePropertiesToSkip) {
1637 let routeToUpdate = manifest[route.id];
1638 invariant(routeToUpdate, "No route found in manifest");
1639 if (!route.lazy) {
1640 return {
1641 lazyRoutePromise: void 0,
1642 lazyHandlerPromise: void 0
1643 };
1644 }
1645 if (typeof route.lazy === "function") {
1646 let cachedPromise = lazyRouteFunctionCache.get(routeToUpdate);
1647 if (cachedPromise) {
1648 return {
1649 lazyRoutePromise: cachedPromise,
1650 lazyHandlerPromise: cachedPromise
1651 };
1652 }
1653 let lazyRoutePromise2 = (async () => {
1654 invariant(
1655 typeof route.lazy === "function",
1656 "No lazy route function found"
1657 );
1658 let lazyRoute = await route.lazy();
1659 let routeUpdates = {};
1660 for (let lazyRouteProperty in lazyRoute) {
1661 let lazyValue = lazyRoute[lazyRouteProperty];
1662 if (lazyValue === void 0) {
1663 continue;
1664 }
1665 let isUnsupported = isUnsupportedLazyRouteFunctionKey(lazyRouteProperty);
1666 let staticRouteValue = routeToUpdate[lazyRouteProperty];
1667 let isStaticallyDefined = staticRouteValue !== void 0 && // This property isn't static since it should always be updated based
1668 // on the route updates
1669 lazyRouteProperty !== "hasErrorBoundary";
1670 if (isUnsupported) {
1671 warning(
1672 !isUnsupported,
1673 "Route property " + lazyRouteProperty + " is not a supported property to be returned from a lazy route function. This property will be ignored."
1674 );
1675 } else if (isStaticallyDefined) {
1676 warning(
1677 !isStaticallyDefined,
1678 `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.`
1679 );
1680 } else {
1681 routeUpdates[lazyRouteProperty] = lazyValue;
1682 }
1683 }
1684 Object.assign(routeToUpdate, routeUpdates);
1685 Object.assign(routeToUpdate, {
1686 // To keep things framework agnostic, we use the provided `mapRouteProperties`
1687 // function to set the framework-aware properties (`element`/`hasErrorBoundary`)
1688 // since the logic will differ between frameworks.
1689 ...mapRouteProperties(routeToUpdate),
1690 lazy: void 0
1691 });
1692 })();
1693 lazyRouteFunctionCache.set(routeToUpdate, lazyRoutePromise2);
1694 lazyRoutePromise2.catch(() => {
1695 });
1696 return {
1697 lazyRoutePromise: lazyRoutePromise2,
1698 lazyHandlerPromise: lazyRoutePromise2
1699 };
1700 }
1701 let lazyKeys = Object.keys(route.lazy);
1702 let lazyPropertyPromises = [];
1703 let lazyHandlerPromise = void 0;
1704 for (let key of lazyKeys) {
1705 if (lazyRoutePropertiesToSkip && lazyRoutePropertiesToSkip.includes(key)) {
1706 continue;
1707 }
1708 let promise = loadLazyRouteProperty({
1709 key,
1710 route,
1711 manifest,
1712 mapRouteProperties
1713 });
1714 if (promise) {
1715 lazyPropertyPromises.push(promise);
1716 if (key === type) {
1717 lazyHandlerPromise = promise;
1718 }
1719 }
1720 }
1721 let lazyRoutePromise = lazyPropertyPromises.length > 0 ? Promise.all(lazyPropertyPromises).then(() => {
1722 }) : void 0;
1723 lazyRoutePromise?.catch(() => {
1724 });
1725 lazyHandlerPromise?.catch(() => {
1726 });
1727 return {
1728 lazyRoutePromise,
1729 lazyHandlerPromise
1730 };
1731}
1732function isNonNullable(value) {
1733 return value !== void 0;
1734}
1735function loadLazyMiddlewareForMatches(matches, manifest, mapRouteProperties) {
1736 let promises = matches.map(({ route }) => {
1737 if (typeof route.lazy !== "object" || !route.lazy.middleware) {
1738 return void 0;
1739 }
1740 return loadLazyRouteProperty({
1741 key: "middleware",
1742 route,
1743 manifest,
1744 mapRouteProperties
1745 });
1746 }).filter(isNonNullable);
1747 return promises.length > 0 ? Promise.all(promises) : void 0;
1748}
1749async function defaultDataStrategy(args) {
1750 let matchesToLoad = args.matches.filter((m) => m.shouldLoad);
1751 let keyedResults = {};
1752 let results = await Promise.all(matchesToLoad.map((m) => m.resolve()));
1753 results.forEach((result, i) => {
1754 keyedResults[matchesToLoad[i].route.id] = result;
1755 });
1756 return keyedResults;
1757}
1758function runServerMiddlewarePipeline(args, handler, errorHandler) {
1759 return runMiddlewarePipeline(
1760 args,
1761 handler,
1762 processResult,
1763 isResponse,
1764 errorHandler
1765 );
1766 function processResult(result) {
1767 return isDataWithResponseInit(result) ? dataWithResponseInitToResponse(result) : result;
1768 }
1769}
1770async function runMiddlewarePipeline(args, handler, processResult, isResult, errorHandler) {
1771 let { matches, ...dataFnArgs } = args;
1772 let tuples = matches.flatMap(
1773 (m) => m.route.middleware ? m.route.middleware.map((fn) => [m.route.id, fn]) : []
1774 );
1775 let result = await callRouteMiddleware(
1776 dataFnArgs,
1777 tuples,
1778 handler,
1779 processResult,
1780 isResult,
1781 errorHandler
1782 );
1783 return result;
1784}
1785async function callRouteMiddleware(args, middlewares, handler, processResult, isResult, errorHandler, idx = 0) {
1786 let { request } = args;
1787 if (request.signal.aborted) {
1788 throw request.signal.reason ?? new Error(`Request aborted: ${request.method} ${request.url}`);
1789 }
1790 let tuple = middlewares[idx];
1791 if (!tuple) {
1792 let result = await handler();
1793 return result;
1794 }
1795 let [routeId, middleware] = tuple;
1796 let nextResult;
1797 let next = async () => {
1798 if (nextResult) {
1799 throw new Error("You may only call `next()` once per middleware");
1800 }
1801 try {
1802 let result = await callRouteMiddleware(
1803 args,
1804 middlewares,
1805 handler,
1806 processResult,
1807 isResult,
1808 errorHandler,
1809 idx + 1
1810 );
1811 nextResult = { value: result };
1812 return nextResult.value;
1813 } catch (error) {
1814 nextResult = { value: await errorHandler(error, routeId, nextResult) };
1815 return nextResult.value;
1816 }
1817 };
1818 try {
1819 let value = await middleware(args, next);
1820 let result = value != null ? processResult(value) : void 0;
1821 if (isResult(result)) {
1822 return result;
1823 } else if (nextResult) {
1824 return result ?? nextResult.value;
1825 } else {
1826 nextResult = { value: await next() };
1827 return nextResult.value;
1828 }
1829 } catch (error) {
1830 let response = await errorHandler(error, routeId, nextResult);
1831 return response;
1832 }
1833}
1834function getDataStrategyMatchLazyPromises(mapRouteProperties, manifest, request, match, lazyRoutePropertiesToSkip) {
1835 let lazyMiddlewarePromise = loadLazyRouteProperty({
1836 key: "middleware",
1837 route: match.route,
1838 manifest,
1839 mapRouteProperties
1840 });
1841 let lazyRoutePromises = loadLazyRoute(
1842 match.route,
1843 isMutationMethod(request.method) ? "action" : "loader",
1844 manifest,
1845 mapRouteProperties,
1846 lazyRoutePropertiesToSkip
1847 );
1848 return {
1849 middleware: lazyMiddlewarePromise,
1850 route: lazyRoutePromises.lazyRoutePromise,
1851 handler: lazyRoutePromises.lazyHandlerPromise
1852 };
1853}
1854function getDataStrategyMatch(mapRouteProperties, manifest, request, path, unstable_pattern, match, lazyRoutePropertiesToSkip, scopedContext, shouldLoad, shouldRevalidateArgs = null, callSiteDefaultShouldRevalidate) {
1855 let isUsingNewApi = false;
1856 let _lazyPromises = getDataStrategyMatchLazyPromises(
1857 mapRouteProperties,
1858 manifest,
1859 request,
1860 match,
1861 lazyRoutePropertiesToSkip
1862 );
1863 return {
1864 ...match,
1865 _lazyPromises,
1866 shouldLoad,
1867 shouldRevalidateArgs,
1868 shouldCallHandler(defaultShouldRevalidate) {
1869 isUsingNewApi = true;
1870 if (!shouldRevalidateArgs) {
1871 return shouldLoad;
1872 }
1873 if (typeof defaultShouldRevalidate === "boolean") {
1874 return shouldRevalidateLoader(match, {
1875 ...shouldRevalidateArgs,
1876 defaultShouldRevalidate
1877 });
1878 }
1879 return shouldRevalidateLoader(match, shouldRevalidateArgs);
1880 },
1881 resolve(handlerOverride) {
1882 let { lazy, loader, middleware } = match.route;
1883 let callHandler = isUsingNewApi || shouldLoad || handlerOverride && !isMutationMethod(request.method) && (lazy || loader);
1884 let isMiddlewareOnlyRoute = middleware && middleware.length > 0 && !loader && !lazy;
1885 if (callHandler && (isMutationMethod(request.method) || !isMiddlewareOnlyRoute)) {
1886 return callLoaderOrAction({
1887 request,
1888 path,
1889 unstable_pattern,
1890 match,
1891 lazyHandlerPromise: _lazyPromises?.handler,
1892 lazyRoutePromise: _lazyPromises?.route,
1893 handlerOverride,
1894 scopedContext
1895 });
1896 }
1897 return Promise.resolve({ type: "data" /* data */, result: void 0 });
1898 }
1899 };
1900}
1901function getTargetedDataStrategyMatches(mapRouteProperties, manifest, request, path, matches, targetMatch, lazyRoutePropertiesToSkip, scopedContext, shouldRevalidateArgs = null) {
1902 return matches.map((match) => {
1903 if (match.route.id !== targetMatch.route.id) {
1904 return {
1905 ...match,
1906 shouldLoad: false,
1907 shouldRevalidateArgs,
1908 shouldCallHandler: () => false,
1909 _lazyPromises: getDataStrategyMatchLazyPromises(
1910 mapRouteProperties,
1911 manifest,
1912 request,
1913 match,
1914 lazyRoutePropertiesToSkip
1915 ),
1916 resolve: () => Promise.resolve({ type: "data", result: void 0 })
1917 };
1918 }
1919 return getDataStrategyMatch(
1920 mapRouteProperties,
1921 manifest,
1922 request,
1923 path,
1924 getRoutePattern(matches),
1925 match,
1926 lazyRoutePropertiesToSkip,
1927 scopedContext,
1928 true,
1929 shouldRevalidateArgs
1930 );
1931 });
1932}
1933async function callDataStrategyImpl(dataStrategyImpl, request, path, matches, fetcherKey, scopedContext, isStaticHandler) {
1934 if (matches.some((m) => m._lazyPromises?.middleware)) {
1935 await Promise.all(matches.map((m) => m._lazyPromises?.middleware));
1936 }
1937 let dataStrategyArgs = {
1938 request,
1939 unstable_url: createDataFunctionUrl(request, path),
1940 unstable_pattern: getRoutePattern(matches),
1941 params: matches[0].params,
1942 context: scopedContext,
1943 matches
1944 };
1945 let runClientMiddleware = () => {
1946 throw new Error(
1947 "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`"
1948 );
1949 } ;
1950 let results = await dataStrategyImpl({
1951 ...dataStrategyArgs,
1952 fetcherKey,
1953 runClientMiddleware
1954 });
1955 try {
1956 await Promise.all(
1957 matches.flatMap((m) => [
1958 m._lazyPromises?.handler,
1959 m._lazyPromises?.route
1960 ])
1961 );
1962 } catch (e) {
1963 }
1964 return results;
1965}
1966async function callLoaderOrAction({
1967 request,
1968 path,
1969 unstable_pattern,
1970 match,
1971 lazyHandlerPromise,
1972 lazyRoutePromise,
1973 handlerOverride,
1974 scopedContext
1975}) {
1976 let result;
1977 let onReject;
1978 let isAction = isMutationMethod(request.method);
1979 let type = isAction ? "action" : "loader";
1980 let runHandler = (handler) => {
1981 let reject;
1982 let abortPromise = new Promise((_, r) => reject = r);
1983 onReject = () => reject();
1984 request.signal.addEventListener("abort", onReject);
1985 let actualHandler = (ctx) => {
1986 if (typeof handler !== "function") {
1987 return Promise.reject(
1988 new Error(
1989 `You cannot call the handler for a route which defines a boolean "${type}" [routeId: ${match.route.id}]`
1990 )
1991 );
1992 }
1993 return handler(
1994 {
1995 request,
1996 unstable_url: createDataFunctionUrl(request, path),
1997 unstable_pattern,
1998 params: match.params,
1999 context: scopedContext
2000 },
2001 ...ctx !== void 0 ? [ctx] : []
2002 );
2003 };
2004 let handlerPromise = (async () => {
2005 try {
2006 let val = await (handlerOverride ? handlerOverride((ctx) => actualHandler(ctx)) : actualHandler());
2007 return { type: "data", result: val };
2008 } catch (e) {
2009 return { type: "error", result: e };
2010 }
2011 })();
2012 return Promise.race([handlerPromise, abortPromise]);
2013 };
2014 try {
2015 let handler = isAction ? match.route.action : match.route.loader;
2016 if (lazyHandlerPromise || lazyRoutePromise) {
2017 if (handler) {
2018 let handlerError;
2019 let [value] = await Promise.all([
2020 // If the handler throws, don't let it immediately bubble out,
2021 // since we need to let the lazy() execution finish so we know if this
2022 // route has a boundary that can handle the error
2023 runHandler(handler).catch((e) => {
2024 handlerError = e;
2025 }),
2026 // Ensure all lazy route promises are resolved before continuing
2027 lazyHandlerPromise,
2028 lazyRoutePromise
2029 ]);
2030 if (handlerError !== void 0) {
2031 throw handlerError;
2032 }
2033 result = value;
2034 } else {
2035 await lazyHandlerPromise;
2036 let handler2 = isAction ? match.route.action : match.route.loader;
2037 if (handler2) {
2038 [result] = await Promise.all([runHandler(handler2), lazyRoutePromise]);
2039 } else if (type === "action") {
2040 let url = new URL(request.url);
2041 let pathname = url.pathname + url.search;
2042 throw getInternalRouterError(405, {
2043 method: request.method,
2044 pathname,
2045 routeId: match.route.id
2046 });
2047 } else {
2048 return { type: "data" /* data */, result: void 0 };
2049 }
2050 }
2051 } else if (!handler) {
2052 let url = new URL(request.url);
2053 let pathname = url.pathname + url.search;
2054 throw getInternalRouterError(404, {
2055 pathname
2056 });
2057 } else {
2058 result = await runHandler(handler);
2059 }
2060 } catch (e) {
2061 return { type: "error" /* error */, result: e };
2062 } finally {
2063 if (onReject) {
2064 request.signal.removeEventListener("abort", onReject);
2065 }
2066 }
2067 return result;
2068}
2069async function parseResponseBody(response) {
2070 let contentType = response.headers.get("Content-Type");
2071 if (contentType && /\bapplication\/json\b/.test(contentType)) {
2072 return response.body == null ? null : response.json();
2073 }
2074 return response.text();
2075}
2076async function convertDataStrategyResultToDataResult(dataStrategyResult) {
2077 let { result, type } = dataStrategyResult;
2078 if (isResponse(result)) {
2079 let data2;
2080 try {
2081 data2 = await parseResponseBody(result);
2082 } catch (e) {
2083 return { type: "error" /* error */, error: e };
2084 }
2085 if (type === "error" /* error */) {
2086 return {
2087 type: "error" /* error */,
2088 error: new ErrorResponseImpl(result.status, result.statusText, data2),
2089 statusCode: result.status,
2090 headers: result.headers
2091 };
2092 }
2093 return {
2094 type: "data" /* data */,
2095 data: data2,
2096 statusCode: result.status,
2097 headers: result.headers
2098 };
2099 }
2100 if (type === "error" /* error */) {
2101 if (isDataWithResponseInit(result)) {
2102 if (result.data instanceof Error) {
2103 return {
2104 type: "error" /* error */,
2105 error: result.data,
2106 statusCode: result.init?.status,
2107 headers: result.init?.headers ? new Headers(result.init.headers) : void 0
2108 };
2109 }
2110 return {
2111 type: "error" /* error */,
2112 error: dataWithResponseInitToErrorResponse(result),
2113 statusCode: isRouteErrorResponse(result) ? result.status : void 0,
2114 headers: result.init?.headers ? new Headers(result.init.headers) : void 0
2115 };
2116 }
2117 return {
2118 type: "error" /* error */,
2119 error: result,
2120 statusCode: isRouteErrorResponse(result) ? result.status : void 0
2121 };
2122 }
2123 if (isDataWithResponseInit(result)) {
2124 return {
2125 type: "data" /* data */,
2126 data: result.data,
2127 statusCode: result.init?.status,
2128 headers: result.init?.headers ? new Headers(result.init.headers) : void 0
2129 };
2130 }
2131 return { type: "data" /* data */, data: result };
2132}
2133function normalizeRelativeRoutingRedirectResponse(response, request, routeId, matches, basename) {
2134 let location = response.headers.get("Location");
2135 invariant(
2136 location,
2137 "Redirects returned/thrown from loaders/actions must have a Location header"
2138 );
2139 if (!isAbsoluteUrl(location)) {
2140 let trimmedMatches = matches.slice(
2141 0,
2142 matches.findIndex((m) => m.route.id === routeId) + 1
2143 );
2144 location = normalizeTo(
2145 new URL(request.url),
2146 trimmedMatches,
2147 basename,
2148 location
2149 );
2150 response.headers.set("Location", location);
2151 }
2152 return response;
2153}
2154function createDataFunctionUrl(request, path) {
2155 let url = new URL(request.url);
2156 let parsed = typeof path === "string" ? parsePath(path) : path;
2157 url.pathname = parsed.pathname || "/";
2158 if (parsed.search) {
2159 let searchParams = new URLSearchParams(parsed.search);
2160 let indexValues = searchParams.getAll("index");
2161 searchParams.delete("index");
2162 for (let value of indexValues.filter(Boolean)) {
2163 searchParams.append("index", value);
2164 }
2165 url.search = searchParams.size ? `?${searchParams.toString()}` : "";
2166 } else {
2167 url.search = "";
2168 }
2169 url.hash = parsed.hash || "";
2170 return url;
2171}
2172function processRouteLoaderData(matches, results, pendingActionResult, isStaticHandler = false, skipLoaderErrorBubbling = false) {
2173 let loaderData = {};
2174 let errors = null;
2175 let statusCode;
2176 let foundError = false;
2177 let loaderHeaders = {};
2178 let pendingError = pendingActionResult && isErrorResult(pendingActionResult[1]) ? pendingActionResult[1].error : void 0;
2179 matches.forEach((match) => {
2180 if (!(match.route.id in results)) {
2181 return;
2182 }
2183 let id = match.route.id;
2184 let result = results[id];
2185 invariant(
2186 !isRedirectResult(result),
2187 "Cannot handle redirect results in processLoaderData"
2188 );
2189 if (isErrorResult(result)) {
2190 let error = result.error;
2191 if (pendingError !== void 0) {
2192 error = pendingError;
2193 pendingError = void 0;
2194 }
2195 errors = errors || {};
2196 if (skipLoaderErrorBubbling) {
2197 errors[id] = error;
2198 } else {
2199 let boundaryMatch = findNearestBoundary(matches, id);
2200 if (errors[boundaryMatch.route.id] == null) {
2201 errors[boundaryMatch.route.id] = error;
2202 }
2203 }
2204 if (!isStaticHandler) {
2205 loaderData[id] = ResetLoaderDataSymbol;
2206 }
2207 if (!foundError) {
2208 foundError = true;
2209 statusCode = isRouteErrorResponse(result.error) ? result.error.status : 500;
2210 }
2211 if (result.headers) {
2212 loaderHeaders[id] = result.headers;
2213 }
2214 } else {
2215 loaderData[id] = result.data;
2216 if (result.statusCode && result.statusCode !== 200 && !foundError) {
2217 statusCode = result.statusCode;
2218 }
2219 if (result.headers) {
2220 loaderHeaders[id] = result.headers;
2221 }
2222 }
2223 });
2224 if (pendingError !== void 0 && pendingActionResult) {
2225 errors = { [pendingActionResult[0]]: pendingError };
2226 if (pendingActionResult[2]) {
2227 loaderData[pendingActionResult[2]] = void 0;
2228 }
2229 }
2230 return {
2231 loaderData,
2232 errors,
2233 statusCode: statusCode || 200,
2234 loaderHeaders
2235 };
2236}
2237function findNearestBoundary(matches, routeId) {
2238 let eligibleMatches = routeId ? matches.slice(0, matches.findIndex((m) => m.route.id === routeId) + 1) : [...matches];
2239 return eligibleMatches.reverse().find((m) => m.route.hasErrorBoundary === true) || matches[0];
2240}
2241function getShortCircuitMatches(routes) {
2242 let route = routes.length === 1 ? routes[0] : routes.find((r) => r.index || !r.path || r.path === "/") || {
2243 id: `__shim-error-route__`
2244 };
2245 return {
2246 matches: [
2247 {
2248 params: {},
2249 pathname: "",
2250 pathnameBase: "",
2251 route
2252 }
2253 ],
2254 route
2255 };
2256}
2257function getInternalRouterError(status, {
2258 pathname,
2259 routeId,
2260 method,
2261 type,
2262 message
2263} = {}) {
2264 let statusText = "Unknown Server Error";
2265 let errorMessage = "Unknown @remix-run/router error";
2266 if (status === 400) {
2267 statusText = "Bad Request";
2268 if (method && pathname && routeId) {
2269 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.`;
2270 } else if (type === "invalid-body") {
2271 errorMessage = "Unable to encode submission body";
2272 }
2273 } else if (status === 403) {
2274 statusText = "Forbidden";
2275 errorMessage = `Route "${routeId}" does not match URL "${pathname}"`;
2276 } else if (status === 404) {
2277 statusText = "Not Found";
2278 errorMessage = `No route matches URL "${pathname}"`;
2279 } else if (status === 405) {
2280 statusText = "Method Not Allowed";
2281 if (method && pathname && routeId) {
2282 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.`;
2283 } else if (method) {
2284 errorMessage = `Invalid request method "${method.toUpperCase()}"`;
2285 }
2286 }
2287 return new ErrorResponseImpl(
2288 status || 500,
2289 statusText,
2290 new Error(errorMessage),
2291 true
2292 );
2293}
2294function dataWithResponseInitToResponse(data2) {
2295 return Response.json(data2.data, data2.init ?? void 0);
2296}
2297function dataWithResponseInitToErrorResponse(data2) {
2298 return new ErrorResponseImpl(
2299 data2.init?.status ?? 500,
2300 data2.init?.statusText ?? "Internal Server Error",
2301 data2.data
2302 );
2303}
2304function isDataStrategyResult(result) {
2305 return result != null && typeof result === "object" && "type" in result && "result" in result && (result.type === "data" /* data */ || result.type === "error" /* error */);
2306}
2307function isRedirectDataStrategyResult(result) {
2308 return isResponse(result.result) && redirectStatusCodes.has(result.result.status);
2309}
2310function isErrorResult(result) {
2311 return result.type === "error" /* error */;
2312}
2313function isRedirectResult(result) {
2314 return (result && result.type) === "redirect" /* redirect */;
2315}
2316function isDataWithResponseInit(value) {
2317 return typeof value === "object" && value != null && "type" in value && "data" in value && "init" in value && value.type === "DataWithResponseInit";
2318}
2319function isResponse(value) {
2320 return value != null && typeof value.status === "number" && typeof value.statusText === "string" && typeof value.headers === "object" && typeof value.body !== "undefined";
2321}
2322function isRedirectStatusCode(statusCode) {
2323 return redirectStatusCodes.has(statusCode);
2324}
2325function isRedirectResponse(result) {
2326 return isResponse(result) && isRedirectStatusCode(result.status) && result.headers.has("Location");
2327}
2328function isValidMethod(method) {
2329 return validRequestMethods.has(method.toUpperCase());
2330}
2331function isMutationMethod(method) {
2332 return validMutationMethods.has(method.toUpperCase());
2333}
2334function hasNakedIndexQuery(search) {
2335 return new URLSearchParams(search).getAll("index").some((v) => v === "");
2336}
2337function getTargetMatch(matches, location) {
2338 let search = typeof location === "string" ? parsePath(location).search : location.search;
2339 if (matches[matches.length - 1].route.index && hasNakedIndexQuery(search || "")) {
2340 return matches[matches.length - 1];
2341 }
2342 let pathMatches = getPathContributingMatches(matches);
2343 return pathMatches[pathMatches.length - 1];
2344}
2345
2346// lib/server-runtime/invariant.ts
2347function invariant2(value, message) {
2348 if (value === false || value === null || typeof value === "undefined") {
2349 console.error(
2350 "The following error is a bug in React Router; please open an issue! https://github.com/remix-run/react-router/issues/new/choose"
2351 );
2352 throw new Error(message);
2353 }
2354}
2355
2356// lib/server-runtime/headers.ts
2357function getDocumentHeadersImpl(context, getRouteHeadersFn, _defaultHeaders) {
2358 let boundaryIdx = context.errors ? context.matches.findIndex((m) => context.errors[m.route.id]) : -1;
2359 let matches = boundaryIdx >= 0 ? context.matches.slice(0, boundaryIdx + 1) : context.matches;
2360 let errorHeaders;
2361 if (boundaryIdx >= 0) {
2362 let { actionHeaders, actionData, loaderHeaders, loaderData } = context;
2363 context.matches.slice(boundaryIdx).some((match) => {
2364 let id = match.route.id;
2365 if (actionHeaders[id] && (!actionData || !actionData.hasOwnProperty(id))) {
2366 errorHeaders = actionHeaders[id];
2367 } else if (loaderHeaders[id] && !loaderData.hasOwnProperty(id)) {
2368 errorHeaders = loaderHeaders[id];
2369 }
2370 return errorHeaders != null;
2371 });
2372 }
2373 const defaultHeaders = new Headers(_defaultHeaders);
2374 return matches.reduce((parentHeaders, match, idx) => {
2375 let { id } = match.route;
2376 let loaderHeaders = context.loaderHeaders[id] || new Headers();
2377 let actionHeaders = context.actionHeaders[id] || new Headers();
2378 let includeErrorHeaders = errorHeaders != null && idx === matches.length - 1;
2379 let includeErrorCookies = includeErrorHeaders && errorHeaders !== loaderHeaders && errorHeaders !== actionHeaders;
2380 let headersFn = getRouteHeadersFn(match);
2381 if (headersFn == null) {
2382 let headers2 = new Headers(parentHeaders);
2383 if (includeErrorCookies) {
2384 prependCookies(errorHeaders, headers2);
2385 }
2386 prependCookies(actionHeaders, headers2);
2387 prependCookies(loaderHeaders, headers2);
2388 return headers2;
2389 }
2390 let headers = new Headers(
2391 typeof headersFn === "function" ? headersFn({
2392 loaderHeaders,
2393 parentHeaders,
2394 actionHeaders,
2395 errorHeaders: includeErrorHeaders ? errorHeaders : void 0
2396 }) : headersFn
2397 );
2398 if (includeErrorCookies) {
2399 prependCookies(errorHeaders, headers);
2400 }
2401 prependCookies(actionHeaders, headers);
2402 prependCookies(loaderHeaders, headers);
2403 prependCookies(parentHeaders, headers);
2404 return headers;
2405 }, new Headers(defaultHeaders));
2406}
2407function prependCookies(parentHeaders, childHeaders) {
2408 let parentSetCookieString = parentHeaders.get("Set-Cookie");
2409 if (parentSetCookieString) {
2410 let cookies = splitCookiesString(parentSetCookieString);
2411 let childCookies = new Set(childHeaders.getSetCookie());
2412 cookies.forEach((cookie) => {
2413 if (!childCookies.has(cookie)) {
2414 childHeaders.append("Set-Cookie", cookie);
2415 }
2416 });
2417 }
2418}
2419var SINGLE_FETCH_REDIRECT_STATUS = 202;
2420
2421// lib/actions.ts
2422function throwIfPotentialCSRFAttack(headers, allowedActionOrigins) {
2423 let originHeader = headers.get("origin");
2424 let originDomain = null;
2425 try {
2426 originDomain = typeof originHeader === "string" && originHeader !== "null" ? new URL(originHeader).host : originHeader;
2427 } catch {
2428 throw new Error(
2429 `\`origin\` header is not a valid URL. Aborting the action.`
2430 );
2431 }
2432 let host = parseHostHeader(headers);
2433 if (originDomain && (!host || originDomain !== host.value)) {
2434 if (!isAllowedOrigin(originDomain, allowedActionOrigins)) {
2435 if (host) {
2436 throw new Error(
2437 `${host.type} header does not match \`origin\` header from a forwarded action request. Aborting the action.`
2438 );
2439 } else {
2440 throw new Error(
2441 "`x-forwarded-host` or `host` headers are not provided. One of these is needed to compare the `origin` header from a forwarded action request. Aborting the action."
2442 );
2443 }
2444 }
2445 }
2446}
2447function matchWildcardDomain(domain, pattern) {
2448 const domainParts = domain.split(".");
2449 const patternParts = pattern.split(".");
2450 if (patternParts.length < 1) {
2451 return false;
2452 }
2453 if (domainParts.length < patternParts.length) {
2454 return false;
2455 }
2456 while (patternParts.length) {
2457 const patternPart = patternParts.pop();
2458 const domainPart = domainParts.pop();
2459 switch (patternPart) {
2460 case "": {
2461 return false;
2462 }
2463 case "*": {
2464 if (domainPart) {
2465 continue;
2466 } else {
2467 return false;
2468 }
2469 }
2470 case "**": {
2471 if (patternParts.length > 0) {
2472 return false;
2473 }
2474 return domainPart !== void 0;
2475 }
2476 case void 0:
2477 default: {
2478 if (domainPart !== patternPart) {
2479 return false;
2480 }
2481 }
2482 }
2483 }
2484 return domainParts.length === 0;
2485}
2486function isAllowedOrigin(originDomain, allowedActionOrigins = []) {
2487 return allowedActionOrigins.some(
2488 (allowedOrigin) => allowedOrigin && (allowedOrigin === originDomain || matchWildcardDomain(originDomain, allowedOrigin))
2489 );
2490}
2491function parseHostHeader(headers) {
2492 let forwardedHostHeader = headers.get("x-forwarded-host");
2493 let forwardedHostValue = forwardedHostHeader?.split(",")[0]?.trim();
2494 let hostHeader = headers.get("host");
2495 return forwardedHostValue ? {
2496 type: "x-forwarded-host",
2497 value: forwardedHostValue
2498 } : hostHeader ? {
2499 type: "host",
2500 value: hostHeader
2501 } : void 0;
2502}
2503
2504// lib/errors.ts
2505var ERROR_DIGEST_BASE = "REACT_ROUTER_ERROR";
2506var ERROR_DIGEST_REDIRECT = "REDIRECT";
2507var ERROR_DIGEST_ROUTE_ERROR_RESPONSE = "ROUTE_ERROR_RESPONSE";
2508function createRedirectErrorDigest(response) {
2509 return `${ERROR_DIGEST_BASE}:${ERROR_DIGEST_REDIRECT}:${JSON.stringify({
2510 status: response.status,
2511 statusText: response.statusText,
2512 location: response.headers.get("Location"),
2513 reloadDocument: response.headers.get("X-Remix-Reload-Document") === "true",
2514 replace: response.headers.get("X-Remix-Replace") === "true"
2515 })}`;
2516}
2517function createRouteErrorResponseDigest(response) {
2518 let status = 500;
2519 let statusText = "";
2520 let data2;
2521 if (isDataWithResponseInit(response)) {
2522 status = response.init?.status ?? status;
2523 statusText = response.init?.statusText ?? statusText;
2524 data2 = response.data;
2525 } else {
2526 status = response.status;
2527 statusText = response.statusText;
2528 data2 = void 0;
2529 }
2530 return `${ERROR_DIGEST_BASE}:${ERROR_DIGEST_ROUTE_ERROR_RESPONSE}:${JSON.stringify(
2531 {
2532 status,
2533 statusText,
2534 data: data2
2535 }
2536 )}`;
2537}
2538
2539// lib/server-runtime/urls.ts
2540function getNormalizedPath(request, basename, future) {
2541 basename = basename || "/";
2542 let url = new URL(request.url);
2543 let pathname = url.pathname;
2544 {
2545 if (stripBasename(pathname, basename) === "/_root.data") {
2546 pathname = basename;
2547 } else if (pathname.endsWith(".data")) {
2548 pathname = pathname.replace(/\.data$/, "");
2549 }
2550 if (stripBasename(pathname, basename) !== "/" && pathname.endsWith("/")) {
2551 pathname = pathname.slice(0, -1);
2552 }
2553 }
2554 let searchParams = new URLSearchParams(url.search);
2555 searchParams.delete("_routes");
2556 let search = searchParams.toString();
2557 if (search) {
2558 search = `?${search}`;
2559 }
2560 return {
2561 pathname,
2562 search,
2563 // No hashes on the server
2564 hash: ""
2565 };
2566}
2567
2568// lib/rsc/server.rsc.ts
2569var Outlet = Outlet$1;
2570var WithComponentProps = UNSAFE_WithComponentProps;
2571var WithErrorBoundaryProps = UNSAFE_WithErrorBoundaryProps;
2572var WithHydrateFallbackProps = UNSAFE_WithHydrateFallbackProps;
2573var globalVar = typeof globalThis !== "undefined" ? globalThis : global;
2574var ServerStorage = globalVar.___reactRouterServerStorage___ ?? (globalVar.___reactRouterServerStorage___ = new AsyncLocalStorage());
2575function getRequest() {
2576 const ctx = ServerStorage.getStore();
2577 if (!ctx)
2578 throw new Error(
2579 "getRequest must be called from within a React Server render context"
2580 );
2581 return ctx.request;
2582}
2583var redirect2 = (...args) => {
2584 const response = redirect(...args);
2585 const ctx = ServerStorage.getStore();
2586 if (ctx && ctx.runningAction) {
2587 ctx.redirect = response;
2588 }
2589 return response;
2590};
2591var redirectDocument2 = (...args) => {
2592 const response = redirectDocument(...args);
2593 const ctx = ServerStorage.getStore();
2594 if (ctx && ctx.runningAction) {
2595 ctx.redirect = response;
2596 }
2597 return response;
2598};
2599var replace2 = (...args) => {
2600 const response = replace(...args);
2601 const ctx = ServerStorage.getStore();
2602 if (ctx && ctx.runningAction) {
2603 ctx.redirect = response;
2604 }
2605 return response;
2606};
2607var cachedResolvePromise = (
2608 // @ts-expect-error - on 18 types, requires 19.
2609 React2.cache(async (resolve) => {
2610 return Promise.allSettled([resolve]).then((r) => r[0]);
2611 })
2612);
2613var Await = async ({
2614 children,
2615 resolve,
2616 errorElement
2617}) => {
2618 let promise = cachedResolvePromise(resolve);
2619 let resolved = await promise;
2620 if (resolved.status === "rejected" && !errorElement) {
2621 throw resolved.reason;
2622 }
2623 if (resolved.status === "rejected") {
2624 return React2.createElement(UNSAFE_AwaitContextProvider, {
2625 children: React2.createElement(React2.Fragment, null, errorElement),
2626 value: { _tracked: true, _error: resolved.reason }
2627 });
2628 }
2629 const toRender = typeof children === "function" ? children(resolved.value) : children;
2630 return React2.createElement(UNSAFE_AwaitContextProvider, {
2631 children: toRender,
2632 value: { _tracked: true, _data: resolved.value }
2633 });
2634};
2635async function matchRSCServerRequest({
2636 allowedActionOrigins,
2637 createTemporaryReferenceSet,
2638 basename,
2639 decodeReply,
2640 requestContext,
2641 routeDiscovery,
2642 loadServerAction,
2643 decodeAction,
2644 decodeFormState,
2645 onError,
2646 request,
2647 routes,
2648 generateResponse
2649}) {
2650 let url = new URL(request.url);
2651 basename = basename || "/";
2652 let normalizedPath = url.pathname;
2653 if (url.pathname.endsWith("/_.rsc")) {
2654 normalizedPath = url.pathname.replace(/_\.rsc$/, "");
2655 } else if (url.pathname.endsWith(".rsc")) {
2656 normalizedPath = url.pathname.replace(/\.rsc$/, "");
2657 }
2658 if (stripBasename(normalizedPath, basename) !== "/" && normalizedPath.endsWith("/")) {
2659 normalizedPath = normalizedPath.slice(0, -1);
2660 }
2661 url.pathname = normalizedPath;
2662 basename = basename.length > normalizedPath.length ? normalizedPath : basename;
2663 let routerRequest = new Request(url.toString(), {
2664 method: request.method,
2665 headers: request.headers,
2666 body: request.body,
2667 signal: request.signal,
2668 duplex: request.body ? "half" : void 0
2669 });
2670 const temporaryReferences = createTemporaryReferenceSet();
2671 const requestUrl = new URL(request.url);
2672 if (isManifestRequest(requestUrl)) {
2673 let response2 = await generateManifestResponse(
2674 routes,
2675 basename,
2676 request,
2677 generateResponse,
2678 temporaryReferences,
2679 routeDiscovery
2680 );
2681 return response2;
2682 }
2683 let isDataRequest = isReactServerRequest(requestUrl);
2684 let matches = matchRoutes(routes, url.pathname, basename);
2685 if (matches) {
2686 await Promise.all(matches.map((m) => explodeLazyRoute(m.route)));
2687 }
2688 const leafMatch = matches?.[matches.length - 1];
2689 if (!isDataRequest && leafMatch && !leafMatch.route.Component && !leafMatch.route.ErrorBoundary) {
2690 return generateResourceResponse(
2691 routerRequest,
2692 routes,
2693 basename,
2694 leafMatch.route.id,
2695 requestContext,
2696 onError
2697 );
2698 }
2699 let response = await generateRenderResponse(
2700 routerRequest,
2701 routes,
2702 basename,
2703 isDataRequest,
2704 decodeReply,
2705 requestContext,
2706 loadServerAction,
2707 decodeAction,
2708 decodeFormState,
2709 onError,
2710 generateResponse,
2711 temporaryReferences,
2712 allowedActionOrigins,
2713 routeDiscovery
2714 );
2715 response.headers.set("X-Remix-Response", "yes");
2716 return response;
2717}
2718async function generateManifestResponse(routes, basename, request, generateResponse, temporaryReferences, routeDiscovery) {
2719 if (routeDiscovery?.mode === "initial") {
2720 let payload2 = {
2721 type: "manifest",
2722 patches: getAllRoutePatches(routes)
2723 };
2724 return generateResponse(
2725 {
2726 statusCode: 200,
2727 headers: new Headers({
2728 "Content-Type": "text/x-component",
2729 Vary: "Content-Type"
2730 }),
2731 payload: payload2
2732 },
2733 { temporaryReferences, onError: defaultOnError }
2734 );
2735 }
2736 let url = new URL(request.url);
2737 let pathParam = url.searchParams.get("paths");
2738 let pathnames = pathParam ? pathParam.split(",").filter(Boolean) : [url.pathname.replace(/\.manifest$/, "")];
2739 let routeIds = /* @__PURE__ */ new Set();
2740 let matchedRoutes = pathnames.flatMap((pathname) => {
2741 let pathnameMatches = matchRoutes(routes, pathname, basename);
2742 return pathnameMatches?.map((m, i) => ({
2743 ...m.route,
2744 parentId: pathnameMatches[i - 1]?.route.id
2745 })) ?? [];
2746 }).filter((route) => {
2747 if (!routeIds.has(route.id)) {
2748 routeIds.add(route.id);
2749 return true;
2750 }
2751 return false;
2752 });
2753 let payload = {
2754 type: "manifest",
2755 patches: Promise.all([
2756 ...matchedRoutes.map((route) => getManifestRoute(route)),
2757 getAdditionalRoutePatches(
2758 pathnames,
2759 routes,
2760 basename,
2761 Array.from(routeIds)
2762 )
2763 ]).then((r) => r.flat(1))
2764 };
2765 return generateResponse(
2766 {
2767 statusCode: 200,
2768 headers: new Headers({
2769 "Content-Type": "text/x-component"
2770 }),
2771 payload
2772 },
2773 { temporaryReferences, onError: defaultOnError }
2774 );
2775}
2776function prependBasenameToRedirectResponse(response, basename = "/") {
2777 if (basename === "/") {
2778 return response;
2779 }
2780 let redirect3 = response.headers.get("Location");
2781 if (!redirect3 || isAbsoluteUrl(redirect3)) {
2782 return response;
2783 }
2784 response.headers.set(
2785 "Location",
2786 prependBasename({ basename, pathname: redirect3 })
2787 );
2788 return response;
2789}
2790async function processServerAction(request, basename, decodeReply, loadServerAction, decodeAction, decodeFormState, onError, temporaryReferences) {
2791 const getRevalidationRequest = () => new Request(request.url, {
2792 method: "GET",
2793 headers: request.headers,
2794 signal: request.signal
2795 });
2796 const isFormRequest = canDecodeWithFormData(
2797 request.headers.get("Content-Type")
2798 );
2799 const actionId = request.headers.get("rsc-action-id");
2800 if (actionId) {
2801 if (!decodeReply || !loadServerAction) {
2802 throw new Error(
2803 "Cannot handle enhanced server action without decodeReply and loadServerAction functions"
2804 );
2805 }
2806 const reply = isFormRequest ? await request.formData() : await request.text();
2807 const actionArgs = await decodeReply(reply, { temporaryReferences });
2808 const action = await loadServerAction(actionId);
2809 const serverAction = action.bind(null, ...actionArgs);
2810 let actionResult = Promise.resolve(serverAction());
2811 try {
2812 await actionResult;
2813 } catch (error) {
2814 if (isResponse(error)) {
2815 return error;
2816 }
2817 onError?.(error);
2818 }
2819 let maybeFormData = actionArgs.length === 1 ? actionArgs[0] : actionArgs[1];
2820 let formData = maybeFormData && typeof maybeFormData === "object" && maybeFormData instanceof FormData ? maybeFormData : null;
2821 let skipRevalidation = formData?.has("$SKIP_REVALIDATION") ?? false;
2822 return {
2823 actionResult,
2824 revalidationRequest: getRevalidationRequest(),
2825 skipRevalidation
2826 };
2827 } else if (isFormRequest) {
2828 const formData = await request.clone().formData();
2829 if (Array.from(formData.keys()).some((k) => k.startsWith("$ACTION_"))) {
2830 if (!decodeAction) {
2831 throw new Error(
2832 "Cannot handle form actions without a decodeAction function"
2833 );
2834 }
2835 const action = await decodeAction(formData);
2836 let formState = void 0;
2837 try {
2838 let result = await action();
2839 if (isRedirectResponse(result)) {
2840 result = prependBasenameToRedirectResponse(result, basename);
2841 }
2842 formState = decodeFormState?.(result, formData);
2843 } catch (error) {
2844 if (isRedirectResponse(error)) {
2845 return prependBasenameToRedirectResponse(error, basename);
2846 }
2847 if (isResponse(error)) {
2848 return error;
2849 }
2850 onError?.(error);
2851 }
2852 return {
2853 formState,
2854 revalidationRequest: getRevalidationRequest(),
2855 skipRevalidation: false
2856 };
2857 }
2858 }
2859}
2860async function generateResourceResponse(request, routes, basename, routeId, requestContext, onError) {
2861 try {
2862 const staticHandler = createStaticHandler(routes, {
2863 basename
2864 });
2865 let response = await staticHandler.queryRoute(request, {
2866 routeId,
2867 requestContext,
2868 async generateMiddlewareResponse(queryRoute) {
2869 try {
2870 let response2 = await queryRoute(request);
2871 return generateResourceResponse2(response2);
2872 } catch (error) {
2873 return generateErrorResponse(error);
2874 }
2875 },
2876 unstable_normalizePath: (r) => getNormalizedPath(r, basename, null)
2877 });
2878 return response;
2879 } catch (error) {
2880 return generateErrorResponse(error);
2881 }
2882 function generateErrorResponse(error) {
2883 let response;
2884 if (isResponse(error)) {
2885 response = error;
2886 } else if (isRouteErrorResponse(error)) {
2887 onError?.(error);
2888 const errorMessage = typeof error.data === "string" ? error.data : error.statusText;
2889 response = new Response(errorMessage, {
2890 status: error.status,
2891 statusText: error.statusText
2892 });
2893 } else {
2894 onError?.(error);
2895 response = new Response("Internal Server Error", { status: 500 });
2896 }
2897 return generateResourceResponse2(response);
2898 }
2899 function generateResourceResponse2(response) {
2900 const headers = new Headers(response.headers);
2901 headers.set("React-Router-Resource", "true");
2902 return new Response(response.body, {
2903 status: response.status,
2904 statusText: response.statusText,
2905 headers
2906 });
2907 }
2908}
2909async function generateRenderResponse(request, routes, basename, isDataRequest, decodeReply, requestContext, loadServerAction, decodeAction, decodeFormState, onError, generateResponse, temporaryReferences, allowedActionOrigins, routeDiscovery) {
2910 let statusCode = 200;
2911 let url = new URL(request.url);
2912 let isSubmission = isMutationMethod(request.method);
2913 let routeIdsToLoad = !isSubmission && url.searchParams.has("_routes") ? url.searchParams.get("_routes").split(",") : null;
2914 const staticHandler = createStaticHandler(routes, {
2915 basename,
2916 mapRouteProperties: (r) => ({
2917 hasErrorBoundary: r.ErrorBoundary != null
2918 })
2919 });
2920 let actionResult;
2921 const ctx = {
2922 request,
2923 runningAction: false
2924 };
2925 const result = await ServerStorage.run(
2926 ctx,
2927 () => staticHandler.query(request, {
2928 requestContext,
2929 skipLoaderErrorBubbling: isDataRequest,
2930 skipRevalidation: isSubmission,
2931 ...routeIdsToLoad ? { filterMatchesToLoad: (m) => routeIdsToLoad.includes(m.route.id) } : {},
2932 unstable_normalizePath: (r) => getNormalizedPath(r, basename),
2933 async generateMiddlewareResponse(query) {
2934 let formState;
2935 let skipRevalidation = false;
2936 let potentialCSRFAttackError;
2937 if (request.method === "POST") {
2938 try {
2939 throwIfPotentialCSRFAttack(request.headers, allowedActionOrigins);
2940 ctx.runningAction = true;
2941 let result2 = await processServerAction(
2942 request,
2943 basename,
2944 decodeReply,
2945 loadServerAction,
2946 decodeAction,
2947 decodeFormState,
2948 onError,
2949 temporaryReferences
2950 ).finally(() => {
2951 ctx.runningAction = false;
2952 });
2953 if (isResponse(result2)) {
2954 return generateRedirectResponse(
2955 result2,
2956 actionResult,
2957 basename,
2958 isDataRequest,
2959 generateResponse,
2960 temporaryReferences,
2961 ctx.redirect?.headers
2962 );
2963 }
2964 skipRevalidation = result2?.skipRevalidation ?? false;
2965 actionResult = result2?.actionResult;
2966 formState = result2?.formState;
2967 request = result2?.revalidationRequest ?? request;
2968 if (ctx.redirect) {
2969 return generateRedirectResponse(
2970 ctx.redirect,
2971 actionResult,
2972 basename,
2973 isDataRequest,
2974 generateResponse,
2975 temporaryReferences,
2976 void 0
2977 );
2978 }
2979 } catch (error) {
2980 potentialCSRFAttackError = error;
2981 }
2982 }
2983 let staticContext = await query(
2984 request,
2985 skipRevalidation || !!potentialCSRFAttackError ? {
2986 filterMatchesToLoad: () => false
2987 } : void 0
2988 );
2989 if (isResponse(staticContext)) {
2990 return generateRedirectResponse(
2991 staticContext,
2992 actionResult,
2993 basename,
2994 isDataRequest,
2995 generateResponse,
2996 temporaryReferences,
2997 ctx.redirect?.headers
2998 );
2999 }
3000 if (potentialCSRFAttackError) {
3001 staticContext.errors ?? (staticContext.errors = {});
3002 staticContext.errors[staticContext.matches[0].route.id] = potentialCSRFAttackError;
3003 staticContext.statusCode = 400;
3004 }
3005 return generateStaticContextResponse(
3006 routes,
3007 basename,
3008 generateResponse,
3009 statusCode,
3010 routeIdsToLoad,
3011 isDataRequest,
3012 isSubmission,
3013 actionResult,
3014 formState,
3015 staticContext,
3016 temporaryReferences,
3017 skipRevalidation,
3018 ctx.redirect?.headers,
3019 routeDiscovery
3020 );
3021 }
3022 })
3023 );
3024 if (isRedirectResponse(result)) {
3025 return generateRedirectResponse(
3026 result,
3027 actionResult,
3028 basename,
3029 isDataRequest,
3030 generateResponse,
3031 temporaryReferences,
3032 ctx.redirect?.headers
3033 );
3034 }
3035 invariant2(isResponse(result), "Expected a response from query");
3036 return result;
3037}
3038function generateRedirectResponse(response, actionResult, basename, isDataRequest, generateResponse, temporaryReferences, sideEffectRedirectHeaders) {
3039 let redirect3 = response.headers.get("Location");
3040 if (isDataRequest && basename) {
3041 redirect3 = stripBasename(redirect3, basename) || redirect3;
3042 }
3043 let payload = {
3044 type: "redirect",
3045 location: redirect3,
3046 reload: response.headers.get("X-Remix-Reload-Document") === "true",
3047 replace: response.headers.get("X-Remix-Replace") === "true",
3048 status: response.status,
3049 actionResult
3050 };
3051 let headers = new Headers(sideEffectRedirectHeaders);
3052 for (const [key, value] of response.headers.entries()) {
3053 headers.append(key, value);
3054 }
3055 headers.delete("Location");
3056 headers.delete("X-Remix-Reload-Document");
3057 headers.delete("X-Remix-Replace");
3058 headers.delete("Content-Length");
3059 headers.set("Content-Type", "text/x-component");
3060 return generateResponse(
3061 {
3062 statusCode: SINGLE_FETCH_REDIRECT_STATUS,
3063 headers,
3064 payload
3065 },
3066 { temporaryReferences, onError: defaultOnError }
3067 );
3068}
3069async function generateStaticContextResponse(routes, basename, generateResponse, statusCode, routeIdsToLoad, isDataRequest, isSubmission, actionResult, formState, staticContext, temporaryReferences, skipRevalidation, sideEffectRedirectHeaders, routeDiscovery) {
3070 statusCode = staticContext.statusCode ?? statusCode;
3071 if (staticContext.errors) {
3072 staticContext.errors = Object.fromEntries(
3073 Object.entries(staticContext.errors).map(([key, error]) => [
3074 key,
3075 isRouteErrorResponse(error) ? Object.fromEntries(Object.entries(error)) : error
3076 ])
3077 );
3078 }
3079 staticContext.matches.forEach((m) => {
3080 const routeHasNoLoaderData = staticContext.loaderData[m.route.id] === void 0;
3081 const routeHasError = Boolean(
3082 staticContext.errors && m.route.id in staticContext.errors
3083 );
3084 if (routeHasNoLoaderData && !routeHasError) {
3085 staticContext.loaderData[m.route.id] = null;
3086 }
3087 });
3088 let headers = getDocumentHeadersImpl(
3089 staticContext,
3090 (match) => match.route.headers,
3091 sideEffectRedirectHeaders
3092 );
3093 headers.delete("Content-Length");
3094 const baseRenderPayload = {
3095 type: "render",
3096 basename: staticContext.basename,
3097 routeDiscovery: routeDiscovery ?? { mode: "lazy" },
3098 actionData: staticContext.actionData,
3099 errors: staticContext.errors,
3100 loaderData: staticContext.loaderData,
3101 location: staticContext.location,
3102 formState
3103 };
3104 const renderPayloadPromise = () => getRenderPayload(
3105 baseRenderPayload,
3106 routes,
3107 basename,
3108 routeIdsToLoad,
3109 isDataRequest,
3110 staticContext,
3111 routeDiscovery
3112 );
3113 let payload;
3114 if (actionResult) {
3115 payload = {
3116 type: "action",
3117 actionResult,
3118 rerender: skipRevalidation ? void 0 : renderPayloadPromise()
3119 };
3120 } else if (isSubmission && isDataRequest) {
3121 payload = {
3122 ...baseRenderPayload,
3123 matches: [],
3124 patches: Promise.resolve([])
3125 };
3126 } else {
3127 payload = await renderPayloadPromise();
3128 }
3129 return generateResponse(
3130 {
3131 statusCode,
3132 headers,
3133 payload
3134 },
3135 { temporaryReferences, onError: defaultOnError }
3136 );
3137}
3138async function getRenderPayload(baseRenderPayload, routes, basename, routeIdsToLoad, isDataRequest, staticContext, routeDiscovery) {
3139 let deepestRenderedRouteIdx = staticContext.matches.length - 1;
3140 let parentIds = {};
3141 staticContext.matches.forEach((m, i) => {
3142 if (i > 0) {
3143 parentIds[m.route.id] = staticContext.matches[i - 1].route.id;
3144 }
3145 if (staticContext.errors && m.route.id in staticContext.errors && deepestRenderedRouteIdx > i) {
3146 deepestRenderedRouteIdx = i;
3147 }
3148 });
3149 let matchesPromise = Promise.all(
3150 staticContext.matches.map((match, i) => {
3151 let isBelowErrorBoundary = i > deepestRenderedRouteIdx;
3152 let parentId = parentIds[match.route.id];
3153 return getRSCRouteMatch({
3154 staticContext,
3155 match,
3156 routeIdsToLoad,
3157 isBelowErrorBoundary,
3158 parentId
3159 });
3160 })
3161 );
3162 let patches = routeDiscovery?.mode === "initial" && !isDataRequest ? getAllRoutePatches(routes).then(
3163 (patches2) => patches2.filter(
3164 (patch) => !staticContext.matches.some((m) => m.route.id === patch.id)
3165 )
3166 ) : getAdditionalRoutePatches(
3167 [staticContext.location.pathname],
3168 routes,
3169 basename,
3170 staticContext.matches.map((m) => m.route.id)
3171 );
3172 return {
3173 ...baseRenderPayload,
3174 matches: await matchesPromise,
3175 patches
3176 };
3177}
3178async function getRSCRouteMatch({
3179 staticContext,
3180 match,
3181 isBelowErrorBoundary,
3182 routeIdsToLoad,
3183 parentId
3184}) {
3185 const route = match.route;
3186 await explodeLazyRoute(route);
3187 const Layout = route.Layout || React2.Fragment;
3188 const Component = route.Component;
3189 const ErrorBoundary = route.ErrorBoundary;
3190 const HydrateFallback = route.HydrateFallback;
3191 const loaderData = staticContext.loaderData[route.id];
3192 const actionData = staticContext.actionData?.[route.id];
3193 const params = match.params;
3194 let element = void 0;
3195 let shouldLoadRoute = !routeIdsToLoad || routeIdsToLoad.includes(route.id);
3196 if (Component && shouldLoadRoute) {
3197 element = !isBelowErrorBoundary ? React2.createElement(
3198 Layout,
3199 null,
3200 isClientReference(Component) ? React2.createElement(WithComponentProps, {
3201 children: React2.createElement(Component)
3202 }) : React2.createElement(Component, {
3203 loaderData,
3204 actionData,
3205 params,
3206 matches: staticContext.matches.map(
3207 (match2) => convertRouteMatchToUiMatch(match2, staticContext.loaderData)
3208 )
3209 })
3210 ) : React2.createElement(Outlet);
3211 }
3212 let error = void 0;
3213 if (ErrorBoundary && staticContext.errors) {
3214 error = staticContext.errors[route.id];
3215 }
3216 const errorElement = ErrorBoundary ? React2.createElement(
3217 Layout,
3218 null,
3219 isClientReference(ErrorBoundary) ? React2.createElement(WithErrorBoundaryProps, {
3220 children: React2.createElement(ErrorBoundary)
3221 }) : React2.createElement(ErrorBoundary, {
3222 loaderData,
3223 actionData,
3224 params,
3225 error
3226 })
3227 ) : void 0;
3228 const hydrateFallbackElement = HydrateFallback ? React2.createElement(
3229 Layout,
3230 null,
3231 isClientReference(HydrateFallback) ? React2.createElement(WithHydrateFallbackProps, {
3232 children: React2.createElement(HydrateFallback)
3233 }) : React2.createElement(HydrateFallback, {
3234 loaderData,
3235 actionData,
3236 params
3237 })
3238 ) : void 0;
3239 const hmrRoute = route;
3240 return {
3241 clientAction: route.clientAction,
3242 clientLoader: route.clientLoader,
3243 element,
3244 errorElement,
3245 handle: route.handle,
3246 hasAction: !!route.action,
3247 hasComponent: !!Component,
3248 hasErrorBoundary: !!ErrorBoundary,
3249 hasLoader: !!route.loader,
3250 hydrateFallbackElement,
3251 id: route.id,
3252 index: "index" in route ? route.index : void 0,
3253 links: route.links,
3254 meta: route.meta,
3255 params,
3256 parentId,
3257 path: route.path,
3258 pathname: match.pathname,
3259 pathnameBase: match.pathnameBase,
3260 shouldRevalidate: route.shouldRevalidate,
3261 // Add an unused client-only export (if present) so HMR can support
3262 // switching between server-first and client-only routes during development
3263 ...hmrRoute.__ensureClientRouteModuleForHMR ? {
3264 __ensureClientRouteModuleForHMR: hmrRoute.__ensureClientRouteModuleForHMR
3265 } : {}
3266 };
3267}
3268async function getManifestRoute(route) {
3269 await explodeLazyRoute(route);
3270 const Layout = route.Layout || React2.Fragment;
3271 const errorElement = route.ErrorBoundary ? React2.createElement(
3272 Layout,
3273 null,
3274 React2.createElement(route.ErrorBoundary)
3275 ) : void 0;
3276 return {
3277 clientAction: route.clientAction,
3278 clientLoader: route.clientLoader,
3279 handle: route.handle,
3280 hasAction: !!route.action,
3281 hasComponent: !!route.Component,
3282 hasErrorBoundary: !!route.ErrorBoundary,
3283 errorElement,
3284 hasLoader: !!route.loader,
3285 id: route.id,
3286 parentId: route.parentId,
3287 path: route.path,
3288 index: "index" in route ? route.index : void 0,
3289 links: route.links,
3290 meta: route.meta
3291 };
3292}
3293async function explodeLazyRoute(route) {
3294 if ("lazy" in route && route.lazy) {
3295 let {
3296 default: lazyDefaultExport,
3297 Component: lazyComponentExport,
3298 ...lazyProperties
3299 } = await route.lazy();
3300 let Component = lazyComponentExport || lazyDefaultExport;
3301 if (Component && !route.Component) {
3302 route.Component = Component;
3303 }
3304 for (let [k, v] of Object.entries(lazyProperties)) {
3305 if (k !== "id" && k !== "path" && k !== "index" && k !== "children" && route[k] == null) {
3306 route[k] = v;
3307 }
3308 }
3309 route.lazy = void 0;
3310 }
3311}
3312async function getAllRoutePatches(routes, basename) {
3313 let patches = [];
3314 async function traverse(route, parentId) {
3315 let manifestRoute = await getManifestRoute({ ...route, parentId });
3316 patches.push(manifestRoute);
3317 if ("children" in route && route.children?.length) {
3318 for (let child of route.children) {
3319 await traverse(child, route.id);
3320 }
3321 }
3322 }
3323 for (let route of routes) {
3324 await traverse(route, void 0);
3325 }
3326 return patches.filter((p) => !!p.parentId);
3327}
3328async function getAdditionalRoutePatches(pathnames, routes, basename, matchedRouteIds) {
3329 let patchRouteMatches = /* @__PURE__ */ new Map();
3330 let matchedPaths = /* @__PURE__ */ new Set();
3331 for (const pathname of pathnames) {
3332 let segments = pathname.split("/").filter(Boolean);
3333 let paths = ["/"];
3334 segments.pop();
3335 while (segments.length > 0) {
3336 paths.push(`/${segments.join("/")}`);
3337 segments.pop();
3338 }
3339 paths.forEach((path) => {
3340 if (matchedPaths.has(path)) {
3341 return;
3342 }
3343 matchedPaths.add(path);
3344 let matches = matchRoutes(routes, path, basename) || [];
3345 matches.forEach((m, i) => {
3346 if (patchRouteMatches.get(m.route.id)) {
3347 return;
3348 }
3349 patchRouteMatches.set(m.route.id, {
3350 ...m.route,
3351 parentId: matches[i - 1]?.route.id
3352 });
3353 });
3354 });
3355 }
3356 let patches = await Promise.all(
3357 [...patchRouteMatches.values()].filter((route) => !matchedRouteIds.some((id) => id === route.id)).map((route) => getManifestRoute(route))
3358 );
3359 return patches;
3360}
3361function isReactServerRequest(url) {
3362 return url.pathname.endsWith(".rsc");
3363}
3364function isManifestRequest(url) {
3365 return url.pathname.endsWith(".manifest");
3366}
3367function defaultOnError(error) {
3368 if (isRedirectResponse(error)) {
3369 return createRedirectErrorDigest(error);
3370 }
3371 if (isResponse(error) || isDataWithResponseInit(error)) {
3372 return createRouteErrorResponseDigest(error);
3373 }
3374}
3375function isClientReference(x) {
3376 try {
3377 return x.$$typeof === Symbol.for("react.client.reference");
3378 } catch {
3379 return false;
3380 }
3381}
3382function canDecodeWithFormData(contentType) {
3383 if (!contentType) return false;
3384 return contentType.match(/\bapplication\/x-www-form-urlencoded\b/) || contentType.match(/\bmultipart\/form-data\b/);
3385}
3386
3387// lib/href.ts
3388function href(path, ...args) {
3389 let params = args[0];
3390 let result = trimTrailingSplat(path).replace(
3391 /\/:([\w-]+)(\?)?/g,
3392 // same regex as in .\router\utils.ts: compilePath().
3393 (_, param, questionMark) => {
3394 const isRequired = questionMark === void 0;
3395 const value = params?.[param];
3396 if (isRequired && value === void 0) {
3397 throw new Error(
3398 `Path '${path}' requires param '${param}' but it was not provided`
3399 );
3400 }
3401 return value === void 0 ? "" : "/" + value;
3402 }
3403 );
3404 if (path.endsWith("*")) {
3405 const value = params?.["*"];
3406 if (value !== void 0) {
3407 result += "/" + value;
3408 }
3409 }
3410 return result || "/";
3411}
3412function trimTrailingSplat(path) {
3413 let i = path.length - 1;
3414 let char = path[i];
3415 if (char !== "*" && char !== "/") return path;
3416 i--;
3417 for (; i >= 0; i--) {
3418 if (path[i] !== "/") break;
3419 }
3420 return path.slice(0, i + 1);
3421}
3422
3423// lib/server-runtime/crypto.ts
3424var encoder = /* @__PURE__ */ new TextEncoder();
3425var sign = async (value, secret) => {
3426 let data2 = encoder.encode(value);
3427 let key = await createKey2(secret, ["sign"]);
3428 let signature = await crypto.subtle.sign("HMAC", key, data2);
3429 let hash = btoa(String.fromCharCode(...new Uint8Array(signature))).replace(
3430 /=+$/,
3431 ""
3432 );
3433 return value + "." + hash;
3434};
3435var unsign = async (cookie, secret) => {
3436 let index = cookie.lastIndexOf(".");
3437 let value = cookie.slice(0, index);
3438 let hash = cookie.slice(index + 1);
3439 let data2 = encoder.encode(value);
3440 let key = await createKey2(secret, ["verify"]);
3441 try {
3442 let signature = byteStringToUint8Array(atob(hash));
3443 let valid = await crypto.subtle.verify("HMAC", key, signature, data2);
3444 return valid ? value : false;
3445 } catch (error) {
3446 return false;
3447 }
3448};
3449var createKey2 = async (secret, usages) => crypto.subtle.importKey(
3450 "raw",
3451 encoder.encode(secret),
3452 { name: "HMAC", hash: "SHA-256" },
3453 false,
3454 usages
3455);
3456function byteStringToUint8Array(byteString) {
3457 let array = new Uint8Array(byteString.length);
3458 for (let i = 0; i < byteString.length; i++) {
3459 array[i] = byteString.charCodeAt(i);
3460 }
3461 return array;
3462}
3463
3464// lib/server-runtime/warnings.ts
3465var alreadyWarned = {};
3466function warnOnce(condition, message) {
3467 if (!condition && !alreadyWarned[message]) {
3468 alreadyWarned[message] = true;
3469 console.warn(message);
3470 }
3471}
3472
3473// lib/server-runtime/cookies.ts
3474var createCookie = (name, cookieOptions = {}) => {
3475 let { secrets = [], ...options } = {
3476 path: "/",
3477 sameSite: "lax",
3478 ...cookieOptions
3479 };
3480 warnOnceAboutExpiresCookie(name, options.expires);
3481 return {
3482 get name() {
3483 return name;
3484 },
3485 get isSigned() {
3486 return secrets.length > 0;
3487 },
3488 get expires() {
3489 return typeof options.maxAge !== "undefined" ? new Date(Date.now() + options.maxAge * 1e3) : options.expires;
3490 },
3491 async parse(cookieHeader, parseOptions) {
3492 if (!cookieHeader) return null;
3493 let cookies = parse(cookieHeader, { ...options, ...parseOptions });
3494 if (name in cookies) {
3495 let value = cookies[name];
3496 if (typeof value === "string" && value !== "") {
3497 let decoded = await decodeCookieValue(value, secrets);
3498 return decoded;
3499 } else {
3500 return "";
3501 }
3502 } else {
3503 return null;
3504 }
3505 },
3506 async serialize(value, serializeOptions) {
3507 return serialize(
3508 name,
3509 value === "" ? "" : await encodeCookieValue(value, secrets),
3510 {
3511 ...options,
3512 ...serializeOptions
3513 }
3514 );
3515 }
3516 };
3517};
3518var isCookie = (object) => {
3519 return object != null && typeof object.name === "string" && typeof object.isSigned === "boolean" && typeof object.parse === "function" && typeof object.serialize === "function";
3520};
3521async function encodeCookieValue(value, secrets) {
3522 let encoded = encodeData(value);
3523 if (secrets.length > 0) {
3524 encoded = await sign(encoded, secrets[0]);
3525 }
3526 return encoded;
3527}
3528async function decodeCookieValue(value, secrets) {
3529 if (secrets.length > 0) {
3530 for (let secret of secrets) {
3531 let unsignedValue = await unsign(value, secret);
3532 if (unsignedValue !== false) {
3533 return decodeData(unsignedValue);
3534 }
3535 }
3536 return null;
3537 }
3538 return decodeData(value);
3539}
3540function encodeData(value) {
3541 return btoa(myUnescape(encodeURIComponent(JSON.stringify(value))));
3542}
3543function decodeData(value) {
3544 try {
3545 return JSON.parse(decodeURIComponent(myEscape(atob(value))));
3546 } catch (error) {
3547 return {};
3548 }
3549}
3550function myEscape(value) {
3551 let str = value.toString();
3552 let result = "";
3553 let index = 0;
3554 let chr, code;
3555 while (index < str.length) {
3556 chr = str.charAt(index++);
3557 if (/[\w*+\-./@]/.exec(chr)) {
3558 result += chr;
3559 } else {
3560 code = chr.charCodeAt(0);
3561 if (code < 256) {
3562 result += "%" + hex(code, 2);
3563 } else {
3564 result += "%u" + hex(code, 4).toUpperCase();
3565 }
3566 }
3567 }
3568 return result;
3569}
3570function hex(code, length) {
3571 let result = code.toString(16);
3572 while (result.length < length) result = "0" + result;
3573 return result;
3574}
3575function myUnescape(value) {
3576 let str = value.toString();
3577 let result = "";
3578 let index = 0;
3579 let chr, part;
3580 while (index < str.length) {
3581 chr = str.charAt(index++);
3582 if (chr === "%") {
3583 if (str.charAt(index) === "u") {
3584 part = str.slice(index + 1, index + 5);
3585 if (/^[\da-f]{4}$/i.exec(part)) {
3586 result += String.fromCharCode(parseInt(part, 16));
3587 index += 5;
3588 continue;
3589 }
3590 } else {
3591 part = str.slice(index, index + 2);
3592 if (/^[\da-f]{2}$/i.exec(part)) {
3593 result += String.fromCharCode(parseInt(part, 16));
3594 index += 2;
3595 continue;
3596 }
3597 }
3598 }
3599 result += chr;
3600 }
3601 return result;
3602}
3603function warnOnceAboutExpiresCookie(name, expires) {
3604 warnOnce(
3605 !expires,
3606 `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.`
3607 );
3608}
3609
3610// lib/server-runtime/sessions.ts
3611function flash(name) {
3612 return `__flash_${name}__`;
3613}
3614var createSession = (initialData = {}, id = "") => {
3615 let map = new Map(Object.entries(initialData));
3616 return {
3617 get id() {
3618 return id;
3619 },
3620 get data() {
3621 return Object.fromEntries(map);
3622 },
3623 has(name) {
3624 return map.has(name) || map.has(flash(name));
3625 },
3626 get(name) {
3627 if (map.has(name)) return map.get(name);
3628 let flashName = flash(name);
3629 if (map.has(flashName)) {
3630 let value = map.get(flashName);
3631 map.delete(flashName);
3632 return value;
3633 }
3634 return void 0;
3635 },
3636 set(name, value) {
3637 map.set(name, value);
3638 },
3639 flash(name, value) {
3640 map.set(flash(name), value);
3641 },
3642 unset(name) {
3643 map.delete(name);
3644 }
3645 };
3646};
3647var isSession = (object) => {
3648 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";
3649};
3650function createSessionStorage({
3651 cookie: cookieArg,
3652 createData,
3653 readData,
3654 updateData,
3655 deleteData
3656}) {
3657 let cookie = isCookie(cookieArg) ? cookieArg : createCookie(cookieArg?.name || "__session", cookieArg);
3658 warnOnceAboutSigningSessionCookie(cookie);
3659 return {
3660 async getSession(cookieHeader, options) {
3661 let id = cookieHeader && await cookie.parse(cookieHeader, options);
3662 let data2 = id && await readData(id);
3663 return createSession(data2 || {}, id || "");
3664 },
3665 async commitSession(session, options) {
3666 let { id, data: data2 } = session;
3667 let expires = options?.maxAge != null ? new Date(Date.now() + options.maxAge * 1e3) : options?.expires != null ? options.expires : cookie.expires;
3668 if (id) {
3669 await updateData(id, data2, expires);
3670 } else {
3671 id = await createData(data2, expires);
3672 }
3673 return cookie.serialize(id, options);
3674 },
3675 async destroySession(session, options) {
3676 await deleteData(session.id);
3677 return cookie.serialize("", {
3678 ...options,
3679 maxAge: void 0,
3680 expires: /* @__PURE__ */ new Date(0)
3681 });
3682 }
3683 };
3684}
3685function warnOnceAboutSigningSessionCookie(cookie) {
3686 warnOnce(
3687 cookie.isSigned,
3688 `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.`
3689 );
3690}
3691
3692// lib/server-runtime/sessions/cookieStorage.ts
3693function createCookieSessionStorage({ cookie: cookieArg } = {}) {
3694 let cookie = isCookie(cookieArg) ? cookieArg : createCookie(cookieArg?.name || "__session", cookieArg);
3695 warnOnceAboutSigningSessionCookie(cookie);
3696 return {
3697 async getSession(cookieHeader, options) {
3698 return createSession(
3699 cookieHeader && await cookie.parse(cookieHeader, options) || {}
3700 );
3701 },
3702 async commitSession(session, options) {
3703 let serializedCookie = await cookie.serialize(session.data, options);
3704 if (serializedCookie.length > 4096) {
3705 throw new Error(
3706 "Cookie length will exceed browser maximum. Length: " + serializedCookie.length
3707 );
3708 }
3709 return serializedCookie;
3710 },
3711 async destroySession(_session, options) {
3712 return cookie.serialize("", {
3713 ...options,
3714 maxAge: void 0,
3715 expires: /* @__PURE__ */ new Date(0)
3716 });
3717 }
3718 };
3719}
3720
3721// lib/server-runtime/sessions/memoryStorage.ts
3722function createMemorySessionStorage({ cookie } = {}) {
3723 let map = /* @__PURE__ */ new Map();
3724 return createSessionStorage({
3725 cookie,
3726 async createData(data2, expires) {
3727 let id = Math.random().toString(36).substring(2, 10);
3728 map.set(id, { data: data2, expires });
3729 return id;
3730 },
3731 async readData(id) {
3732 if (map.has(id)) {
3733 let { data: data2, expires } = map.get(id);
3734 if (!expires || expires > /* @__PURE__ */ new Date()) {
3735 return data2;
3736 }
3737 if (expires) map.delete(id);
3738 }
3739 return null;
3740 },
3741 async updateData(id, data2, expires) {
3742 map.set(id, { data: data2, expires });
3743 },
3744 async deleteData(id) {
3745 map.delete(id);
3746 }
3747 });
3748}
3749
3750export { Await, RouterContextProvider, createContext, createCookie, createCookieSessionStorage, createMemorySessionStorage, createSession, createSessionStorage, createStaticHandler, data, href, isCookie, isRouteErrorResponse, isSession, matchRoutes, redirect2 as redirect, redirectDocument2 as redirectDocument, replace2 as replace, getRequest as unstable_getRequest, matchRSCServerRequest as unstable_matchRSCServerRequest };