INDIE UNPKG

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