UNPKG

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