UNPKG

78.5 kBJavaScriptView Raw
1/**
2 * react-router v7.13.1
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-LFPYN7LY.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 = null;
762 try {
763 originDomain = typeof originHeader === "string" && originHeader !== "null" ? new URL(originHeader).host : originHeader;
764 } catch {
765 throw new Error(
766 `\`origin\` header is not a valid URL. Aborting the action.`
767 );
768 }
769 let host = parseHostHeader(headers);
770 if (originDomain && (!host || originDomain !== host.value)) {
771 if (!isAllowedOrigin(originDomain, allowedActionOrigins)) {
772 if (host) {
773 throw new Error(
774 `${host.type} header does not match \`origin\` header from a forwarded action request. Aborting the action.`
775 );
776 } else {
777 throw new Error(
778 "`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."
779 );
780 }
781 }
782 }
783}
784function matchWildcardDomain(domain, pattern) {
785 const domainParts = domain.split(".");
786 const patternParts = pattern.split(".");
787 if (patternParts.length < 1) {
788 return false;
789 }
790 if (domainParts.length < patternParts.length) {
791 return false;
792 }
793 while (patternParts.length) {
794 const patternPart = patternParts.pop();
795 const domainPart = domainParts.pop();
796 switch (patternPart) {
797 case "": {
798 return false;
799 }
800 case "*": {
801 if (domainPart) {
802 continue;
803 } else {
804 return false;
805 }
806 }
807 case "**": {
808 if (patternParts.length > 0) {
809 return false;
810 }
811 return domainPart !== void 0;
812 }
813 case void 0:
814 default: {
815 if (domainPart !== patternPart) {
816 return false;
817 }
818 }
819 }
820 }
821 return domainParts.length === 0;
822}
823function isAllowedOrigin(originDomain, allowedActionOrigins = []) {
824 return allowedActionOrigins.some(
825 (allowedOrigin) => allowedOrigin && (allowedOrigin === originDomain || matchWildcardDomain(originDomain, allowedOrigin))
826 );
827}
828function parseHostHeader(headers) {
829 let forwardedHostHeader = headers.get("x-forwarded-host");
830 let forwardedHostValue = forwardedHostHeader?.split(",")[0]?.trim();
831 let hostHeader = headers.get("host");
832 return forwardedHostValue ? {
833 type: "x-forwarded-host",
834 value: forwardedHostValue
835 } : hostHeader ? {
836 type: "host",
837 value: hostHeader
838 } : void 0;
839}
840
841// lib/server-runtime/single-fetch.ts
842var SERVER_NO_BODY_STATUS_CODES = /* @__PURE__ */ new Set([
843 ...NO_BODY_STATUS_CODES,
844 304
845]);
846async function singleFetchAction(build, serverMode, staticHandler, request, handlerUrl, loadContext, handleError) {
847 try {
848 try {
849 throwIfPotentialCSRFAttack(
850 request.headers,
851 Array.isArray(build.allowedActionOrigins) ? build.allowedActionOrigins : []
852 );
853 } catch (e) {
854 return handleQueryError(new Error("Bad Request"), 400);
855 }
856 let handlerRequest = new Request(handlerUrl, {
857 method: request.method,
858 body: request.body,
859 headers: request.headers,
860 signal: request.signal,
861 ...request.body ? { duplex: "half" } : void 0
862 });
863 let result = await staticHandler.query(handlerRequest, {
864 requestContext: loadContext,
865 skipLoaderErrorBubbling: true,
866 skipRevalidation: true,
867 generateMiddlewareResponse: build.future.v8_middleware ? async (query) => {
868 try {
869 let innerResult = await query(handlerRequest);
870 return handleQueryResult(innerResult);
871 } catch (error) {
872 return handleQueryError(error);
873 }
874 } : void 0
875 });
876 return handleQueryResult(result);
877 } catch (error) {
878 return handleQueryError(error);
879 }
880 function handleQueryResult(result) {
881 return isResponse(result) ? result : staticContextToResponse(result);
882 }
883 function handleQueryError(error, status = 500) {
884 handleError(error);
885 return generateSingleFetchResponse(request, build, serverMode, {
886 result: { error },
887 headers: new Headers(),
888 status
889 });
890 }
891 function staticContextToResponse(context) {
892 let headers = getDocumentHeaders(context, build);
893 if (isRedirectStatusCode(context.statusCode) && headers.has("Location")) {
894 return new Response(null, { status: context.statusCode, headers });
895 }
896 if (context.errors) {
897 Object.values(context.errors).forEach((err) => {
898 if (!isRouteErrorResponse(err) || err.error) {
899 handleError(err);
900 }
901 });
902 context.errors = sanitizeErrors(context.errors, serverMode);
903 }
904 let singleFetchResult;
905 if (context.errors) {
906 singleFetchResult = { error: Object.values(context.errors)[0] };
907 } else {
908 singleFetchResult = {
909 data: Object.values(context.actionData || {})[0]
910 };
911 }
912 return generateSingleFetchResponse(request, build, serverMode, {
913 result: singleFetchResult,
914 headers,
915 status: context.statusCode
916 });
917 }
918}
919async function singleFetchLoaders(build, serverMode, staticHandler, request, handlerUrl, loadContext, handleError) {
920 let routesParam = new URL(request.url).searchParams.get("_routes");
921 let loadRouteIds = routesParam ? new Set(routesParam.split(",")) : null;
922 try {
923 let handlerRequest = new Request(handlerUrl, {
924 headers: request.headers,
925 signal: request.signal
926 });
927 let result = await staticHandler.query(handlerRequest, {
928 requestContext: loadContext,
929 filterMatchesToLoad: (m) => !loadRouteIds || loadRouteIds.has(m.route.id),
930 skipLoaderErrorBubbling: true,
931 generateMiddlewareResponse: build.future.v8_middleware ? async (query) => {
932 try {
933 let innerResult = await query(handlerRequest);
934 return handleQueryResult(innerResult);
935 } catch (error) {
936 return handleQueryError(error);
937 }
938 } : void 0
939 });
940 return handleQueryResult(result);
941 } catch (error) {
942 return handleQueryError(error);
943 }
944 function handleQueryResult(result) {
945 return isResponse(result) ? result : staticContextToResponse(result);
946 }
947 function handleQueryError(error) {
948 handleError(error);
949 return generateSingleFetchResponse(request, build, serverMode, {
950 result: { error },
951 headers: new Headers(),
952 status: 500
953 });
954 }
955 function staticContextToResponse(context) {
956 let headers = getDocumentHeaders(context, build);
957 if (isRedirectStatusCode(context.statusCode) && headers.has("Location")) {
958 return new Response(null, { status: context.statusCode, headers });
959 }
960 if (context.errors) {
961 Object.values(context.errors).forEach((err) => {
962 if (!isRouteErrorResponse(err) || err.error) {
963 handleError(err);
964 }
965 });
966 context.errors = sanitizeErrors(context.errors, serverMode);
967 }
968 let results = {};
969 let loadedMatches = new Set(
970 context.matches.filter(
971 (m) => loadRouteIds ? loadRouteIds.has(m.route.id) : m.route.loader != null
972 ).map((m) => m.route.id)
973 );
974 if (context.errors) {
975 for (let [id, error] of Object.entries(context.errors)) {
976 results[id] = { error };
977 }
978 }
979 for (let [id, data2] of Object.entries(context.loaderData)) {
980 if (!(id in results) && loadedMatches.has(id)) {
981 results[id] = { data: data2 };
982 }
983 }
984 return generateSingleFetchResponse(request, build, serverMode, {
985 result: results,
986 headers,
987 status: context.statusCode
988 });
989 }
990}
991function generateSingleFetchResponse(request, build, serverMode, {
992 result,
993 headers,
994 status
995}) {
996 let resultHeaders = new Headers(headers);
997 resultHeaders.set("X-Remix-Response", "yes");
998 if (SERVER_NO_BODY_STATUS_CODES.has(status)) {
999 return new Response(null, { status, headers: resultHeaders });
1000 }
1001 resultHeaders.set("Content-Type", "text/x-script");
1002 resultHeaders.delete("Content-Length");
1003 return new Response(
1004 encodeViaTurboStream(
1005 result,
1006 request.signal,
1007 build.entry.module.streamTimeout,
1008 serverMode
1009 ),
1010 {
1011 status: status || 200,
1012 headers: resultHeaders
1013 }
1014 );
1015}
1016function generateSingleFetchRedirectResponse(redirectResponse, request, build, serverMode) {
1017 let redirect2 = getSingleFetchRedirect(
1018 redirectResponse.status,
1019 redirectResponse.headers,
1020 build.basename
1021 );
1022 let headers = new Headers(redirectResponse.headers);
1023 headers.delete("Location");
1024 headers.set("Content-Type", "text/x-script");
1025 return generateSingleFetchResponse(request, build, serverMode, {
1026 result: request.method === "GET" ? { [SingleFetchRedirectSymbol]: redirect2 } : redirect2,
1027 headers,
1028 status: SINGLE_FETCH_REDIRECT_STATUS
1029 });
1030}
1031function getSingleFetchRedirect(status, headers, basename) {
1032 let redirect2 = headers.get("Location");
1033 if (basename) {
1034 redirect2 = stripBasename(redirect2, basename) || redirect2;
1035 }
1036 return {
1037 redirect: redirect2,
1038 status,
1039 revalidate: (
1040 // Technically X-Remix-Revalidate isn't needed here - that was an implementation
1041 // detail of ?_data requests as our way to tell the front end to revalidate when
1042 // we didn't have a response body to include that information in.
1043 // With single fetch, we tell the front end via this revalidate boolean field.
1044 // However, we're respecting it for now because it may be something folks have
1045 // used in their own responses
1046 // TODO(v3): Consider removing or making this official public API
1047 headers.has("X-Remix-Revalidate") || headers.has("Set-Cookie")
1048 ),
1049 reload: headers.has("X-Remix-Reload-Document"),
1050 replace: headers.has("X-Remix-Replace")
1051 };
1052}
1053function encodeViaTurboStream(data2, requestSignal, streamTimeout, serverMode) {
1054 let controller = new AbortController();
1055 let timeoutId = setTimeout(
1056 () => controller.abort(new Error("Server Timeout")),
1057 typeof streamTimeout === "number" ? streamTimeout : 4950
1058 );
1059 let clearStreamTimeout = () => clearTimeout(timeoutId);
1060 requestSignal.addEventListener("abort", clearStreamTimeout);
1061 return encode(data2, {
1062 signal: controller.signal,
1063 onComplete: clearStreamTimeout,
1064 plugins: [
1065 (value) => {
1066 if (value instanceof Error) {
1067 let { name, message, stack } = serverMode === "production" /* Production */ ? sanitizeError(value, serverMode) : value;
1068 return ["SanitizedError", name, message, stack];
1069 }
1070 if (value instanceof ErrorResponseImpl) {
1071 let { data: data3, status, statusText } = value;
1072 return ["ErrorResponse", data3, status, statusText];
1073 }
1074 if (value && typeof value === "object" && SingleFetchRedirectSymbol in value) {
1075 return ["SingleFetchRedirect", value[SingleFetchRedirectSymbol]];
1076 }
1077 }
1078 ],
1079 postPlugins: [
1080 (value) => {
1081 if (!value) return;
1082 if (typeof value !== "object") return;
1083 return [
1084 "SingleFetchClassInstance",
1085 Object.fromEntries(Object.entries(value))
1086 ];
1087 },
1088 () => ["SingleFetchFallback"]
1089 ]
1090 });
1091}
1092
1093// lib/server-runtime/server.ts
1094function derive(build, mode) {
1095 let routes = createRoutes(build.routes);
1096 let dataRoutes = createStaticHandlerDataRoutes(build.routes, build.future);
1097 let serverMode = isServerMode(mode) ? mode : "production" /* Production */;
1098 let staticHandler = createStaticHandler(dataRoutes, {
1099 basename: build.basename,
1100 unstable_instrumentations: build.entry.module.unstable_instrumentations
1101 });
1102 let errorHandler = build.entry.module.handleError || ((error, { request }) => {
1103 if (serverMode !== "test" /* Test */ && !request.signal.aborted) {
1104 console.error(
1105 // @ts-expect-error This is "private" from users but intended for internal use
1106 isRouteErrorResponse(error) && error.error ? error.error : error
1107 );
1108 }
1109 });
1110 let requestHandler = async (request, initialContext) => {
1111 let params = {};
1112 let loadContext;
1113 let handleError = (error) => {
1114 if (mode === "development" /* Development */) {
1115 getDevServerHooks()?.processRequestError?.(error);
1116 }
1117 errorHandler(error, {
1118 context: loadContext,
1119 params,
1120 request
1121 });
1122 };
1123 if (build.future.v8_middleware) {
1124 if (initialContext && !(initialContext instanceof RouterContextProvider)) {
1125 let error = new Error(
1126 "Invalid `context` value provided to `handleRequest`. When middleware is enabled you must return an instance of `RouterContextProvider` from your `getLoadContext` function."
1127 );
1128 handleError(error);
1129 return returnLastResortErrorResponse(error, serverMode);
1130 }
1131 loadContext = initialContext || new RouterContextProvider();
1132 } else {
1133 loadContext = initialContext || {};
1134 }
1135 let url = new URL(request.url);
1136 let normalizedBasename = build.basename || "/";
1137 let normalizedPath = url.pathname;
1138 if (build.future.unstable_trailingSlashAwareDataRequests) {
1139 if (normalizedPath.endsWith("/_.data")) {
1140 normalizedPath = normalizedPath.replace(/_.data$/, "");
1141 } else {
1142 normalizedPath = normalizedPath.replace(/\.data$/, "");
1143 }
1144 } else {
1145 if (stripBasename(normalizedPath, normalizedBasename) === "/_root.data") {
1146 normalizedPath = normalizedBasename;
1147 } else if (normalizedPath.endsWith(".data")) {
1148 normalizedPath = normalizedPath.replace(/\.data$/, "");
1149 }
1150 if (stripBasename(normalizedPath, normalizedBasename) !== "/" && normalizedPath.endsWith("/")) {
1151 normalizedPath = normalizedPath.slice(0, -1);
1152 }
1153 }
1154 let isSpaMode = getBuildTimeHeader(request, "X-React-Router-SPA-Mode") === "yes";
1155 if (!build.ssr) {
1156 let decodedPath = decodeURI(normalizedPath);
1157 if (normalizedBasename !== "/") {
1158 let strippedPath = stripBasename(decodedPath, normalizedBasename);
1159 if (strippedPath == null) {
1160 errorHandler(
1161 new ErrorResponseImpl(
1162 404,
1163 "Not Found",
1164 `Refusing to prerender the \`${decodedPath}\` path because it does not start with the basename \`${normalizedBasename}\``
1165 ),
1166 {
1167 context: loadContext,
1168 params,
1169 request
1170 }
1171 );
1172 return new Response("Not Found", {
1173 status: 404,
1174 statusText: "Not Found"
1175 });
1176 }
1177 decodedPath = strippedPath;
1178 }
1179 if (build.prerender.length === 0) {
1180 isSpaMode = true;
1181 } else if (!build.prerender.includes(decodedPath) && !build.prerender.includes(decodedPath + "/")) {
1182 if (url.pathname.endsWith(".data")) {
1183 errorHandler(
1184 new ErrorResponseImpl(
1185 404,
1186 "Not Found",
1187 `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.`
1188 ),
1189 {
1190 context: loadContext,
1191 params,
1192 request
1193 }
1194 );
1195 return new Response("Not Found", {
1196 status: 404,
1197 statusText: "Not Found"
1198 });
1199 } else {
1200 isSpaMode = true;
1201 }
1202 }
1203 }
1204 let manifestUrl = getManifestPath(
1205 build.routeDiscovery.manifestPath,
1206 normalizedBasename
1207 );
1208 if (url.pathname === manifestUrl) {
1209 try {
1210 let res = await handleManifestRequest(build, routes, url);
1211 return res;
1212 } catch (e) {
1213 handleError(e);
1214 return new Response("Unknown Server Error", { status: 500 });
1215 }
1216 }
1217 let matches = matchServerRoutes(routes, normalizedPath, build.basename);
1218 if (matches && matches.length > 0) {
1219 Object.assign(params, matches[0].params);
1220 }
1221 let response;
1222 if (url.pathname.endsWith(".data")) {
1223 let handlerUrl = new URL(request.url);
1224 handlerUrl.pathname = normalizedPath;
1225 let singleFetchMatches = matchServerRoutes(
1226 routes,
1227 handlerUrl.pathname,
1228 build.basename
1229 );
1230 response = await handleSingleFetchRequest(
1231 serverMode,
1232 build,
1233 staticHandler,
1234 request,
1235 handlerUrl,
1236 loadContext,
1237 handleError
1238 );
1239 if (isRedirectResponse(response)) {
1240 response = generateSingleFetchRedirectResponse(
1241 response,
1242 request,
1243 build,
1244 serverMode
1245 );
1246 }
1247 if (build.entry.module.handleDataRequest) {
1248 response = await build.entry.module.handleDataRequest(response, {
1249 context: loadContext,
1250 params: singleFetchMatches ? singleFetchMatches[0].params : {},
1251 request
1252 });
1253 if (isRedirectResponse(response)) {
1254 response = generateSingleFetchRedirectResponse(
1255 response,
1256 request,
1257 build,
1258 serverMode
1259 );
1260 }
1261 }
1262 } else if (!isSpaMode && matches && matches[matches.length - 1].route.module.default == null && matches[matches.length - 1].route.module.ErrorBoundary == null) {
1263 response = await handleResourceRequest(
1264 serverMode,
1265 build,
1266 staticHandler,
1267 matches.slice(-1)[0].route.id,
1268 request,
1269 loadContext,
1270 handleError
1271 );
1272 } else {
1273 let { pathname } = url;
1274 let criticalCss = void 0;
1275 if (build.unstable_getCriticalCss) {
1276 criticalCss = await build.unstable_getCriticalCss({ pathname });
1277 } else if (mode === "development" /* Development */ && getDevServerHooks()?.getCriticalCss) {
1278 criticalCss = await getDevServerHooks()?.getCriticalCss?.(pathname);
1279 }
1280 response = await handleDocumentRequest(
1281 serverMode,
1282 build,
1283 staticHandler,
1284 request,
1285 loadContext,
1286 handleError,
1287 isSpaMode,
1288 criticalCss
1289 );
1290 }
1291 if (request.method === "HEAD") {
1292 return new Response(null, {
1293 headers: response.headers,
1294 status: response.status,
1295 statusText: response.statusText
1296 });
1297 }
1298 return response;
1299 };
1300 if (build.entry.module.unstable_instrumentations) {
1301 requestHandler = instrumentHandler(
1302 requestHandler,
1303 build.entry.module.unstable_instrumentations.map((i) => i.handler).filter(Boolean)
1304 );
1305 }
1306 return {
1307 routes,
1308 dataRoutes,
1309 serverMode,
1310 staticHandler,
1311 errorHandler,
1312 requestHandler
1313 };
1314}
1315var createRequestHandler = (build, mode) => {
1316 let _build;
1317 let routes;
1318 let serverMode;
1319 let staticHandler;
1320 let errorHandler;
1321 let _requestHandler;
1322 return async function requestHandler(request, initialContext) {
1323 _build = typeof build === "function" ? await build() : build;
1324 if (typeof build === "function") {
1325 let derived = derive(_build, mode);
1326 routes = derived.routes;
1327 serverMode = derived.serverMode;
1328 staticHandler = derived.staticHandler;
1329 errorHandler = derived.errorHandler;
1330 _requestHandler = derived.requestHandler;
1331 } else if (!routes || !serverMode || !staticHandler || !errorHandler || !_requestHandler) {
1332 let derived = derive(_build, mode);
1333 routes = derived.routes;
1334 serverMode = derived.serverMode;
1335 staticHandler = derived.staticHandler;
1336 errorHandler = derived.errorHandler;
1337 _requestHandler = derived.requestHandler;
1338 }
1339 return _requestHandler(request, initialContext);
1340 };
1341};
1342async function handleManifestRequest(build, routes, url) {
1343 if (build.assets.version !== url.searchParams.get("version")) {
1344 return new Response(null, {
1345 status: 204,
1346 headers: {
1347 "X-Remix-Reload-Document": "true"
1348 }
1349 });
1350 }
1351 let patches = {};
1352 if (url.searchParams.has("paths")) {
1353 let paths = /* @__PURE__ */ new Set();
1354 let pathParam = url.searchParams.get("paths") || "";
1355 let requestedPaths = pathParam.split(",").filter(Boolean);
1356 requestedPaths.forEach((path) => {
1357 if (!path.startsWith("/")) {
1358 path = `/${path}`;
1359 }
1360 let segments = path.split("/").slice(1);
1361 segments.forEach((_, i) => {
1362 let partialPath = segments.slice(0, i + 1).join("/");
1363 paths.add(`/${partialPath}`);
1364 });
1365 });
1366 for (let path of paths) {
1367 let matches = matchServerRoutes(routes, path, build.basename);
1368 if (matches) {
1369 for (let match of matches) {
1370 let routeId = match.route.id;
1371 let route = build.assets.routes[routeId];
1372 if (route) {
1373 patches[routeId] = route;
1374 }
1375 }
1376 }
1377 }
1378 return Response.json(patches, {
1379 headers: {
1380 "Cache-Control": "public, max-age=31536000, immutable"
1381 }
1382 });
1383 }
1384 return new Response("Invalid Request", { status: 400 });
1385}
1386async function handleSingleFetchRequest(serverMode, build, staticHandler, request, handlerUrl, loadContext, handleError) {
1387 let response = request.method !== "GET" ? await singleFetchAction(
1388 build,
1389 serverMode,
1390 staticHandler,
1391 request,
1392 handlerUrl,
1393 loadContext,
1394 handleError
1395 ) : await singleFetchLoaders(
1396 build,
1397 serverMode,
1398 staticHandler,
1399 request,
1400 handlerUrl,
1401 loadContext,
1402 handleError
1403 );
1404 return response;
1405}
1406async function handleDocumentRequest(serverMode, build, staticHandler, request, loadContext, handleError, isSpaMode, criticalCss) {
1407 try {
1408 if (request.method === "POST") {
1409 try {
1410 throwIfPotentialCSRFAttack(
1411 request.headers,
1412 Array.isArray(build.allowedActionOrigins) ? build.allowedActionOrigins : []
1413 );
1414 } catch (e) {
1415 handleError(e);
1416 return new Response("Bad Request", { status: 400 });
1417 }
1418 }
1419 let result = await staticHandler.query(request, {
1420 requestContext: loadContext,
1421 generateMiddlewareResponse: build.future.v8_middleware ? async (query) => {
1422 try {
1423 let innerResult = await query(request);
1424 if (!isResponse(innerResult)) {
1425 innerResult = await renderHtml(innerResult, isSpaMode);
1426 }
1427 return innerResult;
1428 } catch (error) {
1429 handleError(error);
1430 return new Response(null, { status: 500 });
1431 }
1432 } : void 0
1433 });
1434 if (!isResponse(result)) {
1435 result = await renderHtml(result, isSpaMode);
1436 }
1437 return result;
1438 } catch (error) {
1439 handleError(error);
1440 return new Response(null, { status: 500 });
1441 }
1442 async function renderHtml(context, isSpaMode2) {
1443 let headers = getDocumentHeaders(context, build);
1444 if (SERVER_NO_BODY_STATUS_CODES.has(context.statusCode)) {
1445 return new Response(null, { status: context.statusCode, headers });
1446 }
1447 if (context.errors) {
1448 Object.values(context.errors).forEach((err) => {
1449 if (!isRouteErrorResponse(err) || err.error) {
1450 handleError(err);
1451 }
1452 });
1453 context.errors = sanitizeErrors(context.errors, serverMode);
1454 }
1455 let state = {
1456 loaderData: context.loaderData,
1457 actionData: context.actionData,
1458 errors: serializeErrors(context.errors, serverMode)
1459 };
1460 let baseServerHandoff = {
1461 basename: build.basename,
1462 future: build.future,
1463 routeDiscovery: build.routeDiscovery,
1464 ssr: build.ssr,
1465 isSpaMode: isSpaMode2
1466 };
1467 let entryContext = {
1468 manifest: build.assets,
1469 routeModules: createEntryRouteModules(build.routes),
1470 staticHandlerContext: context,
1471 criticalCss,
1472 serverHandoffString: createServerHandoffString({
1473 ...baseServerHandoff,
1474 criticalCss
1475 }),
1476 serverHandoffStream: encodeViaTurboStream(
1477 state,
1478 request.signal,
1479 build.entry.module.streamTimeout,
1480 serverMode
1481 ),
1482 renderMeta: {},
1483 future: build.future,
1484 ssr: build.ssr,
1485 routeDiscovery: build.routeDiscovery,
1486 isSpaMode: isSpaMode2,
1487 serializeError: (err) => serializeError(err, serverMode)
1488 };
1489 let handleDocumentRequestFunction = build.entry.module.default;
1490 try {
1491 return await handleDocumentRequestFunction(
1492 request,
1493 context.statusCode,
1494 headers,
1495 entryContext,
1496 loadContext
1497 );
1498 } catch (error) {
1499 handleError(error);
1500 let errorForSecondRender = error;
1501 if (isResponse(error)) {
1502 try {
1503 let data2 = await unwrapResponse(error);
1504 errorForSecondRender = new ErrorResponseImpl(
1505 error.status,
1506 error.statusText,
1507 data2
1508 );
1509 } catch (e) {
1510 }
1511 }
1512 context = getStaticContextFromError(
1513 staticHandler.dataRoutes,
1514 context,
1515 errorForSecondRender
1516 );
1517 if (context.errors) {
1518 context.errors = sanitizeErrors(context.errors, serverMode);
1519 }
1520 let state2 = {
1521 loaderData: context.loaderData,
1522 actionData: context.actionData,
1523 errors: serializeErrors(context.errors, serverMode)
1524 };
1525 entryContext = {
1526 ...entryContext,
1527 staticHandlerContext: context,
1528 serverHandoffString: createServerHandoffString(baseServerHandoff),
1529 serverHandoffStream: encodeViaTurboStream(
1530 state2,
1531 request.signal,
1532 build.entry.module.streamTimeout,
1533 serverMode
1534 ),
1535 renderMeta: {}
1536 };
1537 try {
1538 return await handleDocumentRequestFunction(
1539 request,
1540 context.statusCode,
1541 headers,
1542 entryContext,
1543 loadContext
1544 );
1545 } catch (error2) {
1546 handleError(error2);
1547 return returnLastResortErrorResponse(error2, serverMode);
1548 }
1549 }
1550 }
1551}
1552async function handleResourceRequest(serverMode, build, staticHandler, routeId, request, loadContext, handleError) {
1553 try {
1554 let result = await staticHandler.queryRoute(request, {
1555 routeId,
1556 requestContext: loadContext,
1557 generateMiddlewareResponse: build.future.v8_middleware ? async (queryRoute) => {
1558 try {
1559 let innerResult = await queryRoute(request);
1560 return handleQueryRouteResult(innerResult);
1561 } catch (error) {
1562 return handleQueryRouteError(error);
1563 }
1564 } : void 0
1565 });
1566 return handleQueryRouteResult(result);
1567 } catch (error) {
1568 return handleQueryRouteError(error);
1569 }
1570 function handleQueryRouteResult(result) {
1571 if (isResponse(result)) {
1572 return result;
1573 }
1574 if (typeof result === "string") {
1575 return new Response(result);
1576 }
1577 return Response.json(result);
1578 }
1579 function handleQueryRouteError(error) {
1580 if (isResponse(error)) {
1581 return error;
1582 }
1583 if (isRouteErrorResponse(error)) {
1584 handleError(error);
1585 return errorResponseToJson(error, serverMode);
1586 }
1587 if (error instanceof Error && error.message === "Expected a response from queryRoute") {
1588 let newError = new Error(
1589 "Expected a Response to be returned from resource route handler"
1590 );
1591 handleError(newError);
1592 return returnLastResortErrorResponse(newError, serverMode);
1593 }
1594 handleError(error);
1595 return returnLastResortErrorResponse(error, serverMode);
1596 }
1597}
1598function errorResponseToJson(errorResponse, serverMode) {
1599 return Response.json(
1600 serializeError(
1601 // @ts-expect-error This is "private" from users but intended for internal use
1602 errorResponse.error || new Error("Unexpected Server Error"),
1603 serverMode
1604 ),
1605 {
1606 status: errorResponse.status,
1607 statusText: errorResponse.statusText
1608 }
1609 );
1610}
1611function returnLastResortErrorResponse(error, serverMode) {
1612 let message = "Unexpected Server Error";
1613 if (serverMode !== "production" /* Production */) {
1614 message += `
1615
1616${String(error)}`;
1617 }
1618 return new Response(message, {
1619 status: 500,
1620 headers: {
1621 "Content-Type": "text/plain"
1622 }
1623 });
1624}
1625function unwrapResponse(response) {
1626 let contentType = response.headers.get("Content-Type");
1627 return contentType && /\bapplication\/json\b/.test(contentType) ? response.body == null ? null : response.json() : response.text();
1628}
1629
1630// lib/server-runtime/sessions.ts
1631function flash(name) {
1632 return `__flash_${name}__`;
1633}
1634var createSession = (initialData = {}, id = "") => {
1635 let map = new Map(Object.entries(initialData));
1636 return {
1637 get id() {
1638 return id;
1639 },
1640 get data() {
1641 return Object.fromEntries(map);
1642 },
1643 has(name) {
1644 return map.has(name) || map.has(flash(name));
1645 },
1646 get(name) {
1647 if (map.has(name)) return map.get(name);
1648 let flashName = flash(name);
1649 if (map.has(flashName)) {
1650 let value = map.get(flashName);
1651 map.delete(flashName);
1652 return value;
1653 }
1654 return void 0;
1655 },
1656 set(name, value) {
1657 map.set(name, value);
1658 },
1659 flash(name, value) {
1660 map.set(flash(name), value);
1661 },
1662 unset(name) {
1663 map.delete(name);
1664 }
1665 };
1666};
1667var isSession = (object) => {
1668 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";
1669};
1670function createSessionStorage({
1671 cookie: cookieArg,
1672 createData,
1673 readData,
1674 updateData,
1675 deleteData
1676}) {
1677 let cookie = isCookie(cookieArg) ? cookieArg : createCookie(cookieArg?.name || "__session", cookieArg);
1678 warnOnceAboutSigningSessionCookie(cookie);
1679 return {
1680 async getSession(cookieHeader, options) {
1681 let id = cookieHeader && await cookie.parse(cookieHeader, options);
1682 let data2 = id && await readData(id);
1683 return createSession(data2 || {}, id || "");
1684 },
1685 async commitSession(session, options) {
1686 let { id, data: data2 } = session;
1687 let expires = options?.maxAge != null ? new Date(Date.now() + options.maxAge * 1e3) : options?.expires != null ? options.expires : cookie.expires;
1688 if (id) {
1689 await updateData(id, data2, expires);
1690 } else {
1691 id = await createData(data2, expires);
1692 }
1693 return cookie.serialize(id, options);
1694 },
1695 async destroySession(session, options) {
1696 await deleteData(session.id);
1697 return cookie.serialize("", {
1698 ...options,
1699 maxAge: void 0,
1700 expires: /* @__PURE__ */ new Date(0)
1701 });
1702 }
1703 };
1704}
1705function warnOnceAboutSigningSessionCookie(cookie) {
1706 warnOnce(
1707 cookie.isSigned,
1708 `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.`
1709 );
1710}
1711
1712// lib/server-runtime/sessions/cookieStorage.ts
1713function createCookieSessionStorage({ cookie: cookieArg } = {}) {
1714 let cookie = isCookie(cookieArg) ? cookieArg : createCookie(cookieArg?.name || "__session", cookieArg);
1715 warnOnceAboutSigningSessionCookie(cookie);
1716 return {
1717 async getSession(cookieHeader, options) {
1718 return createSession(
1719 cookieHeader && await cookie.parse(cookieHeader, options) || {}
1720 );
1721 },
1722 async commitSession(session, options) {
1723 let serializedCookie = await cookie.serialize(session.data, options);
1724 if (serializedCookie.length > 4096) {
1725 throw new Error(
1726 "Cookie length will exceed browser maximum. Length: " + serializedCookie.length
1727 );
1728 }
1729 return serializedCookie;
1730 },
1731 async destroySession(_session, options) {
1732 return cookie.serialize("", {
1733 ...options,
1734 maxAge: void 0,
1735 expires: /* @__PURE__ */ new Date(0)
1736 });
1737 }
1738 };
1739}
1740
1741// lib/server-runtime/sessions/memoryStorage.ts
1742function createMemorySessionStorage({ cookie } = {}) {
1743 let map = /* @__PURE__ */ new Map();
1744 return createSessionStorage({
1745 cookie,
1746 async createData(data2, expires) {
1747 let id = Math.random().toString(36).substring(2, 10);
1748 map.set(id, { data: data2, expires });
1749 return id;
1750 },
1751 async readData(id) {
1752 if (map.has(id)) {
1753 let { data: data2, expires } = map.get(id);
1754 if (!expires || expires > /* @__PURE__ */ new Date()) {
1755 return data2;
1756 }
1757 if (expires) map.delete(id);
1758 }
1759 return null;
1760 },
1761 async updateData(id, data2, expires) {
1762 map.set(id, { data: data2, expires });
1763 },
1764 async deleteData(id) {
1765 map.delete(id);
1766 }
1767 });
1768}
1769
1770// lib/href.ts
1771function href(path, ...args) {
1772 let params = args[0];
1773 let result = trimTrailingSplat(path).replace(
1774 /\/:([\w-]+)(\?)?/g,
1775 // same regex as in .\router\utils.ts: compilePath().
1776 (_, param, questionMark) => {
1777 const isRequired = questionMark === void 0;
1778 const value = params?.[param];
1779 if (isRequired && value === void 0) {
1780 throw new Error(
1781 `Path '${path}' requires param '${param}' but it was not provided`
1782 );
1783 }
1784 return value === void 0 ? "" : "/" + value;
1785 }
1786 );
1787 if (path.endsWith("*")) {
1788 const value = params?.["*"];
1789 if (value !== void 0) {
1790 result += "/" + value;
1791 }
1792 }
1793 return result || "/";
1794}
1795function trimTrailingSplat(path) {
1796 let i = path.length - 1;
1797 let char = path[i];
1798 if (char !== "*" && char !== "/") return path;
1799 i--;
1800 for (; i >= 0; i--) {
1801 if (path[i] !== "/") break;
1802 }
1803 return path.slice(0, i + 1);
1804}
1805
1806// lib/rsc/server.ssr.tsx
1807import * as React4 from "react";
1808
1809// lib/rsc/html-stream/server.ts
1810var encoder2 = new TextEncoder();
1811var trailer = "</body></html>";
1812function injectRSCPayload(rscStream) {
1813 let decoder = new TextDecoder();
1814 let resolveFlightDataPromise;
1815 let flightDataPromise = new Promise(
1816 (resolve) => resolveFlightDataPromise = resolve
1817 );
1818 let startedRSC = false;
1819 let buffered = [];
1820 let timeout = null;
1821 function flushBufferedChunks(controller) {
1822 for (let chunk of buffered) {
1823 let buf = decoder.decode(chunk, { stream: true });
1824 if (buf.endsWith(trailer)) {
1825 buf = buf.slice(0, -trailer.length);
1826 }
1827 controller.enqueue(encoder2.encode(buf));
1828 }
1829 buffered.length = 0;
1830 timeout = null;
1831 }
1832 return new TransformStream({
1833 transform(chunk, controller) {
1834 buffered.push(chunk);
1835 if (timeout) {
1836 return;
1837 }
1838 timeout = setTimeout(async () => {
1839 flushBufferedChunks(controller);
1840 if (!startedRSC) {
1841 startedRSC = true;
1842 writeRSCStream(rscStream, controller).catch((err) => controller.error(err)).then(resolveFlightDataPromise);
1843 }
1844 }, 0);
1845 },
1846 async flush(controller) {
1847 await flightDataPromise;
1848 if (timeout) {
1849 clearTimeout(timeout);
1850 flushBufferedChunks(controller);
1851 }
1852 controller.enqueue(encoder2.encode("</body></html>"));
1853 }
1854 });
1855}
1856async function writeRSCStream(rscStream, controller) {
1857 let decoder = new TextDecoder("utf-8", { fatal: true });
1858 const reader = rscStream.getReader();
1859 try {
1860 let read;
1861 while ((read = await reader.read()) && !read.done) {
1862 const chunk = read.value;
1863 try {
1864 writeChunk(
1865 JSON.stringify(decoder.decode(chunk, { stream: true })),
1866 controller
1867 );
1868 } catch (err) {
1869 let base64 = JSON.stringify(btoa(String.fromCodePoint(...chunk)));
1870 writeChunk(
1871 `Uint8Array.from(atob(${base64}), m => m.codePointAt(0))`,
1872 controller
1873 );
1874 }
1875 }
1876 } finally {
1877 reader.releaseLock();
1878 }
1879 let remaining = decoder.decode();
1880 if (remaining.length) {
1881 writeChunk(JSON.stringify(remaining), controller);
1882 }
1883}
1884function writeChunk(chunk, controller) {
1885 controller.enqueue(
1886 encoder2.encode(
1887 `<script>${escapeScript(
1888 `(self.__FLIGHT_DATA||=[]).push(${chunk})`
1889 )}</script>`
1890 )
1891 );
1892}
1893function escapeScript(script) {
1894 return script.replace(/<!--/g, "<\\!--").replace(/<\/(script)/gi, "</\\$1");
1895}
1896
1897// lib/rsc/errorBoundaries.tsx
1898import React3 from "react";
1899var RSCRouterGlobalErrorBoundary = class extends React3.Component {
1900 constructor(props) {
1901 super(props);
1902 this.state = { error: null, location: props.location };
1903 }
1904 static getDerivedStateFromError(error) {
1905 return { error };
1906 }
1907 static getDerivedStateFromProps(props, state) {
1908 if (state.location !== props.location) {
1909 return { error: null, location: props.location };
1910 }
1911 return { error: state.error, location: state.location };
1912 }
1913 render() {
1914 if (this.state.error) {
1915 return /* @__PURE__ */ React3.createElement(
1916 RSCDefaultRootErrorBoundaryImpl,
1917 {
1918 error: this.state.error,
1919 renderAppShell: true
1920 }
1921 );
1922 } else {
1923 return this.props.children;
1924 }
1925 }
1926};
1927function ErrorWrapper({
1928 renderAppShell,
1929 title,
1930 children
1931}) {
1932 if (!renderAppShell) {
1933 return children;
1934 }
1935 return /* @__PURE__ */ React3.createElement("html", { lang: "en" }, /* @__PURE__ */ React3.createElement("head", null, /* @__PURE__ */ React3.createElement("meta", { charSet: "utf-8" }), /* @__PURE__ */ React3.createElement(
1936 "meta",
1937 {
1938 name: "viewport",
1939 content: "width=device-width,initial-scale=1,viewport-fit=cover"
1940 }
1941 ), /* @__PURE__ */ React3.createElement("title", null, title)), /* @__PURE__ */ React3.createElement("body", null, /* @__PURE__ */ React3.createElement("main", { style: { fontFamily: "system-ui, sans-serif", padding: "2rem" } }, children)));
1942}
1943function RSCDefaultRootErrorBoundaryImpl({
1944 error,
1945 renderAppShell
1946}) {
1947 console.error(error);
1948 let heyDeveloper = /* @__PURE__ */ React3.createElement(
1949 "script",
1950 {
1951 dangerouslySetInnerHTML: {
1952 __html: `
1953 console.log(
1954 "\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."
1955 );
1956 `
1957 }
1958 }
1959 );
1960 if (isRouteErrorResponse(error)) {
1961 return /* @__PURE__ */ React3.createElement(
1962 ErrorWrapper,
1963 {
1964 renderAppShell,
1965 title: "Unhandled Thrown Response!"
1966 },
1967 /* @__PURE__ */ React3.createElement("h1", { style: { fontSize: "24px" } }, error.status, " ", error.statusText),
1968 ENABLE_DEV_WARNINGS ? heyDeveloper : null
1969 );
1970 }
1971 let errorInstance;
1972 if (error instanceof Error) {
1973 errorInstance = error;
1974 } else {
1975 let errorString = error == null ? "Unknown Error" : typeof error === "object" && "toString" in error ? error.toString() : JSON.stringify(error);
1976 errorInstance = new Error(errorString);
1977 }
1978 return /* @__PURE__ */ React3.createElement(ErrorWrapper, { renderAppShell, title: "Application Error!" }, /* @__PURE__ */ React3.createElement("h1", { style: { fontSize: "24px" } }, "Application Error"), /* @__PURE__ */ React3.createElement(
1979 "pre",
1980 {
1981 style: {
1982 padding: "2rem",
1983 background: "hsla(10, 50%, 50%, 0.1)",
1984 color: "red",
1985 overflow: "auto"
1986 }
1987 },
1988 errorInstance.stack
1989 ), heyDeveloper);
1990}
1991function RSCDefaultRootErrorBoundary({
1992 hasRootLayout
1993}) {
1994 let error = useRouteError();
1995 if (hasRootLayout === void 0) {
1996 throw new Error("Missing 'hasRootLayout' prop");
1997 }
1998 return /* @__PURE__ */ React3.createElement(
1999 RSCDefaultRootErrorBoundaryImpl,
2000 {
2001 renderAppShell: !hasRootLayout,
2002 error
2003 }
2004 );
2005}
2006
2007// lib/rsc/route-modules.ts
2008function createRSCRouteModules(payload) {
2009 const routeModules = {};
2010 for (const match of payload.matches) {
2011 populateRSCRouteModules(routeModules, match);
2012 }
2013 return routeModules;
2014}
2015function populateRSCRouteModules(routeModules, matches) {
2016 matches = Array.isArray(matches) ? matches : [matches];
2017 for (const match of matches) {
2018 routeModules[match.id] = {
2019 links: match.links,
2020 meta: match.meta,
2021 default: noopComponent
2022 };
2023 }
2024}
2025var noopComponent = () => null;
2026
2027// lib/rsc/server.ssr.tsx
2028var REACT_USE = "use";
2029var useImpl = React4[REACT_USE];
2030function useSafe(promise) {
2031 if (useImpl) {
2032 return useImpl(promise);
2033 }
2034 throw new Error("React Router v7 requires React 19+ for RSC features.");
2035}
2036async function routeRSCServerRequest({
2037 request,
2038 serverResponse,
2039 createFromReadableStream,
2040 renderHTML,
2041 hydrate = true
2042}) {
2043 const url = new URL(request.url);
2044 const isDataRequest = isReactServerRequest(url);
2045 const respondWithRSCPayload = isDataRequest || isManifestRequest(url) || request.headers.has("rsc-action-id");
2046 if (respondWithRSCPayload || serverResponse.headers.get("React-Router-Resource") === "true") {
2047 return serverResponse;
2048 }
2049 if (!serverResponse.body) {
2050 throw new Error("Missing body in server response");
2051 }
2052 const detectRedirectResponse = serverResponse.clone();
2053 let serverResponseB = null;
2054 if (hydrate) {
2055 serverResponseB = serverResponse.clone();
2056 }
2057 const body = serverResponse.body;
2058 let buffer;
2059 let streamControllers = [];
2060 const createStream = () => {
2061 if (!buffer) {
2062 buffer = [];
2063 return body.pipeThrough(
2064 new TransformStream({
2065 transform(chunk, controller) {
2066 buffer.push(chunk);
2067 controller.enqueue(chunk);
2068 streamControllers.forEach((c) => c.enqueue(chunk));
2069 },
2070 flush() {
2071 streamControllers.forEach((c) => c.close());
2072 streamControllers = [];
2073 }
2074 })
2075 );
2076 }
2077 return new ReadableStream({
2078 start(controller) {
2079 buffer.forEach((chunk) => controller.enqueue(chunk));
2080 streamControllers.push(controller);
2081 }
2082 });
2083 };
2084 let deepestRenderedBoundaryId = null;
2085 const getPayload = () => {
2086 const payloadPromise = Promise.resolve(
2087 createFromReadableStream(createStream())
2088 );
2089 return Object.defineProperties(payloadPromise, {
2090 _deepestRenderedBoundaryId: {
2091 get() {
2092 return deepestRenderedBoundaryId;
2093 },
2094 set(boundaryId) {
2095 deepestRenderedBoundaryId = boundaryId;
2096 }
2097 },
2098 formState: {
2099 get() {
2100 return payloadPromise.then(
2101 (payload) => payload.type === "render" ? payload.formState : void 0
2102 );
2103 }
2104 }
2105 });
2106 };
2107 let renderRedirect;
2108 let renderError;
2109 try {
2110 if (!detectRedirectResponse.body) {
2111 throw new Error("Failed to clone server response");
2112 }
2113 const payload = await createFromReadableStream(
2114 detectRedirectResponse.body
2115 );
2116 if (serverResponse.status === SINGLE_FETCH_REDIRECT_STATUS && payload.type === "redirect") {
2117 const headers2 = new Headers(serverResponse.headers);
2118 headers2.delete("Content-Encoding");
2119 headers2.delete("Content-Length");
2120 headers2.delete("Content-Type");
2121 headers2.delete("X-Remix-Response");
2122 headers2.set("Location", payload.location);
2123 return new Response(serverResponseB?.body || "", {
2124 headers: headers2,
2125 status: payload.status,
2126 statusText: serverResponse.statusText
2127 });
2128 }
2129 let reactHeaders = new Headers();
2130 let status = serverResponse.status;
2131 let statusText = serverResponse.statusText;
2132 let html = await renderHTML(getPayload, {
2133 onError(error) {
2134 if (typeof error === "object" && error && "digest" in error && typeof error.digest === "string") {
2135 renderRedirect = decodeRedirectErrorDigest(error.digest);
2136 if (renderRedirect) {
2137 return error.digest;
2138 }
2139 let routeErrorResponse = decodeRouteErrorResponseDigest(error.digest);
2140 if (routeErrorResponse) {
2141 renderError = routeErrorResponse;
2142 status = routeErrorResponse.status;
2143 statusText = routeErrorResponse.statusText;
2144 return error.digest;
2145 }
2146 }
2147 },
2148 onHeaders(headers2) {
2149 for (const [key, value] of headers2) {
2150 reactHeaders.append(key, value);
2151 }
2152 }
2153 });
2154 const headers = new Headers(reactHeaders);
2155 for (const [key, value] of serverResponse.headers) {
2156 headers.append(key, value);
2157 }
2158 headers.set("Content-Type", "text/html; charset=utf-8");
2159 if (renderRedirect) {
2160 headers.set("Location", renderRedirect.location);
2161 return new Response(html, {
2162 status: renderRedirect.status,
2163 headers
2164 });
2165 }
2166 const redirectTransform = new TransformStream({
2167 flush(controller) {
2168 if (renderRedirect) {
2169 controller.enqueue(
2170 new TextEncoder().encode(
2171 `<meta http-equiv="refresh" content="0;url=${escapeHtml(renderRedirect.location)}"/>`
2172 )
2173 );
2174 }
2175 }
2176 });
2177 if (!hydrate) {
2178 return new Response(html.pipeThrough(redirectTransform), {
2179 status,
2180 statusText,
2181 headers
2182 });
2183 }
2184 if (!serverResponseB?.body) {
2185 throw new Error("Failed to clone server response");
2186 }
2187 const body2 = html.pipeThrough(injectRSCPayload(serverResponseB.body)).pipeThrough(redirectTransform);
2188 return new Response(body2, {
2189 status,
2190 statusText,
2191 headers
2192 });
2193 } catch (reason) {
2194 if (reason instanceof Response) {
2195 return reason;
2196 }
2197 if (renderRedirect) {
2198 return new Response(`Redirect: ${renderRedirect.location}`, {
2199 status: renderRedirect.status,
2200 headers: {
2201 Location: renderRedirect.location
2202 }
2203 });
2204 }
2205 try {
2206 reason = renderError ?? reason;
2207 let [status, statusText] = isRouteErrorResponse(reason) ? [reason.status, reason.statusText] : [500, ""];
2208 let retryRedirect;
2209 let reactHeaders = new Headers();
2210 const html = await renderHTML(
2211 () => {
2212 const decoded = Promise.resolve(
2213 createFromReadableStream(createStream())
2214 );
2215 const payloadPromise = decoded.then(
2216 (payload) => Object.assign(payload, {
2217 status,
2218 errors: deepestRenderedBoundaryId ? {
2219 [deepestRenderedBoundaryId]: reason
2220 } : {}
2221 })
2222 );
2223 return Object.defineProperties(payloadPromise, {
2224 _deepestRenderedBoundaryId: {
2225 get() {
2226 return deepestRenderedBoundaryId;
2227 },
2228 set(boundaryId) {
2229 deepestRenderedBoundaryId = boundaryId;
2230 }
2231 },
2232 formState: {
2233 get() {
2234 return payloadPromise.then(
2235 (payload) => payload.type === "render" ? payload.formState : void 0
2236 );
2237 }
2238 }
2239 });
2240 },
2241 {
2242 onError(error) {
2243 if (typeof error === "object" && error && "digest" in error && typeof error.digest === "string") {
2244 retryRedirect = decodeRedirectErrorDigest(error.digest);
2245 if (retryRedirect) {
2246 return error.digest;
2247 }
2248 let routeErrorResponse = decodeRouteErrorResponseDigest(
2249 error.digest
2250 );
2251 if (routeErrorResponse) {
2252 status = routeErrorResponse.status;
2253 statusText = routeErrorResponse.statusText;
2254 return error.digest;
2255 }
2256 }
2257 },
2258 onHeaders(headers2) {
2259 for (const [key, value] of headers2) {
2260 reactHeaders.append(key, value);
2261 }
2262 }
2263 }
2264 );
2265 const headers = new Headers(reactHeaders);
2266 for (const [key, value] of serverResponse.headers) {
2267 headers.append(key, value);
2268 }
2269 headers.set("Content-Type", "text/html; charset=utf-8");
2270 if (retryRedirect) {
2271 headers.set("Location", retryRedirect.location);
2272 return new Response(html, {
2273 status: retryRedirect.status,
2274 headers
2275 });
2276 }
2277 const retryRedirectTransform = new TransformStream({
2278 flush(controller) {
2279 if (retryRedirect) {
2280 controller.enqueue(
2281 new TextEncoder().encode(
2282 `<meta http-equiv="refresh" content="0;url=${escapeHtml(retryRedirect.location)}"/>`
2283 )
2284 );
2285 }
2286 }
2287 });
2288 if (!hydrate) {
2289 return new Response(html.pipeThrough(retryRedirectTransform), {
2290 status,
2291 statusText,
2292 headers
2293 });
2294 }
2295 if (!serverResponseB?.body) {
2296 throw new Error("Failed to clone server response");
2297 }
2298 const body2 = html.pipeThrough(injectRSCPayload(serverResponseB.body)).pipeThrough(retryRedirectTransform);
2299 return new Response(body2, {
2300 status,
2301 statusText,
2302 headers
2303 });
2304 } catch {
2305 }
2306 throw reason;
2307 }
2308}
2309function RSCStaticRouter({ getPayload }) {
2310 const decoded = getPayload();
2311 const payload = useSafe(decoded);
2312 if (payload.type === "redirect") {
2313 throw new Response(null, {
2314 status: payload.status,
2315 headers: {
2316 Location: payload.location
2317 }
2318 });
2319 }
2320 if (payload.type !== "render") return null;
2321 let patchedLoaderData = { ...payload.loaderData };
2322 for (const match of payload.matches) {
2323 if (shouldHydrateRouteLoader(
2324 match.id,
2325 match.clientLoader,
2326 match.hasLoader,
2327 false
2328 ) && (match.hydrateFallbackElement || !match.hasLoader)) {
2329 delete patchedLoaderData[match.id];
2330 }
2331 }
2332 const context = {
2333 get _deepestRenderedBoundaryId() {
2334 return decoded._deepestRenderedBoundaryId ?? null;
2335 },
2336 set _deepestRenderedBoundaryId(boundaryId) {
2337 decoded._deepestRenderedBoundaryId = boundaryId;
2338 },
2339 actionData: payload.actionData,
2340 actionHeaders: {},
2341 basename: payload.basename,
2342 errors: payload.errors,
2343 loaderData: patchedLoaderData,
2344 loaderHeaders: {},
2345 location: payload.location,
2346 statusCode: 200,
2347 matches: payload.matches.map((match) => ({
2348 params: match.params,
2349 pathname: match.pathname,
2350 pathnameBase: match.pathnameBase,
2351 route: {
2352 id: match.id,
2353 action: match.hasAction || !!match.clientAction,
2354 handle: match.handle,
2355 hasErrorBoundary: match.hasErrorBoundary,
2356 loader: match.hasLoader || !!match.clientLoader,
2357 index: match.index,
2358 path: match.path,
2359 shouldRevalidate: match.shouldRevalidate
2360 }
2361 }))
2362 };
2363 const router = createStaticRouter(
2364 payload.matches.reduceRight((previous, match) => {
2365 const route = {
2366 id: match.id,
2367 action: match.hasAction || !!match.clientAction,
2368 element: match.element,
2369 errorElement: match.errorElement,
2370 handle: match.handle,
2371 hasErrorBoundary: !!match.errorElement,
2372 hydrateFallbackElement: match.hydrateFallbackElement,
2373 index: match.index,
2374 loader: match.hasLoader || !!match.clientLoader,
2375 path: match.path,
2376 shouldRevalidate: match.shouldRevalidate
2377 };
2378 if (previous.length > 0) {
2379 route.children = previous;
2380 }
2381 return [route];
2382 }, []),
2383 context
2384 );
2385 const frameworkContext = {
2386 future: {
2387 // These flags have no runtime impact so can always be false. If we add
2388 // flags that drive runtime behavior they'll need to be proxied through.
2389 v8_middleware: false,
2390 unstable_subResourceIntegrity: false,
2391 unstable_trailingSlashAwareDataRequests: true
2392 // always on for RSC
2393 },
2394 isSpaMode: false,
2395 ssr: true,
2396 criticalCss: "",
2397 manifest: {
2398 routes: {},
2399 version: "1",
2400 url: "",
2401 entry: {
2402 module: "",
2403 imports: []
2404 }
2405 },
2406 routeDiscovery: { mode: "lazy", manifestPath: "/__manifest" },
2407 routeModules: createRSCRouteModules(payload)
2408 };
2409 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(
2410 StaticRouterProvider,
2411 {
2412 context,
2413 router,
2414 hydrate: false,
2415 nonce: payload.nonce
2416 }
2417 ))));
2418}
2419function isReactServerRequest(url) {
2420 return url.pathname.endsWith(".rsc");
2421}
2422function isManifestRequest(url) {
2423 return url.pathname.endsWith(".manifest");
2424}
2425
2426// lib/dom/ssr/errors.ts
2427function deserializeErrors(errors) {
2428 if (!errors) return null;
2429 let entries = Object.entries(errors);
2430 let serialized = {};
2431 for (let [key, val] of entries) {
2432 if (val && val.__type === "RouteErrorResponse") {
2433 serialized[key] = new ErrorResponseImpl(
2434 val.status,
2435 val.statusText,
2436 val.data,
2437 val.internal === true
2438 );
2439 } else if (val && val.__type === "Error") {
2440 if (val.__subType) {
2441 let ErrorConstructor = window[val.__subType];
2442 if (typeof ErrorConstructor === "function") {
2443 try {
2444 let error = new ErrorConstructor(val.message);
2445 error.stack = val.stack;
2446 serialized[key] = error;
2447 } catch (e) {
2448 }
2449 }
2450 }
2451 if (serialized[key] == null) {
2452 let error = new Error(val.message);
2453 error.stack = val.stack;
2454 serialized[key] = error;
2455 }
2456 } else {
2457 serialized[key] = val;
2458 }
2459 }
2460 return serialized;
2461}
2462
2463// lib/dom/ssr/hydration.tsx
2464function getHydrationData({
2465 state,
2466 routes,
2467 getRouteInfo,
2468 location,
2469 basename,
2470 isSpaMode
2471}) {
2472 let hydrationData = {
2473 ...state,
2474 loaderData: { ...state.loaderData }
2475 };
2476 let initialMatches = matchRoutes(routes, location, basename);
2477 if (initialMatches) {
2478 for (let match of initialMatches) {
2479 let routeId = match.route.id;
2480 let routeInfo = getRouteInfo(routeId);
2481 if (shouldHydrateRouteLoader(
2482 routeId,
2483 routeInfo.clientLoader,
2484 routeInfo.hasLoader,
2485 isSpaMode
2486 ) && (routeInfo.hasHydrateFallback || !routeInfo.hasLoader)) {
2487 delete hydrationData.loaderData[routeId];
2488 } else if (!routeInfo.hasLoader) {
2489 hydrationData.loaderData[routeId] = null;
2490 }
2491 }
2492 }
2493 return hydrationData;
2494}
2495
2496export {
2497 ServerRouter,
2498 createRoutesStub,
2499 createCookie,
2500 isCookie,
2501 ServerMode,
2502 setDevServerHooks,
2503 createRequestHandler,
2504 createSession,
2505 isSession,
2506 createSessionStorage,
2507 createCookieSessionStorage,
2508 createMemorySessionStorage,
2509 href,
2510 RSCRouterGlobalErrorBoundary,
2511 RSCDefaultRootErrorBoundary,
2512 populateRSCRouteModules,
2513 routeRSCServerRequest,
2514 RSCStaticRouter,
2515 deserializeErrors,
2516 getHydrationData
2517};