UNPKG

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