UNPKG

80.1 kBJavaScriptView Raw
1/**
2 * react-router v7.15.0
3 *
4 * Copyright (c) Remix Software Inc.
5 *
6 * This source code is licensed under the MIT license found in the
7 * LICENSE.md file in the root directory of this source tree.
8 *
9 * @license MIT
10 */
11import {
12 ENABLE_DEV_WARNINGS,
13 ErrorResponseImpl,
14 FrameworkContext,
15 NO_BODY_STATUS_CODES,
16 Outlet,
17 RSCRouterContext,
18 RemixErrorBoundary,
19 RouterContextProvider,
20 RouterProvider,
21 SINGLE_FETCH_REDIRECT_STATUS,
22 SingleFetchRedirectSymbol,
23 StaticRouterProvider,
24 StreamTransfer,
25 URL_LIMIT,
26 convertRoutesToDataRoutes,
27 createMemoryRouter,
28 createServerRoutes,
29 createStaticHandler,
30 createStaticRouter,
31 decodeRedirectErrorDigest,
32 decodeRouteErrorResponseDigest,
33 decodeViaTurboStream,
34 encode,
35 escapeHtml,
36 getManifestPath,
37 getStaticContextFromError,
38 instrumentHandler,
39 isDataWithResponseInit,
40 isRedirectResponse,
41 isRedirectStatusCode,
42 isResponse,
43 isRouteErrorResponse,
44 matchRoutes,
45 matchRoutesImpl,
46 redirect,
47 redirectDocument,
48 replace,
49 shouldHydrateRouteLoader,
50 stripBasename,
51 useRouteError,
52 warnOnce,
53 withComponentProps,
54 withErrorBoundaryProps,
55 withHydrateFallbackProps
56} from "./chunk-5KNZJZUH.mjs";
57
58// lib/dom/ssr/server.tsx
59import * as React from "react";
60function ServerRouter({
61 context,
62 url,
63 nonce
64}) {
65 if (typeof url === "string") {
66 url = new URL(url);
67 }
68 let { manifest, routeModules, criticalCss, serverHandoffString } = context;
69 let routes = createServerRoutes(
70 manifest.routes,
71 routeModules,
72 context.future,
73 context.isSpaMode
74 );
75 context.staticHandlerContext.loaderData = {
76 ...context.staticHandlerContext.loaderData
77 };
78 for (let match of context.staticHandlerContext.matches) {
79 let routeId = match.route.id;
80 let route = routeModules[routeId];
81 let manifestRoute = context.manifest.routes[routeId];
82 if (route && manifestRoute && shouldHydrateRouteLoader(
83 routeId,
84 route.clientLoader,
85 manifestRoute.hasLoader,
86 context.isSpaMode
87 ) && (route.HydrateFallback || !manifestRoute.hasLoader)) {
88 delete context.staticHandlerContext.loaderData[routeId];
89 }
90 }
91 let router = createStaticRouter(routes, context.staticHandlerContext, {
92 branches: context.branches
93 });
94 return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(
95 FrameworkContext.Provider,
96 {
97 value: {
98 manifest,
99 routeModules,
100 criticalCss,
101 serverHandoffString,
102 future: context.future,
103 ssr: context.ssr,
104 isSpaMode: context.isSpaMode,
105 routeDiscovery: context.routeDiscovery,
106 serializeError: context.serializeError,
107 renderMeta: context.renderMeta
108 }
109 },
110 /* @__PURE__ */ React.createElement(RemixErrorBoundary, { location: router.state.location }, /* @__PURE__ */ React.createElement(
111 StaticRouterProvider,
112 {
113 router,
114 context: context.staticHandlerContext,
115 hydrate: false
116 }
117 ))
118 ), context.serverHandoffStream ? /* @__PURE__ */ React.createElement(React.Suspense, null, /* @__PURE__ */ React.createElement(
119 StreamTransfer,
120 {
121 context,
122 identifier: 0,
123 reader: context.serverHandoffStream.getReader(),
124 textDecoder: new TextDecoder(),
125 nonce
126 }
127 )) : null);
128}
129
130// lib/dom/ssr/routes-test-stub.tsx
131import * as React2 from "react";
132function createRoutesStub(routes, _context) {
133 return function RoutesTestStub({
134 initialEntries,
135 initialIndex,
136 hydrationData,
137 future
138 }) {
139 let routerRef = React2.useRef();
140 let frameworkContextRef = React2.useRef();
141 if (routerRef.current == null) {
142 frameworkContextRef.current = {
143 future: {
144 v8_passThroughRequests: future?.v8_passThroughRequests === true,
145 v8_middleware: future?.v8_middleware === true,
146 unstable_trailingSlashAwareDataRequests: future?.unstable_trailingSlashAwareDataRequests === true
147 },
148 manifest: {
149 routes: {},
150 entry: { imports: [], module: "" },
151 url: "",
152 version: ""
153 },
154 routeModules: {},
155 ssr: false,
156 isSpaMode: false,
157 routeDiscovery: { mode: "lazy", manifestPath: "/__manifest" }
158 };
159 let patched = processRoutes(
160 // @ts-expect-error `StubRouteObject` is stricter about `loader`/`action`
161 // types compared to `RouteObject`
162 convertRoutesToDataRoutes(routes, (r) => r),
163 _context !== void 0 ? _context : future?.v8_middleware ? new RouterContextProvider() : {},
164 frameworkContextRef.current.manifest,
165 frameworkContextRef.current.routeModules
166 );
167 routerRef.current = createMemoryRouter(patched, {
168 initialEntries,
169 initialIndex,
170 hydrationData
171 });
172 }
173 return /* @__PURE__ */ React2.createElement(FrameworkContext.Provider, { value: frameworkContextRef.current }, /* @__PURE__ */ React2.createElement(RouterProvider, { router: routerRef.current }));
174 };
175}
176function processRoutes(routes, context, manifest, routeModules, parentId) {
177 return routes.map((route) => {
178 if (!route.id) {
179 throw new Error(
180 "Expected a route.id in react-router processRoutes() function"
181 );
182 }
183 let newRoute = {
184 id: route.id,
185 path: route.path,
186 index: route.index,
187 Component: route.Component ? withComponentProps(route.Component) : void 0,
188 HydrateFallback: route.HydrateFallback ? withHydrateFallbackProps(route.HydrateFallback) : void 0,
189 ErrorBoundary: route.ErrorBoundary ? withErrorBoundaryProps(route.ErrorBoundary) : void 0,
190 action: route.action ? (args) => route.action({ ...args, context }) : void 0,
191 loader: route.loader ? (args) => route.loader({ ...args, context }) : void 0,
192 middleware: route.middleware ? route.middleware.map(
193 (mw) => (...args) => mw(
194 { ...args[0], context },
195 args[1]
196 )
197 ) : void 0,
198 handle: route.handle,
199 shouldRevalidate: route.shouldRevalidate
200 };
201 let entryRoute = {
202 id: route.id,
203 path: route.path,
204 index: route.index,
205 parentId,
206 hasAction: route.action != null,
207 hasLoader: route.loader != null,
208 // When testing routes, you should be stubbing loader/action/middleware,
209 // not trying to re-implement the full loader/clientLoader/SSR/hydration
210 // flow. That is better tested via E2E tests.
211 hasClientAction: false,
212 hasClientLoader: false,
213 hasClientMiddleware: false,
214 hasErrorBoundary: route.ErrorBoundary != null,
215 // any need for these?
216 module: "build/stub-path-to-module.js",
217 clientActionModule: void 0,
218 clientLoaderModule: void 0,
219 clientMiddlewareModule: void 0,
220 hydrateFallbackModule: void 0
221 };
222 manifest.routes[newRoute.id] = entryRoute;
223 routeModules[route.id] = {
224 default: newRoute.Component || Outlet,
225 ErrorBoundary: newRoute.ErrorBoundary || void 0,
226 handle: route.handle,
227 links: route.links,
228 meta: route.meta,
229 shouldRevalidate: route.shouldRevalidate
230 };
231 if (route.children) {
232 newRoute.children = processRoutes(
233 route.children,
234 context,
235 manifest,
236 routeModules,
237 newRoute.id
238 );
239 }
240 return newRoute;
241 });
242}
243
244// lib/server-runtime/cookies.ts
245import { parse, serialize } from "cookie";
246
247// lib/server-runtime/crypto.ts
248var encoder = /* @__PURE__ */ new TextEncoder();
249var sign = async (value, secret) => {
250 let data2 = encoder.encode(value);
251 let key = await createKey(secret, ["sign"]);
252 let signature = await crypto.subtle.sign("HMAC", key, data2);
253 let hash = btoa(String.fromCharCode(...new Uint8Array(signature))).replace(
254 /=+$/,
255 ""
256 );
257 return value + "." + hash;
258};
259var unsign = async (cookie, secret) => {
260 let index = cookie.lastIndexOf(".");
261 let value = cookie.slice(0, index);
262 let hash = cookie.slice(index + 1);
263 let data2 = encoder.encode(value);
264 let key = await createKey(secret, ["verify"]);
265 try {
266 let signature = byteStringToUint8Array(atob(hash));
267 let valid = await crypto.subtle.verify("HMAC", key, signature, data2);
268 return valid ? value : false;
269 } catch (error) {
270 return false;
271 }
272};
273var createKey = async (secret, usages) => crypto.subtle.importKey(
274 "raw",
275 encoder.encode(secret),
276 { name: "HMAC", hash: "SHA-256" },
277 false,
278 usages
279);
280function byteStringToUint8Array(byteString) {
281 let array = new Uint8Array(byteString.length);
282 for (let i = 0; i < byteString.length; i++) {
283 array[i] = byteString.charCodeAt(i);
284 }
285 return array;
286}
287
288// lib/server-runtime/cookies.ts
289var createCookie = (name, cookieOptions = {}) => {
290 let { secrets = [], ...options } = {
291 path: "/",
292 sameSite: "lax",
293 ...cookieOptions
294 };
295 warnOnceAboutExpiresCookie(name, options.expires);
296 return {
297 get name() {
298 return name;
299 },
300 get isSigned() {
301 return secrets.length > 0;
302 },
303 get expires() {
304 return typeof options.maxAge !== "undefined" ? new Date(Date.now() + options.maxAge * 1e3) : options.expires;
305 },
306 async parse(cookieHeader, parseOptions) {
307 if (!cookieHeader) return null;
308 let cookies = parse(cookieHeader, { ...options, ...parseOptions });
309 if (name in cookies) {
310 let value = cookies[name];
311 if (typeof value === "string" && value !== "") {
312 let decoded = await decodeCookieValue(value, secrets);
313 return decoded;
314 } else {
315 return "";
316 }
317 } else {
318 return null;
319 }
320 },
321 async serialize(value, serializeOptions) {
322 return serialize(
323 name,
324 value === "" ? "" : await encodeCookieValue(value, secrets),
325 {
326 ...options,
327 ...serializeOptions
328 }
329 );
330 }
331 };
332};
333var isCookie = (object) => {
334 return object != null && typeof object.name === "string" && typeof object.isSigned === "boolean" && typeof object.parse === "function" && typeof object.serialize === "function";
335};
336async function encodeCookieValue(value, secrets) {
337 let encoded = encodeData(value);
338 if (secrets.length > 0) {
339 encoded = await sign(encoded, secrets[0]);
340 }
341 return encoded;
342}
343async function decodeCookieValue(value, secrets) {
344 if (secrets.length > 0) {
345 for (let secret of secrets) {
346 let unsignedValue = await unsign(value, secret);
347 if (unsignedValue !== false) {
348 return decodeData(unsignedValue);
349 }
350 }
351 return null;
352 }
353 return decodeData(value);
354}
355function encodeData(value) {
356 return btoa(myUnescape(encodeURIComponent(JSON.stringify(value))));
357}
358function decodeData(value) {
359 try {
360 return JSON.parse(decodeURIComponent(myEscape(atob(value))));
361 } catch (error) {
362 return {};
363 }
364}
365function myEscape(value) {
366 let str = value.toString();
367 let result = "";
368 let index = 0;
369 let chr, code;
370 while (index < str.length) {
371 chr = str.charAt(index++);
372 if (/[\w*+\-./@]/.exec(chr)) {
373 result += chr;
374 } else {
375 code = chr.charCodeAt(0);
376 if (code < 256) {
377 result += "%" + hex(code, 2);
378 } else {
379 result += "%u" + hex(code, 4).toUpperCase();
380 }
381 }
382 }
383 return result;
384}
385function hex(code, length) {
386 let result = code.toString(16);
387 while (result.length < length) result = "0" + result;
388 return result;
389}
390function myUnescape(value) {
391 let str = value.toString();
392 let result = "";
393 let index = 0;
394 let chr, part;
395 while (index < str.length) {
396 chr = str.charAt(index++);
397 if (chr === "%") {
398 if (str.charAt(index) === "u") {
399 part = str.slice(index + 1, index + 5);
400 if (/^[\da-f]{4}$/i.exec(part)) {
401 result += String.fromCharCode(parseInt(part, 16));
402 index += 5;
403 continue;
404 }
405 } else {
406 part = str.slice(index, index + 2);
407 if (/^[\da-f]{2}$/i.exec(part)) {
408 result += String.fromCharCode(parseInt(part, 16));
409 index += 2;
410 continue;
411 }
412 }
413 }
414 result += chr;
415 }
416 return result;
417}
418function warnOnceAboutExpiresCookie(name, expires) {
419 warnOnce(
420 !expires,
421 `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.`
422 );
423}
424
425// lib/server-runtime/entry.ts
426function createEntryRouteModules(manifest) {
427 return Object.keys(manifest).reduce((memo, routeId) => {
428 let route = manifest[routeId];
429 if (route) {
430 memo[routeId] = route.module;
431 }
432 return memo;
433 }, {});
434}
435
436// lib/server-runtime/mode.ts
437var ServerMode = /* @__PURE__ */ ((ServerMode2) => {
438 ServerMode2["Development"] = "development";
439 ServerMode2["Production"] = "production";
440 ServerMode2["Test"] = "test";
441 return ServerMode2;
442})(ServerMode || {});
443function isServerMode(value) {
444 return value === "development" /* Development */ || value === "production" /* Production */ || value === "test" /* Test */;
445}
446
447// lib/server-runtime/errors.ts
448function sanitizeError(error, serverMode) {
449 if (error instanceof Error && serverMode !== "development" /* Development */) {
450 let sanitized = new Error("Unexpected Server Error");
451 sanitized.stack = void 0;
452 return sanitized;
453 }
454 return error;
455}
456function sanitizeErrors(errors, serverMode) {
457 return Object.entries(errors).reduce((acc, [routeId, error]) => {
458 return Object.assign(acc, { [routeId]: sanitizeError(error, serverMode) });
459 }, {});
460}
461function serializeError(error, serverMode) {
462 let sanitized = sanitizeError(error, serverMode);
463 return {
464 message: sanitized.message,
465 stack: sanitized.stack
466 };
467}
468function serializeErrors(errors, serverMode) {
469 if (!errors) return null;
470 let entries = Object.entries(errors);
471 let serialized = {};
472 for (let [key, val] of entries) {
473 if (isRouteErrorResponse(val)) {
474 serialized[key] = { ...val, __type: "RouteErrorResponse" };
475 } else if (val instanceof Error) {
476 let sanitized = sanitizeError(val, serverMode);
477 serialized[key] = {
478 message: sanitized.message,
479 stack: sanitized.stack,
480 __type: "Error",
481 // If this is a subclass (i.e., ReferenceError), send up the type so we
482 // can re-create the same type during hydration. This will only apply
483 // in dev mode since all production errors are sanitized to normal
484 // Error instances
485 ...sanitized.name !== "Error" ? {
486 __subType: sanitized.name
487 } : {}
488 };
489 } else {
490 serialized[key] = val;
491 }
492 }
493 return serialized;
494}
495
496// lib/server-runtime/invariant.ts
497function invariant(value, message) {
498 if (value === false || value === null || typeof value === "undefined") {
499 console.error(
500 "The following error is a bug in React Router; please open an issue! https://github.com/remix-run/react-router/issues/new/choose"
501 );
502 throw new Error(message);
503 }
504}
505
506// lib/server-runtime/routeMatching.ts
507function matchServerRoutes(manifest, dataRoutes, branches, pathname, basename) {
508 let matches = matchRoutesImpl(
509 dataRoutes,
510 pathname,
511 basename ?? "/",
512 false,
513 branches
514 );
515 if (!matches) return null;
516 return matches.map((match) => {
517 let route = manifest[match.route.id];
518 invariant(
519 route,
520 `Route with id "${match.route.id}" not found in manifest.`
521 );
522 return {
523 params: match.params,
524 pathname: match.pathname,
525 route
526 };
527 });
528}
529
530// lib/server-runtime/data.ts
531async function callRouteHandler(handler, args, future) {
532 let result = await handler({
533 request: future.v8_passThroughRequests ? args.request : stripRoutesParam(stripIndexParam(args.request)),
534 url: args.url,
535 params: args.params,
536 context: args.context,
537 pattern: args.pattern
538 });
539 if (isDataWithResponseInit(result) && result.init && result.init.status && isRedirectStatusCode(result.init.status)) {
540 throw new Response(null, result.init);
541 }
542 return result;
543}
544function stripIndexParam(request) {
545 let url = new URL(request.url);
546 let indexValues = url.searchParams.getAll("index");
547 url.searchParams.delete("index");
548 let indexValuesToKeep = [];
549 for (let indexValue of indexValues) {
550 if (indexValue) {
551 indexValuesToKeep.push(indexValue);
552 }
553 }
554 for (let toKeep of indexValuesToKeep) {
555 url.searchParams.append("index", toKeep);
556 }
557 let init = {
558 method: request.method,
559 body: request.body,
560 headers: request.headers,
561 signal: request.signal
562 };
563 if (init.body) {
564 init.duplex = "half";
565 }
566 return new Request(url.href, init);
567}
568function stripRoutesParam(request) {
569 let url = new URL(request.url);
570 url.searchParams.delete("_routes");
571 let init = {
572 method: request.method,
573 body: request.body,
574 headers: request.headers,
575 signal: request.signal
576 };
577 if (init.body) {
578 init.duplex = "half";
579 }
580 return new Request(url.href, init);
581}
582
583// lib/server-runtime/dev.ts
584var globalDevServerHooksKey = "__reactRouterDevServerHooks";
585function setDevServerHooks(devServerHooks) {
586 globalThis[globalDevServerHooksKey] = devServerHooks;
587}
588function getDevServerHooks() {
589 return globalThis[globalDevServerHooksKey];
590}
591function getBuildTimeHeader(request, headerName) {
592 if (typeof process !== "undefined") {
593 try {
594 if (process.env.hasOwnProperty("IS_RR_BUILD_REQUEST") && process.env.IS_RR_BUILD_REQUEST === "yes") {
595 return request.headers.get(headerName);
596 }
597 } catch (e) {
598 }
599 }
600 return null;
601}
602
603// lib/server-runtime/routes.ts
604function groupRoutesByParentId(manifest) {
605 let routes = {};
606 Object.values(manifest).forEach((route) => {
607 if (route) {
608 let parentId = route.parentId || "";
609 if (!routes[parentId]) {
610 routes[parentId] = [];
611 }
612 routes[parentId].push(route);
613 }
614 });
615 return routes;
616}
617function createStaticHandlerDataRoutes(manifest, future, parentId = "", routesByParentId = groupRoutesByParentId(manifest)) {
618 return (routesByParentId[parentId] || []).map((route) => {
619 let commonRoute = {
620 // Always include root due to default boundaries
621 hasErrorBoundary: route.id === "root" || route.module.ErrorBoundary != null,
622 id: route.id,
623 path: route.path,
624 middleware: route.module.middleware,
625 // Need to use RR's version in the param typed here to permit the optional
626 // context even though we know it'll always be provided in remix
627 loader: route.module.loader ? async (args) => {
628 let preRenderedData = getBuildTimeHeader(
629 args.request,
630 "X-React-Router-Prerender-Data"
631 );
632 if (preRenderedData != null) {
633 let encoded = preRenderedData ? decodeURI(preRenderedData) : preRenderedData;
634 invariant(encoded, "Missing prerendered data for route");
635 let uint8array = new TextEncoder().encode(encoded);
636 let stream = new ReadableStream({
637 start(controller) {
638 controller.enqueue(uint8array);
639 controller.close();
640 }
641 });
642 let decoded = await decodeViaTurboStream(stream, global);
643 let data2 = decoded.value;
644 if (data2 && SingleFetchRedirectSymbol in data2) {
645 let result = data2[SingleFetchRedirectSymbol];
646 let init = { status: result.status };
647 if (result.reload) {
648 throw redirectDocument(result.redirect, init);
649 } else if (result.replace) {
650 throw replace(result.redirect, init);
651 } else {
652 throw redirect(result.redirect, init);
653 }
654 } else {
655 invariant(
656 data2 && route.id in data2,
657 "Unable to decode prerendered data"
658 );
659 let result = data2[route.id];
660 invariant(
661 "data" in result,
662 "Unable to process prerendered data"
663 );
664 return result.data;
665 }
666 }
667 let val = await callRouteHandler(
668 route.module.loader,
669 args,
670 future
671 );
672 return val;
673 } : void 0,
674 action: route.module.action ? (args) => callRouteHandler(route.module.action, args, future) : void 0,
675 handle: route.module.handle
676 };
677 return route.index ? {
678 index: true,
679 ...commonRoute
680 } : {
681 caseSensitive: route.caseSensitive,
682 children: createStaticHandlerDataRoutes(
683 manifest,
684 future,
685 route.id,
686 routesByParentId
687 ),
688 ...commonRoute
689 };
690 });
691}
692
693// lib/server-runtime/serverHandoff.ts
694function createServerHandoffString(serverHandoff) {
695 return escapeHtml(JSON.stringify(serverHandoff));
696}
697
698// lib/server-runtime/headers.ts
699import { splitCookiesString } from "set-cookie-parser";
700function getDocumentHeaders(context, build) {
701 return getDocumentHeadersImpl(context, (m) => {
702 let route = build.routes[m.route.id];
703 invariant(route, `Route with id "${m.route.id}" not found in build`);
704 return route.module.headers;
705 });
706}
707function getDocumentHeadersImpl(context, getRouteHeadersFn, _defaultHeaders) {
708 let boundaryIdx = context.errors ? context.matches.findIndex((m) => context.errors[m.route.id]) : -1;
709 let matches = boundaryIdx >= 0 ? context.matches.slice(0, boundaryIdx + 1) : context.matches;
710 let errorHeaders;
711 if (boundaryIdx >= 0) {
712 let { actionHeaders, actionData, loaderHeaders, loaderData } = context;
713 context.matches.slice(boundaryIdx).some((match) => {
714 let id = match.route.id;
715 if (actionHeaders[id] && (!actionData || !actionData.hasOwnProperty(id))) {
716 errorHeaders = actionHeaders[id];
717 } else if (loaderHeaders[id] && !loaderData.hasOwnProperty(id)) {
718 errorHeaders = loaderHeaders[id];
719 }
720 return errorHeaders != null;
721 });
722 }
723 const defaultHeaders = new Headers(_defaultHeaders);
724 return matches.reduce((parentHeaders, match, idx) => {
725 let { id } = match.route;
726 let loaderHeaders = context.loaderHeaders[id] || new Headers();
727 let actionHeaders = context.actionHeaders[id] || new Headers();
728 let includeErrorHeaders = errorHeaders != null && idx === matches.length - 1;
729 let includeErrorCookies = includeErrorHeaders && errorHeaders !== loaderHeaders && errorHeaders !== actionHeaders;
730 let headersFn = getRouteHeadersFn(match);
731 if (headersFn == null) {
732 let headers2 = new Headers(parentHeaders);
733 if (includeErrorCookies) {
734 prependCookies(errorHeaders, headers2);
735 }
736 prependCookies(actionHeaders, headers2);
737 prependCookies(loaderHeaders, headers2);
738 return headers2;
739 }
740 let headers = new Headers(
741 typeof headersFn === "function" ? headersFn({
742 loaderHeaders,
743 parentHeaders,
744 actionHeaders,
745 errorHeaders: includeErrorHeaders ? errorHeaders : void 0
746 }) : headersFn
747 );
748 if (includeErrorCookies) {
749 prependCookies(errorHeaders, headers);
750 }
751 prependCookies(actionHeaders, headers);
752 prependCookies(loaderHeaders, headers);
753 prependCookies(parentHeaders, headers);
754 return headers;
755 }, new Headers(defaultHeaders));
756}
757function prependCookies(parentHeaders, childHeaders) {
758 let parentSetCookieString = parentHeaders.get("Set-Cookie");
759 if (parentSetCookieString) {
760 let cookies = splitCookiesString(parentSetCookieString);
761 let childCookies = new Set(childHeaders.getSetCookie());
762 cookies.forEach((cookie) => {
763 if (!childCookies.has(cookie)) {
764 childHeaders.append("Set-Cookie", cookie);
765 }
766 });
767 }
768}
769
770// lib/actions.ts
771function throwIfPotentialCSRFAttack(headers, allowedActionOrigins) {
772 let originHeader = headers.get("origin");
773 let originDomain = null;
774 try {
775 originDomain = typeof originHeader === "string" && originHeader !== "null" ? new URL(originHeader).host : originHeader;
776 } catch {
777 throw new Error(
778 `\`origin\` header is not a valid URL. Aborting the action.`
779 );
780 }
781 let host = parseHostHeader(headers);
782 if (originDomain && (!host || originDomain !== host.value)) {
783 if (!isAllowedOrigin(originDomain, allowedActionOrigins)) {
784 if (host) {
785 throw new Error(
786 `${host.type} header does not match \`origin\` header from a forwarded action request. Aborting the action.`
787 );
788 } else {
789 throw new Error(
790 "`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."
791 );
792 }
793 }
794 }
795}
796function matchWildcardDomain(domain, pattern) {
797 const domainParts = domain.split(".");
798 const patternParts = pattern.split(".");
799 if (patternParts.length < 1) {
800 return false;
801 }
802 if (domainParts.length < patternParts.length) {
803 return false;
804 }
805 while (patternParts.length) {
806 const patternPart = patternParts.pop();
807 const domainPart = domainParts.pop();
808 switch (patternPart) {
809 case "": {
810 return false;
811 }
812 case "*": {
813 if (domainPart) {
814 continue;
815 } else {
816 return false;
817 }
818 }
819 case "**": {
820 if (patternParts.length > 0) {
821 return false;
822 }
823 return domainPart !== void 0;
824 }
825 case void 0:
826 default: {
827 if (domainPart !== patternPart) {
828 return false;
829 }
830 }
831 }
832 }
833 return domainParts.length === 0;
834}
835function isAllowedOrigin(originDomain, allowedActionOrigins = []) {
836 return allowedActionOrigins.some(
837 (allowedOrigin) => allowedOrigin && (allowedOrigin === originDomain || matchWildcardDomain(originDomain, allowedOrigin))
838 );
839}
840function parseHostHeader(headers) {
841 let forwardedHostHeader = headers.get("x-forwarded-host");
842 let forwardedHostValue = forwardedHostHeader?.split(",")[0]?.trim();
843 let hostHeader = headers.get("host");
844 return forwardedHostValue ? {
845 type: "x-forwarded-host",
846 value: forwardedHostValue
847 } : hostHeader ? {
848 type: "host",
849 value: hostHeader
850 } : void 0;
851}
852
853// lib/server-runtime/urls.ts
854function getNormalizedPath(request, basename, future) {
855 basename = basename || "/";
856 let url = new URL(request.url);
857 let pathname = url.pathname;
858 if (future?.unstable_trailingSlashAwareDataRequests) {
859 if (pathname.endsWith("/_.data")) {
860 pathname = pathname.replace(/_\.data$/, "");
861 } else {
862 pathname = pathname.replace(/\.data$/, "");
863 }
864 } else {
865 if (stripBasename(pathname, basename) === "/_root.data") {
866 pathname = basename;
867 } else if (pathname.endsWith(".data")) {
868 pathname = pathname.replace(/\.data$/, "");
869 }
870 if (stripBasename(pathname, basename) !== "/" && pathname.endsWith("/")) {
871 pathname = pathname.slice(0, -1);
872 }
873 }
874 let searchParams = new URLSearchParams(url.search);
875 searchParams.delete("_routes");
876 let search = searchParams.toString();
877 if (search) {
878 search = `?${search}`;
879 }
880 return {
881 pathname,
882 search,
883 // No hashes on the server
884 hash: ""
885 };
886}
887
888// lib/server-runtime/single-fetch.ts
889var SERVER_NO_BODY_STATUS_CODES = /* @__PURE__ */ new Set([
890 ...NO_BODY_STATUS_CODES,
891 304
892]);
893async function singleFetchAction(build, serverMode, staticHandler, request, handlerUrl, loadContext, handleError) {
894 try {
895 try {
896 throwIfPotentialCSRFAttack(
897 request.headers,
898 Array.isArray(build.allowedActionOrigins) ? build.allowedActionOrigins : []
899 );
900 } catch (e) {
901 return handleQueryError(new Error("Bad Request"), 400);
902 }
903 let handlerRequest = build.future.v8_passThroughRequests ? request : new Request(handlerUrl, {
904 method: request.method,
905 body: request.body,
906 headers: request.headers,
907 signal: request.signal,
908 ...request.body ? { duplex: "half" } : void 0
909 });
910 let result = await staticHandler.query(handlerRequest, {
911 requestContext: loadContext,
912 skipLoaderErrorBubbling: true,
913 skipRevalidation: true,
914 generateMiddlewareResponse: build.future.v8_middleware ? async (query) => {
915 try {
916 let innerResult = await query(handlerRequest);
917 return handleQueryResult(innerResult);
918 } catch (error) {
919 return handleQueryError(error);
920 }
921 } : void 0,
922 normalizePath: (r) => getNormalizedPath(r, build.basename, build.future)
923 });
924 return handleQueryResult(result);
925 } catch (error) {
926 return handleQueryError(error);
927 }
928 function handleQueryResult(result) {
929 return isResponse(result) ? result : staticContextToResponse(result);
930 }
931 function handleQueryError(error, status = 500) {
932 handleError(error);
933 return generateSingleFetchResponse(request, build, serverMode, {
934 result: { error },
935 headers: new Headers(),
936 status
937 });
938 }
939 function staticContextToResponse(context) {
940 let headers = getDocumentHeaders(context, build);
941 if (isRedirectStatusCode(context.statusCode) && headers.has("Location")) {
942 return new Response(null, { status: context.statusCode, headers });
943 }
944 if (context.errors) {
945 Object.values(context.errors).forEach((err) => {
946 if (!isRouteErrorResponse(err) || err.error) {
947 handleError(err);
948 }
949 });
950 context.errors = sanitizeErrors(context.errors, serverMode);
951 }
952 let singleFetchResult;
953 if (context.errors) {
954 singleFetchResult = { error: Object.values(context.errors)[0] };
955 } else {
956 singleFetchResult = {
957 data: Object.values(context.actionData || {})[0]
958 };
959 }
960 return generateSingleFetchResponse(request, build, serverMode, {
961 result: singleFetchResult,
962 headers,
963 status: context.statusCode
964 });
965 }
966}
967async function singleFetchLoaders(build, serverMode, staticHandler, request, handlerUrl, loadContext, handleError) {
968 let routesParam = new URL(request.url).searchParams.get("_routes");
969 let loadRouteIds = routesParam ? new Set(routesParam.split(",")) : null;
970 try {
971 let handlerRequest = build.future.v8_passThroughRequests ? request : new Request(handlerUrl, {
972 headers: request.headers,
973 signal: request.signal
974 });
975 let result = await staticHandler.query(handlerRequest, {
976 requestContext: loadContext,
977 filterMatchesToLoad: (m) => !loadRouteIds || loadRouteIds.has(m.route.id),
978 skipLoaderErrorBubbling: true,
979 generateMiddlewareResponse: build.future.v8_middleware ? async (query) => {
980 try {
981 let innerResult = await query(handlerRequest);
982 return handleQueryResult(innerResult);
983 } catch (error) {
984 return handleQueryError(error);
985 }
986 } : void 0,
987 normalizePath: (r) => getNormalizedPath(r, build.basename, build.future)
988 });
989 return handleQueryResult(result);
990 } catch (error) {
991 return handleQueryError(error);
992 }
993 function handleQueryResult(result) {
994 return isResponse(result) ? result : staticContextToResponse(result);
995 }
996 function handleQueryError(error) {
997 handleError(error);
998 return generateSingleFetchResponse(request, build, serverMode, {
999 result: { error },
1000 headers: new Headers(),
1001 status: 500
1002 });
1003 }
1004 function staticContextToResponse(context) {
1005 let headers = getDocumentHeaders(context, build);
1006 if (isRedirectStatusCode(context.statusCode) && headers.has("Location")) {
1007 return new Response(null, { status: context.statusCode, headers });
1008 }
1009 if (context.errors) {
1010 Object.values(context.errors).forEach((err) => {
1011 if (!isRouteErrorResponse(err) || err.error) {
1012 handleError(err);
1013 }
1014 });
1015 context.errors = sanitizeErrors(context.errors, serverMode);
1016 }
1017 let results = {};
1018 let loadedMatches = new Set(
1019 context.matches.filter(
1020 (m) => loadRouteIds ? loadRouteIds.has(m.route.id) : m.route.loader != null
1021 ).map((m) => m.route.id)
1022 );
1023 if (context.errors) {
1024 for (let [id, error] of Object.entries(context.errors)) {
1025 results[id] = { error };
1026 }
1027 }
1028 for (let [id, data2] of Object.entries(context.loaderData)) {
1029 if (!(id in results) && loadedMatches.has(id)) {
1030 results[id] = { data: data2 };
1031 }
1032 }
1033 return generateSingleFetchResponse(request, build, serverMode, {
1034 result: results,
1035 headers,
1036 status: context.statusCode
1037 });
1038 }
1039}
1040function generateSingleFetchResponse(request, build, serverMode, {
1041 result,
1042 headers,
1043 status
1044}) {
1045 let resultHeaders = new Headers(headers);
1046 resultHeaders.set("X-Remix-Response", "yes");
1047 if (SERVER_NO_BODY_STATUS_CODES.has(status)) {
1048 return new Response(null, { status, headers: resultHeaders });
1049 }
1050 resultHeaders.set("Content-Type", "text/x-script");
1051 resultHeaders.delete("Content-Length");
1052 return new Response(
1053 encodeViaTurboStream(
1054 result,
1055 request.signal,
1056 build.entry.module.streamTimeout,
1057 serverMode
1058 ),
1059 {
1060 status: status || 200,
1061 headers: resultHeaders
1062 }
1063 );
1064}
1065function generateSingleFetchRedirectResponse(redirectResponse, request, build, serverMode) {
1066 let redirect2 = getSingleFetchRedirect(
1067 redirectResponse.status,
1068 redirectResponse.headers,
1069 build.basename
1070 );
1071 let headers = new Headers(redirectResponse.headers);
1072 headers.delete("Location");
1073 headers.set("Content-Type", "text/x-script");
1074 return generateSingleFetchResponse(request, build, serverMode, {
1075 result: request.method === "GET" ? { [SingleFetchRedirectSymbol]: redirect2 } : redirect2,
1076 headers,
1077 status: SINGLE_FETCH_REDIRECT_STATUS
1078 });
1079}
1080function getSingleFetchRedirect(status, headers, basename) {
1081 let redirect2 = headers.get("Location");
1082 if (basename) {
1083 redirect2 = stripBasename(redirect2, basename) || redirect2;
1084 }
1085 return {
1086 redirect: redirect2,
1087 status,
1088 revalidate: (
1089 // Technically X-Remix-Revalidate isn't needed here - that was an implementation
1090 // detail of ?_data requests as our way to tell the front end to revalidate when
1091 // we didn't have a response body to include that information in.
1092 // With single fetch, we tell the front end via this revalidate boolean field.
1093 // However, we're respecting it for now because it may be something folks have
1094 // used in their own responses
1095 // TODO(v3): Consider removing or making this official public API
1096 headers.has("X-Remix-Revalidate") || headers.has("Set-Cookie")
1097 ),
1098 reload: headers.has("X-Remix-Reload-Document"),
1099 replace: headers.has("X-Remix-Replace")
1100 };
1101}
1102function encodeViaTurboStream(data2, requestSignal, streamTimeout, serverMode) {
1103 let controller = new AbortController();
1104 let timeoutId = setTimeout(
1105 () => {
1106 controller.abort(new Error("Server Timeout"));
1107 cleanupCallbacks();
1108 },
1109 typeof streamTimeout === "number" ? streamTimeout : 4950
1110 );
1111 let abortControllerOnRequestAbort = () => {
1112 controller.abort(requestSignal.reason);
1113 cleanupCallbacks();
1114 };
1115 requestSignal.addEventListener("abort", abortControllerOnRequestAbort);
1116 let cleanupCallbacks = () => {
1117 clearTimeout(timeoutId);
1118 requestSignal.removeEventListener("abort", abortControllerOnRequestAbort);
1119 };
1120 return encode(data2, {
1121 signal: controller.signal,
1122 onComplete: cleanupCallbacks,
1123 plugins: [
1124 (value) => {
1125 if (value instanceof Error) {
1126 let { name, message, stack } = serverMode === "production" /* Production */ ? sanitizeError(value, serverMode) : value;
1127 return ["SanitizedError", name, message, stack];
1128 }
1129 if (value instanceof ErrorResponseImpl) {
1130 let { data: data3, status, statusText } = value;
1131 return ["ErrorResponse", data3, status, statusText];
1132 }
1133 if (value && typeof value === "object" && SingleFetchRedirectSymbol in value) {
1134 return ["SingleFetchRedirect", value[SingleFetchRedirectSymbol]];
1135 }
1136 }
1137 ],
1138 postPlugins: [
1139 (value) => {
1140 if (!value) return;
1141 if (typeof value !== "object") return;
1142 return [
1143 "SingleFetchClassInstance",
1144 Object.fromEntries(Object.entries(value))
1145 ];
1146 },
1147 () => ["SingleFetchFallback"]
1148 ]
1149 });
1150}
1151
1152// lib/server-runtime/server.ts
1153function derive(build, mode) {
1154 let dataRoutes = createStaticHandlerDataRoutes(build.routes, build.future);
1155 let serverMode = isServerMode(mode) ? mode : "production" /* Production */;
1156 let staticHandler = createStaticHandler(dataRoutes, {
1157 basename: build.basename,
1158 instrumentations: build.entry.module.instrumentations,
1159 future: build.future
1160 });
1161 let errorHandler = build.entry.module.handleError || ((error, { request }) => {
1162 if (serverMode !== "test" /* Test */ && !request.signal.aborted) {
1163 console.error(
1164 // @ts-expect-error This is "private" from users but intended for internal use
1165 isRouteErrorResponse(error) && error.error ? error.error : error
1166 );
1167 }
1168 });
1169 let requestHandler = async (request, initialContext) => {
1170 let params = {};
1171 let loadContext;
1172 let handleError = (error) => {
1173 if (mode === "development" /* Development */) {
1174 getDevServerHooks()?.processRequestError?.(error);
1175 }
1176 errorHandler(error, {
1177 context: loadContext,
1178 params,
1179 request
1180 });
1181 };
1182 if (build.future.v8_middleware) {
1183 if (initialContext && !(initialContext instanceof RouterContextProvider)) {
1184 let error = new Error(
1185 "Invalid `context` value provided to `handleRequest`. When middleware is enabled you must return an instance of `RouterContextProvider` from your `getLoadContext` function."
1186 );
1187 handleError(error);
1188 return returnLastResortErrorResponse(error, serverMode);
1189 }
1190 loadContext = initialContext || new RouterContextProvider();
1191 } else {
1192 loadContext = initialContext || {};
1193 }
1194 let requestUrl = new URL(request.url);
1195 let normalizedPathname = getNormalizedPath(
1196 request,
1197 build.basename,
1198 build.future
1199 ).pathname;
1200 let isSpaMode = getBuildTimeHeader(request, "X-React-Router-SPA-Mode") === "yes";
1201 if (!build.ssr) {
1202 let decodedPath = decodeURI(normalizedPathname);
1203 if (build.basename && build.basename !== "/") {
1204 let strippedPath = stripBasename(decodedPath, build.basename);
1205 if (strippedPath == null) {
1206 errorHandler(
1207 new ErrorResponseImpl(
1208 404,
1209 "Not Found",
1210 `Refusing to prerender the \`${decodedPath}\` path because it does not start with the basename \`${build.basename}\``
1211 ),
1212 {
1213 context: loadContext,
1214 params,
1215 request
1216 }
1217 );
1218 return new Response("Not Found", {
1219 status: 404,
1220 statusText: "Not Found"
1221 });
1222 }
1223 decodedPath = strippedPath;
1224 }
1225 if (build.prerender.length === 0) {
1226 isSpaMode = true;
1227 } else if (!build.prerender.includes(decodedPath) && !build.prerender.includes(decodedPath + "/")) {
1228 if (requestUrl.pathname.endsWith(".data")) {
1229 errorHandler(
1230 new ErrorResponseImpl(
1231 404,
1232 "Not Found",
1233 `Refusing to SSR the path \`${decodedPath}\` because \`ssr:false\` is set and the path is not included in the \`prerender\` config, so in production the path will be a 404.`
1234 ),
1235 {
1236 context: loadContext,
1237 params,
1238 request
1239 }
1240 );
1241 return new Response("Not Found", {
1242 status: 404,
1243 statusText: "Not Found"
1244 });
1245 } else {
1246 isSpaMode = true;
1247 }
1248 }
1249 }
1250 let manifestUrl = getManifestPath(
1251 build.routeDiscovery.manifestPath,
1252 build.basename
1253 );
1254 if (requestUrl.pathname === manifestUrl) {
1255 try {
1256 let res = await handleManifestRequest(
1257 build,
1258 staticHandler.dataRoutes,
1259 staticHandler._internalRouteBranches,
1260 requestUrl
1261 );
1262 return res;
1263 } catch (e) {
1264 handleError(e);
1265 return new Response("Unknown Server Error", { status: 500 });
1266 }
1267 }
1268 let matches = matchServerRoutes(
1269 build.routes,
1270 staticHandler.dataRoutes,
1271 staticHandler._internalRouteBranches,
1272 normalizedPathname,
1273 build.basename
1274 );
1275 if (matches && matches.length > 0) {
1276 Object.assign(params, matches[0].params);
1277 }
1278 let response;
1279 if (requestUrl.pathname.endsWith(".data")) {
1280 response = await handleSingleFetchRequest(
1281 serverMode,
1282 build,
1283 staticHandler,
1284 request,
1285 normalizedPathname,
1286 loadContext,
1287 handleError
1288 );
1289 if (isRedirectResponse(response)) {
1290 response = generateSingleFetchRedirectResponse(
1291 response,
1292 request,
1293 build,
1294 serverMode
1295 );
1296 }
1297 if (build.entry.module.handleDataRequest) {
1298 response = await build.entry.module.handleDataRequest(response, {
1299 context: loadContext,
1300 params: matches ? matches[0].params : {},
1301 request
1302 });
1303 if (isRedirectResponse(response)) {
1304 response = generateSingleFetchRedirectResponse(
1305 response,
1306 request,
1307 build,
1308 serverMode
1309 );
1310 }
1311 }
1312 } else if (!isSpaMode && matches && matches[matches.length - 1].route.module.default == null && matches[matches.length - 1].route.module.ErrorBoundary == null) {
1313 response = await handleResourceRequest(
1314 serverMode,
1315 build,
1316 staticHandler,
1317 matches.slice(-1)[0].route.id,
1318 request,
1319 loadContext,
1320 handleError
1321 );
1322 } else {
1323 let { pathname } = requestUrl;
1324 let criticalCss = void 0;
1325 if (build.unstable_getCriticalCss) {
1326 criticalCss = await build.unstable_getCriticalCss({ pathname });
1327 } else if (mode === "development" /* Development */ && getDevServerHooks()?.getCriticalCss) {
1328 criticalCss = await getDevServerHooks()?.getCriticalCss?.(pathname);
1329 }
1330 response = await handleDocumentRequest(
1331 serverMode,
1332 build,
1333 staticHandler,
1334 request,
1335 loadContext,
1336 handleError,
1337 isSpaMode,
1338 criticalCss
1339 );
1340 }
1341 if (request.method === "HEAD") {
1342 return new Response(null, {
1343 headers: response.headers,
1344 status: response.status,
1345 statusText: response.statusText
1346 });
1347 }
1348 return response;
1349 };
1350 if (build.entry.module.instrumentations) {
1351 requestHandler = instrumentHandler(
1352 requestHandler,
1353 build.entry.module.instrumentations.map((i) => i.handler).filter(Boolean)
1354 );
1355 }
1356 return {
1357 serverMode,
1358 staticHandler,
1359 errorHandler,
1360 requestHandler
1361 };
1362}
1363var createRequestHandler = (build, mode) => {
1364 let _build;
1365 let serverMode;
1366 let staticHandler;
1367 let errorHandler;
1368 let _requestHandler;
1369 return async function requestHandler(request, initialContext) {
1370 _build = typeof build === "function" ? await build() : build;
1371 if (typeof build === "function") {
1372 let derived = derive(_build, mode);
1373 serverMode = derived.serverMode;
1374 staticHandler = derived.staticHandler;
1375 errorHandler = derived.errorHandler;
1376 _requestHandler = derived.requestHandler;
1377 } else if (!serverMode || !staticHandler || !errorHandler || !_requestHandler) {
1378 let derived = derive(_build, mode);
1379 serverMode = derived.serverMode;
1380 staticHandler = derived.staticHandler;
1381 errorHandler = derived.errorHandler;
1382 _requestHandler = derived.requestHandler;
1383 }
1384 return _requestHandler(request, initialContext);
1385 };
1386};
1387async function handleManifestRequest(build, dataRoutes, branches, url) {
1388 if (build.assets.version !== url.searchParams.get("version")) {
1389 return new Response(null, {
1390 status: 204,
1391 headers: {
1392 "X-Remix-Reload-Document": "true"
1393 }
1394 });
1395 }
1396 if (url.toString().length > URL_LIMIT) {
1397 return new Response(null, {
1398 statusText: "Bad Request",
1399 status: 400
1400 });
1401 }
1402 let patches = {};
1403 if (url.searchParams.has("paths")) {
1404 let paths = /* @__PURE__ */ new Set();
1405 let pathParam = url.searchParams.get("paths") || "";
1406 let requestedPaths = pathParam.split(",").filter(Boolean);
1407 requestedPaths.forEach((path) => {
1408 if (!path.startsWith("/")) {
1409 path = `/${path}`;
1410 }
1411 let segments = path.split("/").slice(1);
1412 segments.forEach((_, i) => {
1413 let partialPath = segments.slice(0, i + 1).join("/");
1414 paths.add(`/${partialPath}`);
1415 });
1416 });
1417 for (let path of paths) {
1418 let matches = matchServerRoutes(
1419 build.routes,
1420 dataRoutes,
1421 branches,
1422 path,
1423 build.basename
1424 );
1425 if (matches) {
1426 for (let match of matches) {
1427 let routeId = match.route.id;
1428 let route = build.assets.routes[routeId];
1429 if (route) {
1430 patches[routeId] = route;
1431 }
1432 }
1433 }
1434 }
1435 return Response.json(patches, {
1436 headers: {
1437 "Cache-Control": "public, max-age=31536000, immutable"
1438 }
1439 });
1440 }
1441 return new Response("Invalid Request", { status: 400 });
1442}
1443async function handleSingleFetchRequest(serverMode, build, staticHandler, request, normalizedPath, loadContext, handleError) {
1444 let handlerUrl = new URL(request.url);
1445 handlerUrl.pathname = normalizedPath;
1446 let response = request.method !== "GET" ? await singleFetchAction(
1447 build,
1448 serverMode,
1449 staticHandler,
1450 request,
1451 handlerUrl,
1452 loadContext,
1453 handleError
1454 ) : await singleFetchLoaders(
1455 build,
1456 serverMode,
1457 staticHandler,
1458 request,
1459 handlerUrl,
1460 loadContext,
1461 handleError
1462 );
1463 return response;
1464}
1465async function handleDocumentRequest(serverMode, build, staticHandler, request, loadContext, handleError, isSpaMode, criticalCss) {
1466 try {
1467 if (request.method === "POST") {
1468 try {
1469 throwIfPotentialCSRFAttack(
1470 request.headers,
1471 Array.isArray(build.allowedActionOrigins) ? build.allowedActionOrigins : []
1472 );
1473 } catch (e) {
1474 handleError(e);
1475 return new Response("Bad Request", { status: 400 });
1476 }
1477 }
1478 let result = await staticHandler.query(request, {
1479 requestContext: loadContext,
1480 generateMiddlewareResponse: build.future.v8_middleware ? async (query) => {
1481 try {
1482 let innerResult = await query(request);
1483 if (!isResponse(innerResult)) {
1484 innerResult = await renderHtml(innerResult, isSpaMode);
1485 }
1486 return innerResult;
1487 } catch (error) {
1488 handleError(error);
1489 return new Response(null, { status: 500 });
1490 }
1491 } : void 0,
1492 normalizePath: (r) => getNormalizedPath(r, build.basename, build.future)
1493 });
1494 if (!isResponse(result)) {
1495 result = await renderHtml(result, isSpaMode);
1496 }
1497 return result;
1498 } catch (error) {
1499 handleError(error);
1500 return new Response(null, { status: 500 });
1501 }
1502 async function renderHtml(context, isSpaMode2) {
1503 let headers = getDocumentHeaders(context, build);
1504 if (SERVER_NO_BODY_STATUS_CODES.has(context.statusCode)) {
1505 return new Response(null, { status: context.statusCode, headers });
1506 }
1507 if (context.errors) {
1508 Object.values(context.errors).forEach((err) => {
1509 if (!isRouteErrorResponse(err) || err.error) {
1510 handleError(err);
1511 }
1512 });
1513 context.errors = sanitizeErrors(context.errors, serverMode);
1514 }
1515 let state = {
1516 loaderData: context.loaderData,
1517 actionData: context.actionData,
1518 errors: serializeErrors(context.errors, serverMode)
1519 };
1520 let baseServerHandoff = {
1521 basename: build.basename,
1522 future: build.future,
1523 routeDiscovery: build.routeDiscovery,
1524 ssr: build.ssr,
1525 isSpaMode: isSpaMode2
1526 };
1527 let entryContext = {
1528 manifest: build.assets,
1529 branches: staticHandler._internalRouteBranches,
1530 routeModules: createEntryRouteModules(build.routes),
1531 staticHandlerContext: context,
1532 criticalCss,
1533 serverHandoffString: createServerHandoffString({
1534 ...baseServerHandoff,
1535 criticalCss
1536 }),
1537 serverHandoffStream: encodeViaTurboStream(
1538 state,
1539 request.signal,
1540 build.entry.module.streamTimeout,
1541 serverMode
1542 ),
1543 renderMeta: {},
1544 future: build.future,
1545 ssr: build.ssr,
1546 routeDiscovery: build.routeDiscovery,
1547 isSpaMode: isSpaMode2,
1548 serializeError: (err) => serializeError(err, serverMode)
1549 };
1550 let handleDocumentRequestFunction = build.entry.module.default;
1551 try {
1552 return await handleDocumentRequestFunction(
1553 request,
1554 context.statusCode,
1555 headers,
1556 entryContext,
1557 loadContext
1558 );
1559 } catch (error) {
1560 handleError(error);
1561 let errorForSecondRender = error;
1562 if (isResponse(error)) {
1563 try {
1564 let data2 = await unwrapResponse(error);
1565 errorForSecondRender = new ErrorResponseImpl(
1566 error.status,
1567 error.statusText,
1568 data2
1569 );
1570 } catch (e) {
1571 }
1572 }
1573 context = getStaticContextFromError(
1574 staticHandler.dataRoutes,
1575 context,
1576 errorForSecondRender
1577 );
1578 if (context.errors) {
1579 context.errors = sanitizeErrors(context.errors, serverMode);
1580 }
1581 let state2 = {
1582 loaderData: context.loaderData,
1583 actionData: context.actionData,
1584 errors: serializeErrors(context.errors, serverMode)
1585 };
1586 entryContext = {
1587 ...entryContext,
1588 staticHandlerContext: context,
1589 serverHandoffString: createServerHandoffString(baseServerHandoff),
1590 serverHandoffStream: encodeViaTurboStream(
1591 state2,
1592 request.signal,
1593 build.entry.module.streamTimeout,
1594 serverMode
1595 ),
1596 renderMeta: {}
1597 };
1598 try {
1599 return await handleDocumentRequestFunction(
1600 request,
1601 context.statusCode,
1602 headers,
1603 entryContext,
1604 loadContext
1605 );
1606 } catch (error2) {
1607 handleError(error2);
1608 return returnLastResortErrorResponse(error2, serverMode);
1609 }
1610 }
1611 }
1612}
1613async function handleResourceRequest(serverMode, build, staticHandler, routeId, request, loadContext, handleError) {
1614 try {
1615 let result = await staticHandler.queryRoute(request, {
1616 routeId,
1617 requestContext: loadContext,
1618 generateMiddlewareResponse: build.future.v8_middleware ? async (queryRoute) => {
1619 try {
1620 let innerResult = await queryRoute(request);
1621 return handleQueryRouteResult(innerResult);
1622 } catch (error) {
1623 return handleQueryRouteError(error);
1624 }
1625 } : void 0,
1626 normalizePath: (r) => getNormalizedPath(r, build.basename, build.future)
1627 });
1628 return handleQueryRouteResult(result);
1629 } catch (error) {
1630 return handleQueryRouteError(error);
1631 }
1632 function handleQueryRouteResult(result) {
1633 if (isResponse(result)) {
1634 return result;
1635 }
1636 if (typeof result === "string") {
1637 return new Response(result);
1638 }
1639 return Response.json(result);
1640 }
1641 function handleQueryRouteError(error) {
1642 if (isResponse(error)) {
1643 return error;
1644 }
1645 if (isRouteErrorResponse(error)) {
1646 handleError(error);
1647 return errorResponseToJson(error, serverMode);
1648 }
1649 if (error instanceof Error && error.message === "Expected a response from queryRoute") {
1650 let newError = new Error(
1651 "Expected a Response to be returned from resource route handler"
1652 );
1653 handleError(newError);
1654 return returnLastResortErrorResponse(newError, serverMode);
1655 }
1656 handleError(error);
1657 return returnLastResortErrorResponse(error, serverMode);
1658 }
1659}
1660function errorResponseToJson(errorResponse, serverMode) {
1661 return Response.json(
1662 serializeError(
1663 // @ts-expect-error This is "private" from users but intended for internal use
1664 errorResponse.error || new Error("Unexpected Server Error"),
1665 serverMode
1666 ),
1667 {
1668 status: errorResponse.status,
1669 statusText: errorResponse.statusText
1670 }
1671 );
1672}
1673function returnLastResortErrorResponse(error, serverMode) {
1674 let message = "Unexpected Server Error";
1675 if (serverMode !== "production" /* Production */) {
1676 message += `
1677
1678${String(error)}`;
1679 }
1680 return new Response(message, {
1681 status: 500,
1682 headers: {
1683 "Content-Type": "text/plain"
1684 }
1685 });
1686}
1687function unwrapResponse(response) {
1688 let contentType = response.headers.get("Content-Type");
1689 return contentType && /\bapplication\/json\b/.test(contentType) ? response.body == null ? null : response.json() : response.text();
1690}
1691
1692// lib/server-runtime/sessions.ts
1693function flash(name) {
1694 return `__flash_${name}__`;
1695}
1696var createSession = (initialData = {}, id = "") => {
1697 let map = new Map(Object.entries(initialData));
1698 return {
1699 get id() {
1700 return id;
1701 },
1702 get data() {
1703 return Object.fromEntries(map);
1704 },
1705 has(name) {
1706 return map.has(name) || map.has(flash(name));
1707 },
1708 get(name) {
1709 if (map.has(name)) return map.get(name);
1710 let flashName = flash(name);
1711 if (map.has(flashName)) {
1712 let value = map.get(flashName);
1713 map.delete(flashName);
1714 return value;
1715 }
1716 return void 0;
1717 },
1718 set(name, value) {
1719 map.set(name, value);
1720 },
1721 flash(name, value) {
1722 map.set(flash(name), value);
1723 },
1724 unset(name) {
1725 map.delete(name);
1726 }
1727 };
1728};
1729var isSession = (object) => {
1730 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";
1731};
1732function createSessionStorage({
1733 cookie: cookieArg,
1734 createData,
1735 readData,
1736 updateData,
1737 deleteData
1738}) {
1739 let cookie = isCookie(cookieArg) ? cookieArg : createCookie(cookieArg?.name || "__session", cookieArg);
1740 warnOnceAboutSigningSessionCookie(cookie);
1741 return {
1742 async getSession(cookieHeader, options) {
1743 let id = cookieHeader && await cookie.parse(cookieHeader, options);
1744 let data2 = id && await readData(id);
1745 return createSession(data2 || {}, id || "");
1746 },
1747 async commitSession(session, options) {
1748 let { id, data: data2 } = session;
1749 let expires = options?.maxAge != null ? new Date(Date.now() + options.maxAge * 1e3) : options?.expires != null ? options.expires : cookie.expires;
1750 if (id) {
1751 await updateData(id, data2, expires);
1752 } else {
1753 id = await createData(data2, expires);
1754 }
1755 return cookie.serialize(id, options);
1756 },
1757 async destroySession(session, options) {
1758 await deleteData(session.id);
1759 return cookie.serialize("", {
1760 ...options,
1761 maxAge: void 0,
1762 expires: /* @__PURE__ */ new Date(0)
1763 });
1764 }
1765 };
1766}
1767function warnOnceAboutSigningSessionCookie(cookie) {
1768 warnOnce(
1769 cookie.isSigned,
1770 `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.`
1771 );
1772}
1773
1774// lib/server-runtime/sessions/cookieStorage.ts
1775function createCookieSessionStorage({ cookie: cookieArg } = {}) {
1776 let cookie = isCookie(cookieArg) ? cookieArg : createCookie(cookieArg?.name || "__session", cookieArg);
1777 warnOnceAboutSigningSessionCookie(cookie);
1778 return {
1779 async getSession(cookieHeader, options) {
1780 return createSession(
1781 cookieHeader && await cookie.parse(cookieHeader, options) || {}
1782 );
1783 },
1784 async commitSession(session, options) {
1785 let serializedCookie = await cookie.serialize(session.data, options);
1786 if (serializedCookie.length > 4096) {
1787 throw new Error(
1788 "Cookie length will exceed browser maximum. Length: " + serializedCookie.length
1789 );
1790 }
1791 return serializedCookie;
1792 },
1793 async destroySession(_session, options) {
1794 return cookie.serialize("", {
1795 ...options,
1796 maxAge: void 0,
1797 expires: /* @__PURE__ */ new Date(0)
1798 });
1799 }
1800 };
1801}
1802
1803// lib/server-runtime/sessions/memoryStorage.ts
1804function createMemorySessionStorage({ cookie } = {}) {
1805 let map = /* @__PURE__ */ new Map();
1806 return createSessionStorage({
1807 cookie,
1808 async createData(data2, expires) {
1809 let id = Math.random().toString(36).substring(2, 10);
1810 map.set(id, { data: data2, expires });
1811 return id;
1812 },
1813 async readData(id) {
1814 if (map.has(id)) {
1815 let { data: data2, expires } = map.get(id);
1816 if (!expires || expires > /* @__PURE__ */ new Date()) {
1817 return data2;
1818 }
1819 if (expires) map.delete(id);
1820 }
1821 return null;
1822 },
1823 async updateData(id, data2, expires) {
1824 map.set(id, { data: data2, expires });
1825 },
1826 async deleteData(id) {
1827 map.delete(id);
1828 }
1829 });
1830}
1831
1832// lib/href.ts
1833function href(path, ...args) {
1834 let params = args[0];
1835 let result = trimTrailingSplat(path).replace(
1836 /\/:([\w-]+)(\?)?/g,
1837 // same regex as in .\router\utils.ts: compilePath().
1838 (_, param, questionMark) => {
1839 const isRequired = questionMark === void 0;
1840 const value = params?.[param];
1841 if (isRequired && value === void 0) {
1842 throw new Error(
1843 `Path '${path}' requires param '${param}' but it was not provided`
1844 );
1845 }
1846 return value === void 0 ? "" : "/" + value;
1847 }
1848 );
1849 if (path.endsWith("*")) {
1850 const value = params?.["*"];
1851 if (value !== void 0) {
1852 result += "/" + value;
1853 }
1854 }
1855 return result || "/";
1856}
1857function trimTrailingSplat(path) {
1858 let i = path.length - 1;
1859 let char = path[i];
1860 if (char !== "*" && char !== "/") return path;
1861 i--;
1862 for (; i >= 0; i--) {
1863 if (path[i] !== "/") break;
1864 }
1865 return path.slice(0, i + 1);
1866}
1867
1868// lib/rsc/server.ssr.tsx
1869import * as React4 from "react";
1870
1871// lib/rsc/html-stream/server.ts
1872var encoder2 = new TextEncoder();
1873var trailer = "</body></html>";
1874function injectRSCPayload(rscStream) {
1875 let decoder = new TextDecoder();
1876 let resolveFlightDataPromise;
1877 let flightDataPromise = new Promise(
1878 (resolve) => resolveFlightDataPromise = resolve
1879 );
1880 let startedRSC = false;
1881 let buffered = [];
1882 let timeout = null;
1883 function flushBufferedChunks(controller) {
1884 for (let chunk of buffered) {
1885 let buf = decoder.decode(chunk, { stream: true });
1886 if (buf.endsWith(trailer)) {
1887 buf = buf.slice(0, -trailer.length);
1888 }
1889 controller.enqueue(encoder2.encode(buf));
1890 }
1891 buffered.length = 0;
1892 timeout = null;
1893 }
1894 return new TransformStream({
1895 transform(chunk, controller) {
1896 buffered.push(chunk);
1897 if (timeout) {
1898 return;
1899 }
1900 timeout = setTimeout(async () => {
1901 flushBufferedChunks(controller);
1902 if (!startedRSC) {
1903 startedRSC = true;
1904 writeRSCStream(rscStream, controller).catch((err) => controller.error(err)).then(resolveFlightDataPromise);
1905 }
1906 }, 0);
1907 },
1908 async flush(controller) {
1909 await flightDataPromise;
1910 if (timeout) {
1911 clearTimeout(timeout);
1912 flushBufferedChunks(controller);
1913 }
1914 controller.enqueue(encoder2.encode("</body></html>"));
1915 }
1916 });
1917}
1918async function writeRSCStream(rscStream, controller) {
1919 let decoder = new TextDecoder("utf-8", { fatal: true });
1920 const reader = rscStream.getReader();
1921 try {
1922 let read;
1923 while ((read = await reader.read()) && !read.done) {
1924 const chunk = read.value;
1925 try {
1926 writeChunk(
1927 JSON.stringify(decoder.decode(chunk, { stream: true })),
1928 controller
1929 );
1930 } catch (err) {
1931 let base64 = JSON.stringify(btoa(String.fromCodePoint(...chunk)));
1932 writeChunk(
1933 `Uint8Array.from(atob(${base64}), m => m.codePointAt(0))`,
1934 controller
1935 );
1936 }
1937 }
1938 } finally {
1939 reader.releaseLock();
1940 }
1941 let remaining = decoder.decode();
1942 if (remaining.length) {
1943 writeChunk(JSON.stringify(remaining), controller);
1944 }
1945}
1946function writeChunk(chunk, controller) {
1947 controller.enqueue(
1948 encoder2.encode(
1949 `<script>${escapeScript(
1950 `(self.__FLIGHT_DATA||=[]).push(${chunk})`
1951 )}</script>`
1952 )
1953 );
1954}
1955function escapeScript(script) {
1956 return script.replace(/<!--/g, "<\\!--").replace(/<\/(script)/gi, "</\\$1");
1957}
1958
1959// lib/rsc/errorBoundaries.tsx
1960import React3 from "react";
1961var RSCRouterGlobalErrorBoundary = class extends React3.Component {
1962 constructor(props) {
1963 super(props);
1964 this.state = { error: null, location: props.location };
1965 }
1966 static getDerivedStateFromError(error) {
1967 return { error };
1968 }
1969 static getDerivedStateFromProps(props, state) {
1970 if (state.location !== props.location) {
1971 return { error: null, location: props.location };
1972 }
1973 return { error: state.error, location: state.location };
1974 }
1975 render() {
1976 if (this.state.error) {
1977 return /* @__PURE__ */ React3.createElement(
1978 RSCDefaultRootErrorBoundaryImpl,
1979 {
1980 error: this.state.error,
1981 renderAppShell: true
1982 }
1983 );
1984 } else {
1985 return this.props.children;
1986 }
1987 }
1988};
1989function ErrorWrapper({
1990 renderAppShell,
1991 title,
1992 children
1993}) {
1994 if (!renderAppShell) {
1995 return children;
1996 }
1997 return /* @__PURE__ */ React3.createElement("html", { lang: "en" }, /* @__PURE__ */ React3.createElement("head", null, /* @__PURE__ */ React3.createElement("meta", { charSet: "utf-8" }), /* @__PURE__ */ React3.createElement(
1998 "meta",
1999 {
2000 name: "viewport",
2001 content: "width=device-width,initial-scale=1,viewport-fit=cover"
2002 }
2003 ), /* @__PURE__ */ React3.createElement("title", null, title)), /* @__PURE__ */ React3.createElement("body", null, /* @__PURE__ */ React3.createElement("main", { style: { fontFamily: "system-ui, sans-serif", padding: "2rem" } }, children)));
2004}
2005function RSCDefaultRootErrorBoundaryImpl({
2006 error,
2007 renderAppShell
2008}) {
2009 console.error(error);
2010 let heyDeveloper = /* @__PURE__ */ React3.createElement(
2011 "script",
2012 {
2013 dangerouslySetInnerHTML: {
2014 __html: `
2015 console.log(
2016 "\u{1F4BF} Hey developer \u{1F44B}. You can provide a way better UX than this when your app throws errors. Check out https://reactrouter.com/how-to/error-boundary for more information."
2017 );
2018 `
2019 }
2020 }
2021 );
2022 if (isRouteErrorResponse(error)) {
2023 return /* @__PURE__ */ React3.createElement(
2024 ErrorWrapper,
2025 {
2026 renderAppShell,
2027 title: "Unhandled Thrown Response!"
2028 },
2029 /* @__PURE__ */ React3.createElement("h1", { style: { fontSize: "24px" } }, error.status, " ", error.statusText),
2030 ENABLE_DEV_WARNINGS ? heyDeveloper : null
2031 );
2032 }
2033 let errorInstance;
2034 if (error instanceof Error) {
2035 errorInstance = error;
2036 } else {
2037 let errorString = error == null ? "Unknown Error" : typeof error === "object" && "toString" in error ? error.toString() : JSON.stringify(error);
2038 errorInstance = new Error(errorString);
2039 }
2040 return /* @__PURE__ */ React3.createElement(ErrorWrapper, { renderAppShell, title: "Application Error!" }, /* @__PURE__ */ React3.createElement("h1", { style: { fontSize: "24px" } }, "Application Error"), /* @__PURE__ */ React3.createElement(
2041 "pre",
2042 {
2043 style: {
2044 padding: "2rem",
2045 background: "hsla(10, 50%, 50%, 0.1)",
2046 color: "red",
2047 overflow: "auto"
2048 }
2049 },
2050 errorInstance.stack
2051 ), heyDeveloper);
2052}
2053function RSCDefaultRootErrorBoundary({
2054 hasRootLayout
2055}) {
2056 let error = useRouteError();
2057 if (hasRootLayout === void 0) {
2058 throw new Error("Missing 'hasRootLayout' prop");
2059 }
2060 return /* @__PURE__ */ React3.createElement(
2061 RSCDefaultRootErrorBoundaryImpl,
2062 {
2063 renderAppShell: !hasRootLayout,
2064 error
2065 }
2066 );
2067}
2068
2069// lib/rsc/route-modules.ts
2070function createRSCRouteModules(payload) {
2071 const routeModules = {};
2072 for (const match of payload.matches) {
2073 populateRSCRouteModules(routeModules, match);
2074 }
2075 return routeModules;
2076}
2077function populateRSCRouteModules(routeModules, matches) {
2078 matches = Array.isArray(matches) ? matches : [matches];
2079 for (const match of matches) {
2080 routeModules[match.id] = {
2081 links: match.links,
2082 meta: match.meta,
2083 default: noopComponent
2084 };
2085 }
2086}
2087var noopComponent = () => null;
2088
2089// lib/rsc/server.ssr.tsx
2090var defaultManifestPath = "/__manifest";
2091var REACT_USE = "use";
2092var useImpl = React4[REACT_USE];
2093function useSafe(promise) {
2094 if (useImpl) {
2095 return useImpl(promise);
2096 }
2097 throw new Error("React Router v7 requires React 19+ for RSC features.");
2098}
2099async function routeRSCServerRequest({
2100 request,
2101 serverResponse,
2102 createFromReadableStream,
2103 renderHTML,
2104 hydrate = true
2105}) {
2106 const url = new URL(request.url);
2107 const isDataRequest = isReactServerRequest(url);
2108 const respondWithRSCPayload = isDataRequest || isManifestRequest(url) || request.headers.has("rsc-action-id");
2109 if (respondWithRSCPayload || serverResponse.headers.get("React-Router-Resource") === "true") {
2110 return serverResponse;
2111 }
2112 if (!serverResponse.body) {
2113 throw new Error("Missing body in server response");
2114 }
2115 const detectRedirectResponse = serverResponse.clone();
2116 let serverResponseB = null;
2117 if (hydrate) {
2118 serverResponseB = serverResponse.clone();
2119 }
2120 const body = serverResponse.body;
2121 let buffer;
2122 let streamControllers = [];
2123 const createStream = () => {
2124 if (!buffer) {
2125 buffer = [];
2126 return body.pipeThrough(
2127 new TransformStream({
2128 transform(chunk, controller) {
2129 buffer.push(chunk);
2130 controller.enqueue(chunk);
2131 streamControllers.forEach((c) => c.enqueue(chunk));
2132 },
2133 flush() {
2134 streamControllers.forEach((c) => c.close());
2135 streamControllers = [];
2136 }
2137 })
2138 );
2139 }
2140 return new ReadableStream({
2141 start(controller) {
2142 buffer.forEach((chunk) => controller.enqueue(chunk));
2143 streamControllers.push(controller);
2144 }
2145 });
2146 };
2147 let deepestRenderedBoundaryId = null;
2148 const getPayload = () => {
2149 const payloadPromise = Promise.resolve(
2150 createFromReadableStream(createStream())
2151 );
2152 return Object.defineProperties(payloadPromise, {
2153 _deepestRenderedBoundaryId: {
2154 get() {
2155 return deepestRenderedBoundaryId;
2156 },
2157 set(boundaryId) {
2158 deepestRenderedBoundaryId = boundaryId;
2159 }
2160 },
2161 formState: {
2162 get() {
2163 return payloadPromise.then(
2164 (payload) => payload.type === "render" ? payload.formState : void 0
2165 );
2166 }
2167 }
2168 });
2169 };
2170 let renderRedirect;
2171 let renderError;
2172 try {
2173 if (!detectRedirectResponse.body) {
2174 throw new Error("Failed to clone server response");
2175 }
2176 const payload = await createFromReadableStream(
2177 detectRedirectResponse.body
2178 );
2179 if (serverResponse.status === SINGLE_FETCH_REDIRECT_STATUS && payload.type === "redirect") {
2180 const headers2 = new Headers(serverResponse.headers);
2181 headers2.delete("Content-Encoding");
2182 headers2.delete("Content-Length");
2183 headers2.delete("Content-Type");
2184 headers2.delete("X-Remix-Response");
2185 headers2.set("Location", payload.location);
2186 return new Response(serverResponseB?.body || "", {
2187 headers: headers2,
2188 status: payload.status,
2189 statusText: serverResponse.statusText
2190 });
2191 }
2192 let reactHeaders = new Headers();
2193 let status = serverResponse.status;
2194 let statusText = serverResponse.statusText;
2195 let html = await renderHTML(getPayload, {
2196 onError(error) {
2197 if (typeof error === "object" && error && "digest" in error && typeof error.digest === "string") {
2198 renderRedirect = decodeRedirectErrorDigest(error.digest);
2199 if (renderRedirect) {
2200 return error.digest;
2201 }
2202 let routeErrorResponse = decodeRouteErrorResponseDigest(error.digest);
2203 if (routeErrorResponse) {
2204 renderError = routeErrorResponse;
2205 status = routeErrorResponse.status;
2206 statusText = routeErrorResponse.statusText;
2207 return error.digest;
2208 }
2209 }
2210 },
2211 onHeaders(headers2) {
2212 for (const [key, value] of headers2) {
2213 reactHeaders.append(key, value);
2214 }
2215 }
2216 });
2217 const headers = new Headers(reactHeaders);
2218 for (const [key, value] of serverResponse.headers) {
2219 headers.append(key, value);
2220 }
2221 headers.set("Content-Type", "text/html; charset=utf-8");
2222 if (renderRedirect) {
2223 headers.set("Location", renderRedirect.location);
2224 return new Response(html, {
2225 status: renderRedirect.status,
2226 headers
2227 });
2228 }
2229 const redirectTransform = new TransformStream({
2230 flush(controller) {
2231 if (renderRedirect) {
2232 controller.enqueue(
2233 new TextEncoder().encode(
2234 `<meta http-equiv="refresh" content="0;url=${escapeHtml(renderRedirect.location)}"/>`
2235 )
2236 );
2237 }
2238 }
2239 });
2240 if (!hydrate) {
2241 return new Response(html.pipeThrough(redirectTransform), {
2242 status,
2243 statusText,
2244 headers
2245 });
2246 }
2247 if (!serverResponseB?.body) {
2248 throw new Error("Failed to clone server response");
2249 }
2250 const body2 = html.pipeThrough(injectRSCPayload(serverResponseB.body)).pipeThrough(redirectTransform);
2251 return new Response(body2, {
2252 status,
2253 statusText,
2254 headers
2255 });
2256 } catch (reason) {
2257 if (reason instanceof Response) {
2258 return reason;
2259 }
2260 if (renderRedirect) {
2261 return new Response(`Redirect: ${renderRedirect.location}`, {
2262 status: renderRedirect.status,
2263 headers: {
2264 Location: renderRedirect.location
2265 }
2266 });
2267 }
2268 try {
2269 reason = renderError ?? reason;
2270 let [status, statusText] = isRouteErrorResponse(reason) ? [reason.status, reason.statusText] : [500, ""];
2271 let retryRedirect;
2272 let reactHeaders = new Headers();
2273 const html = await renderHTML(
2274 () => {
2275 const decoded = Promise.resolve(
2276 createFromReadableStream(createStream())
2277 );
2278 const payloadPromise = decoded.then(
2279 (payload) => Object.assign(payload, {
2280 status,
2281 errors: deepestRenderedBoundaryId ? {
2282 [deepestRenderedBoundaryId]: reason
2283 } : {}
2284 })
2285 );
2286 return Object.defineProperties(payloadPromise, {
2287 _deepestRenderedBoundaryId: {
2288 get() {
2289 return deepestRenderedBoundaryId;
2290 },
2291 set(boundaryId) {
2292 deepestRenderedBoundaryId = boundaryId;
2293 }
2294 },
2295 formState: {
2296 get() {
2297 return payloadPromise.then(
2298 (payload) => payload.type === "render" ? payload.formState : void 0
2299 );
2300 }
2301 }
2302 });
2303 },
2304 {
2305 onError(error) {
2306 if (typeof error === "object" && error && "digest" in error && typeof error.digest === "string") {
2307 retryRedirect = decodeRedirectErrorDigest(error.digest);
2308 if (retryRedirect) {
2309 return error.digest;
2310 }
2311 let routeErrorResponse = decodeRouteErrorResponseDigest(
2312 error.digest
2313 );
2314 if (routeErrorResponse) {
2315 status = routeErrorResponse.status;
2316 statusText = routeErrorResponse.statusText;
2317 return error.digest;
2318 }
2319 }
2320 },
2321 onHeaders(headers2) {
2322 for (const [key, value] of headers2) {
2323 reactHeaders.append(key, value);
2324 }
2325 }
2326 }
2327 );
2328 const headers = new Headers(reactHeaders);
2329 for (const [key, value] of serverResponse.headers) {
2330 headers.append(key, value);
2331 }
2332 headers.set("Content-Type", "text/html; charset=utf-8");
2333 if (retryRedirect) {
2334 headers.set("Location", retryRedirect.location);
2335 return new Response(html, {
2336 status: retryRedirect.status,
2337 headers
2338 });
2339 }
2340 const retryRedirectTransform = new TransformStream({
2341 flush(controller) {
2342 if (retryRedirect) {
2343 controller.enqueue(
2344 new TextEncoder().encode(
2345 `<meta http-equiv="refresh" content="0;url=${escapeHtml(retryRedirect.location)}"/>`
2346 )
2347 );
2348 }
2349 }
2350 });
2351 if (!hydrate) {
2352 return new Response(html.pipeThrough(retryRedirectTransform), {
2353 status,
2354 statusText,
2355 headers
2356 });
2357 }
2358 if (!serverResponseB?.body) {
2359 throw new Error("Failed to clone server response");
2360 }
2361 const body2 = html.pipeThrough(injectRSCPayload(serverResponseB.body)).pipeThrough(retryRedirectTransform);
2362 return new Response(body2, {
2363 status,
2364 statusText,
2365 headers
2366 });
2367 } catch {
2368 }
2369 throw reason;
2370 }
2371}
2372function RSCStaticRouter({ getPayload }) {
2373 const decoded = getPayload();
2374 const payload = useSafe(decoded);
2375 if (payload.type === "redirect") {
2376 throw new Response(null, {
2377 status: payload.status,
2378 headers: {
2379 Location: payload.location
2380 }
2381 });
2382 }
2383 if (payload.type !== "render") return null;
2384 let patchedLoaderData = { ...payload.loaderData };
2385 for (const match of payload.matches) {
2386 if (shouldHydrateRouteLoader(
2387 match.id,
2388 match.clientLoader,
2389 match.hasLoader,
2390 false
2391 ) && (match.hydrateFallbackElement || !match.hasLoader)) {
2392 delete patchedLoaderData[match.id];
2393 }
2394 }
2395 const context = {
2396 get _deepestRenderedBoundaryId() {
2397 return decoded._deepestRenderedBoundaryId ?? null;
2398 },
2399 set _deepestRenderedBoundaryId(boundaryId) {
2400 decoded._deepestRenderedBoundaryId = boundaryId;
2401 },
2402 actionData: payload.actionData,
2403 actionHeaders: {},
2404 basename: payload.basename,
2405 errors: payload.errors,
2406 loaderData: patchedLoaderData,
2407 loaderHeaders: {},
2408 location: payload.location,
2409 statusCode: 200,
2410 matches: payload.matches.map((match) => ({
2411 params: match.params,
2412 pathname: match.pathname,
2413 pathnameBase: match.pathnameBase,
2414 route: {
2415 id: match.id,
2416 action: match.hasAction || !!match.clientAction,
2417 handle: match.handle,
2418 hasErrorBoundary: match.hasErrorBoundary,
2419 loader: match.hasLoader || !!match.clientLoader,
2420 index: match.index,
2421 path: match.path,
2422 shouldRevalidate: match.shouldRevalidate
2423 }
2424 }))
2425 };
2426 const router = createStaticRouter(
2427 payload.matches.reduceRight((previous, match) => {
2428 const route = {
2429 id: match.id,
2430 action: match.hasAction || !!match.clientAction,
2431 element: match.element,
2432 errorElement: match.errorElement,
2433 handle: match.handle,
2434 hasErrorBoundary: !!match.errorElement,
2435 hydrateFallbackElement: match.hydrateFallbackElement,
2436 index: match.index,
2437 loader: match.hasLoader || !!match.clientLoader,
2438 path: match.path,
2439 shouldRevalidate: match.shouldRevalidate
2440 };
2441 if (previous.length > 0) {
2442 route.children = previous;
2443 }
2444 return [route];
2445 }, []),
2446 context
2447 );
2448 const frameworkContext = {
2449 future: {
2450 // These flags have no runtime impact so can always be false. If we add
2451 // flags that drive runtime behavior they'll need to be proxied through.
2452 v8_middleware: false,
2453 unstable_trailingSlashAwareDataRequests: true,
2454 // always on for RSC
2455 v8_passThroughRequests: true
2456 // always on for RSC
2457 },
2458 isSpaMode: false,
2459 ssr: true,
2460 criticalCss: "",
2461 manifest: {
2462 routes: {},
2463 version: "1",
2464 url: "",
2465 entry: {
2466 module: "",
2467 imports: []
2468 }
2469 },
2470 routeDiscovery: payload.routeDiscovery.mode === "initial" ? { mode: "initial", manifestPath: defaultManifestPath } : {
2471 mode: "lazy",
2472 manifestPath: payload.routeDiscovery.manifestPath || defaultManifestPath
2473 },
2474 routeModules: createRSCRouteModules(payload)
2475 };
2476 return /* @__PURE__ */ React4.createElement(RSCRouterContext.Provider, { value: true }, /* @__PURE__ */ React4.createElement(RSCRouterGlobalErrorBoundary, { location: payload.location }, /* @__PURE__ */ React4.createElement(FrameworkContext.Provider, { value: frameworkContext }, /* @__PURE__ */ React4.createElement(
2477 StaticRouterProvider,
2478 {
2479 context,
2480 router,
2481 hydrate: false,
2482 nonce: payload.nonce
2483 }
2484 ))));
2485}
2486function isReactServerRequest(url) {
2487 return url.pathname.endsWith(".rsc");
2488}
2489function isManifestRequest(url) {
2490 return url.pathname.endsWith(".manifest");
2491}
2492
2493// lib/dom/ssr/errors.ts
2494function deserializeErrors(errors) {
2495 if (!errors) return null;
2496 let entries = Object.entries(errors);
2497 let serialized = {};
2498 for (let [key, val] of entries) {
2499 if (val && val.__type === "RouteErrorResponse") {
2500 serialized[key] = new ErrorResponseImpl(
2501 val.status,
2502 val.statusText,
2503 val.data,
2504 val.internal === true
2505 );
2506 } else if (val && val.__type === "Error") {
2507 if (val.__subType) {
2508 let ErrorConstructor = window[val.__subType];
2509 if (typeof ErrorConstructor === "function") {
2510 try {
2511 let error = new ErrorConstructor(val.message);
2512 error.stack = val.stack;
2513 serialized[key] = error;
2514 } catch (e) {
2515 }
2516 }
2517 }
2518 if (serialized[key] == null) {
2519 let error = new Error(val.message);
2520 error.stack = val.stack;
2521 serialized[key] = error;
2522 }
2523 } else {
2524 serialized[key] = val;
2525 }
2526 }
2527 return serialized;
2528}
2529
2530// lib/dom/ssr/hydration.tsx
2531function getHydrationData({
2532 state,
2533 routes,
2534 getRouteInfo,
2535 location,
2536 basename,
2537 isSpaMode
2538}) {
2539 let hydrationData = {
2540 ...state,
2541 loaderData: { ...state.loaderData }
2542 };
2543 let initialMatches = matchRoutes(routes, location, basename);
2544 if (initialMatches) {
2545 for (let match of initialMatches) {
2546 let routeId = match.route.id;
2547 let routeInfo = getRouteInfo(routeId);
2548 if (shouldHydrateRouteLoader(
2549 routeId,
2550 routeInfo.clientLoader,
2551 routeInfo.hasLoader,
2552 isSpaMode
2553 ) && (routeInfo.hasHydrateFallback || !routeInfo.hasLoader)) {
2554 delete hydrationData.loaderData[routeId];
2555 } else if (!routeInfo.hasLoader) {
2556 hydrationData.loaderData[routeId] = null;
2557 }
2558 }
2559 }
2560 return hydrationData;
2561}
2562
2563export {
2564 ServerRouter,
2565 createRoutesStub,
2566 createCookie,
2567 isCookie,
2568 ServerMode,
2569 setDevServerHooks,
2570 createRequestHandler,
2571 createSession,
2572 isSession,
2573 createSessionStorage,
2574 createCookieSessionStorage,
2575 createMemorySessionStorage,
2576 href,
2577 RSCRouterGlobalErrorBoundary,
2578 RSCDefaultRootErrorBoundary,
2579 populateRSCRouteModules,
2580 routeRSCServerRequest,
2581 RSCStaticRouter,
2582 deserializeErrors,
2583 getHydrationData
2584};