Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@remix-run/react

Package Overview
Dependencies
Maintainers
2
Versions
1040
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@remix-run/react - npm Package Compare versions

Comparing version 0.0.0-nightly-910b900-20231207 to 0.0.0-nightly-91184a743-20240823

dist/esm/fog-of-war.js

2

dist/_virtual/_rollupPluginBabelHelpers.js
/**
* @remix-run/react v0.0.0-nightly-910b900-20231207
* @remix-run/react v0.0.0-nightly-91184a743-20240823
*

@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc.

@@ -1,11 +0,14 @@

import { type HydrationState, type Router } from "@remix-run/router";
import type { HydrationState, Router } from "@remix-run/router";
import type { ReactElement } from "react";
import type { EntryContext, FutureConfig } from "./entry";
import type { AssetsManifest, FutureConfig } from "./entry";
import type { RouteModules } from "./routeModules";
declare global {
var __remixContext: {
url: string;
basename?: string;
state: HydrationState;
criticalCss?: string;
future: FutureConfig;
isSpaMode: boolean;
stream: ReadableStream<Uint8Array> | undefined;
streamController: ReadableStreamDefaultController<Uint8Array>;
a?: number;

@@ -19,5 +22,5 @@ dev?: {

var __remixRouteModules: RouteModules;
var __remixManifest: EntryContext["manifest"];
var __remixManifest: AssetsManifest;
var __remixRevalidation: number | undefined;
var __remixClearCriticalCss: () => void;
var __remixClearCriticalCss: (() => void) | undefined;
var $RefreshRuntime$: {

@@ -29,7 +32,2 @@ performReactRefresh: () => void;

}
declare global {
interface ImportMeta {
hot: any;
}
}
/**

@@ -36,0 +34,0 @@ * The entry point for a Remix app when it is rendered in the browser (in

/**
* @remix-run/react v0.0.0-nightly-910b900-20231207
* @remix-run/react v0.0.0-nightly-91184a743-20240823
*

@@ -23,2 +23,5 @@ * Copyright (c) Remix Software Inc.

var routes = require('./routes.js');
var singleFetch = require('./single-fetch.js');
var invariant = require('./invariant.js');
var fogOfWar = require('./fog-of-war.js');

@@ -49,4 +52,4 @@ function _interopNamespace(e) {

let stateDecodingPromise;
let router;
let didServerRenderFallback = false;
let routerInitialized = false;

@@ -66,4 +69,2 @@ let hmrRouterReadyResolve;

});
// The critical CSS can only be cleared, so the reducer always returns undefined
let criticalCssReducer = () => undefined;

@@ -77,55 +78,67 @@ /**

if (!router) {
// Hard reload if the path we tried to load is not the current path.
// This is usually the result of 2 rapid back/forward clicks from an
// external site into a Remix app, where we initially start the load for
// one URL and while the JS chunks are loading a second forward click moves
// us to a new URL. Avoid comparing search params because of CDNs which
// can be configured to ignore certain params and only pathname is relevant
// towards determining the route matches.
let initialPathname = window.__remixContext.url;
let hydratedPathname = window.location.pathname;
if (initialPathname !== hydratedPathname) {
let errorMsg = `Initial URL (${initialPathname}) does not match URL at time of hydration ` + `(${hydratedPathname}), reloading page...`;
console.error(errorMsg);
window.location.reload();
// Get out of here so the reload can happen - don't create the router
// since it'll then kick off unnecessary route.lazy() loads
return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null);
// When single fetch is enabled, we need to suspend until the initial state
// snapshot is decoded into window.__remixContext.state
if (window.__remixContext.future.unstable_singleFetch) {
// Note: `stateDecodingPromise` is not coupled to `router` - we'll reach this
// code potentially many times waiting for our state to arrive, but we'll
// then only get past here and create the `router` one time
if (!stateDecodingPromise) {
let stream = window.__remixContext.stream;
invariant(stream, "No stream found for single fetch decoding");
window.__remixContext.stream = undefined;
stateDecodingPromise = singleFetch.decodeViaTurboStream(stream, window).then(value => {
window.__remixContext.state = value.value;
stateDecodingPromise.value = true;
}).catch(e => {
stateDecodingPromise.error = e;
});
}
if (stateDecodingPromise.error) {
throw stateDecodingPromise.error;
}
if (!stateDecodingPromise.value) {
throw stateDecodingPromise;
}
}
let routes$1 = routes.createClientRoutes(window.__remixManifest.routes, window.__remixRouteModules, window.__remixContext.state, window.__remixContext.future);
// Create a shallow clone of `loaderData` we can mutate for partial hydration.
// When a route exports a `clientLoader` and a `HydrateFallback`, the SSR will
// render the fallback so we need the client to do the same for hydration.
// The server loader data has already been exposed to these route `clientLoader`'s
// in `createClientRoutes` above, so we need to clear out the version we pass to
// `createBrowserRouter` so it initializes and runs the client loaders.
let hydrationData = {
...window.__remixContext.state,
loaderData: {
...window.__remixContext.state.loaderData
}
};
let initialMatches = reactRouterDom.matchRoutes(routes$1, window.location);
if (initialMatches) {
for (let match of initialMatches) {
let routeId = match.route.id;
let route = window.__remixRouteModules[routeId];
let manifestRoute = window.__remixManifest.routes[routeId];
if (route && route.clientLoader && route.HydrateFallback) {
hydrationData.loaderData[routeId] = undefined;
didServerRenderFallback = true;
} else if (manifestRoute && !manifestRoute.hasLoader) {
// Since every Remix route gets a `loader` on the client side to load
// the route JS module, we need to add a `null` value to `loaderData`
// for any routes that don't have server loaders so our partial
// hydration logic doesn't kick off the route module loaders during
// hydration
hydrationData.loaderData[routeId] = null;
let routes$1 = routes.createClientRoutes(window.__remixManifest.routes, window.__remixRouteModules, window.__remixContext.state, window.__remixContext.future, window.__remixContext.isSpaMode);
let hydrationData = undefined;
if (!window.__remixContext.isSpaMode) {
// Create a shallow clone of `loaderData` we can mutate for partial hydration.
// When a route exports a `clientLoader` and a `HydrateFallback`, the SSR will
// render the fallback so we need the client to do the same for hydration.
// The server loader data has already been exposed to these route `clientLoader`'s
// in `createClientRoutes` above, so we need to clear out the version we pass to
// `createBrowserRouter` so it initializes and runs the client loaders.
hydrationData = {
...window.__remixContext.state,
loaderData: {
...window.__remixContext.state.loaderData
}
};
let initialMatches = reactRouterDom.matchRoutes(routes$1, window.location, window.__remixContext.basename);
if (initialMatches) {
for (let match of initialMatches) {
let routeId = match.route.id;
let route = window.__remixRouteModules[routeId];
let manifestRoute = window.__remixManifest.routes[routeId];
// Clear out the loaderData to avoid rendering the route component when the
// route opted into clientLoader hydration and either:
// * gave us a HydrateFallback
// * or doesn't have a server loader and we have no data to render
if (route && routes.shouldHydrateRouteLoader(manifestRoute, route, window.__remixContext.isSpaMode) && (route.HydrateFallback || !manifestRoute.hasLoader)) {
hydrationData.loaderData[routeId] = undefined;
} else if (manifestRoute && !manifestRoute.hasLoader) {
// Since every Remix route gets a `loader` on the client side to load
// the route JS module, we need to add a `null` value to `loaderData`
// for any routes that don't have server loaders so our partial
// hydration logic doesn't kick off the route module loaders during
// hydration
hydrationData.loaderData[routeId] = null;
}
}
}
if (hydrationData && hydrationData.errors) {
hydrationData.errors = errors.deserializeErrors(hydrationData.errors);
}
}
if (hydrationData && hydrationData.errors) {
hydrationData.errors = errors.deserializeErrors(hydrationData.errors);
}

@@ -137,2 +150,3 @@ // We don't use createBrowserRouter here because we need fine-grained control

history: router$1.createBrowserHistory(),
basename: window.__remixContext.basename,
future: {

@@ -143,11 +157,16 @@ v7_normalizeFormMethod: true,

v7_prependBasename: true,
v7_relativeSplatPath: window.__remixContext.future.v3_relativeSplatPath
v7_relativeSplatPath: window.__remixContext.future.v3_relativeSplatPath,
// Single fetch enables this underlying behavior
v7_skipActionErrorRevalidation: window.__remixContext.future.unstable_singleFetch === true
},
hydrationData,
mapRouteProperties: reactRouter.UNSAFE_mapRouteProperties
mapRouteProperties: reactRouter.UNSAFE_mapRouteProperties,
unstable_dataStrategy: window.__remixContext.future.unstable_singleFetch ? singleFetch.getSingleFetchDataStrategy(window.__remixManifest, window.__remixRouteModules) : undefined,
unstable_patchRoutesOnNavigation: fogOfWar.getPatchRoutesOnNavigationFunction(window.__remixManifest, window.__remixRouteModules, window.__remixContext.future, window.__remixContext.isSpaMode, window.__remixContext.basename)
});
// As long as we didn't SSR a `HydrateFallback`, we can initialize immediately since
// there's no initial client-side data loading to perform
if (!didServerRenderFallback) {
// We can call initialize() immediately if the router doesn't have any
// loaders to run on hydration
if (router.state.initialized) {
routerInitialized = true;
router.initialize();

@@ -169,18 +188,17 @@ }

// server HTML. This allows our HMR logic to clear the critical CSS state.
// eslint-disable-next-line react-hooks/rules-of-hooks
let [criticalCss, clearCriticalCss] = React__namespace.useReducer(criticalCssReducer, window.__remixContext.criticalCss);
window.__remixClearCriticalCss = clearCriticalCss;
let [criticalCss, setCriticalCss] = React__namespace.useState(process.env.NODE_ENV === "development" ? window.__remixContext.criticalCss : undefined);
if (process.env.NODE_ENV === "development") {
window.__remixClearCriticalCss = () => setCriticalCss(undefined);
}
// This is due to the short circuit return above when the pathname doesn't
// match and we force a hard reload. This is an exceptional scenario in which
// we can't hydrate anyway.
// eslint-disable-next-line react-hooks/rules-of-hooks
let [location, setLocation] = React__namespace.useState(router.state.location);
// eslint-disable-next-line react-hooks/rules-of-hooks
React__namespace.useLayoutEffect(() => {
// If we rendered a `HydrateFallback` on the server, delay initialization until
// after we've hydrated with the `HydrateFallback` in case the client loaders
// are synchronous
if (didServerRenderFallback && !routerInitialized) {
// If we had to run clientLoaders on hydration, we delay initialization until
// after we've hydrated to avoid hydration issues from synchronous client loaders
if (!routerInitialized) {
routerInitialized = true;

@@ -190,4 +208,2 @@ router.initialize();

}, []);
// eslint-disable-next-line react-hooks/rules-of-hooks
React__namespace.useLayoutEffect(() => {

@@ -200,2 +216,3 @@ return router.subscribe(newState => {

}, [location]);
fogOfWar.useFogOFWarDiscovery(router, window.__remixManifest, window.__remixRouteModules, window.__remixContext.future, window.__remixContext.isSpaMode);

@@ -206,20 +223,26 @@ // We need to include a wrapper RemixErrorBoundary here in case the root error

// out of there
return /*#__PURE__*/React__namespace.createElement(components.RemixContext.Provider, {
value: {
manifest: window.__remixManifest,
routeModules: window.__remixRouteModules,
future: window.__remixContext.future,
criticalCss
}
}, /*#__PURE__*/React__namespace.createElement(errorBoundaries.RemixErrorBoundary, {
location: location
}, /*#__PURE__*/React__namespace.createElement(reactRouterDom.RouterProvider, {
router: router,
fallbackElement: null,
future: {
v7_startTransition: true
}
})));
return (
/*#__PURE__*/
// This fragment is important to ensure we match the <RemixServer> JSX
// structure so that useId values hydrate correctly
React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(components.RemixContext.Provider, {
value: {
manifest: window.__remixManifest,
routeModules: window.__remixRouteModules,
future: window.__remixContext.future,
criticalCss,
isSpaMode: window.__remixContext.isSpaMode
}
}, /*#__PURE__*/React__namespace.createElement(errorBoundaries.RemixErrorBoundary, {
location: location
}, /*#__PURE__*/React__namespace.createElement(reactRouterDom.RouterProvider, {
router: router,
fallbackElement: null,
future: {
v7_startTransition: true
}
}))), window.__remixContext.future.unstable_singleFetch ? /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null) : null)
);
}
exports.RemixBrowser = RemixBrowser;
import * as React from "react";
import type { UIMatch as UIMatchRR } from "@remix-run/router";
import type { FetcherWithComponents, LinkProps, NavLinkProps } from "react-router-dom";
import type { FetcherWithComponents, FormProps, LinkProps, NavLinkProps } from "react-router-dom";
import { useFetcher as useFetcherRR } from "react-router-dom";

@@ -11,3 +11,11 @@ import type { SerializeFrom } from "@remix-run/server-runtime";

export declare const RemixContext: React.Context<RemixContextObject | undefined>;
export declare function useRemixContext(): RemixContextObject;
/**
* Defines the discovery behavior of the link:
*
* - "render": Eagerly discover when the link is rendered (default)
* - "none": No eager discovery - discover when the link is clicked
*/
export type DiscoverBehavior = "render" | "none";
/**
* Defines the prefetching behavior of the link:

@@ -22,5 +30,7 @@ *

export interface RemixLinkProps extends LinkProps {
discover?: DiscoverBehavior;
prefetch?: PrefetchBehavior;
}
export interface RemixNavLinkProps extends NavLinkProps {
discover?: DiscoverBehavior;
prefetch?: PrefetchBehavior;

@@ -43,2 +53,13 @@ }

export { Link };
export interface RemixFormProps extends FormProps {
discover?: DiscoverBehavior;
}
/**
* This component renders a form tag and is the primary way the user will
* submit information via your website.
*
* @see https://remix.run/components/form
*/
declare let Form: React.ForwardRefExoticComponent<RemixFormProps & React.RefAttributes<HTMLFormElement>>;
export { Form };
export declare function composeEventHandlers<EventType extends React.SyntheticEvent | Event>(theirHandler: ((event: EventType) => any) | undefined, ourHandler: (event: EventType) => any): (event: EventType) => any;

@@ -125,3 +146,3 @@ /**

*/
export declare const LiveReload: (() => null) | (({ origin, port, timeoutMs, nonce, }: {
export declare const LiveReload: ({ origin, port, timeoutMs, nonce, }: {
origin?: string | undefined;

@@ -131,2 +152,2 @@ port?: number | undefined;

nonce?: string | undefined;
}) => React.JSX.Element);
}) => React.JSX.Element | null;
/**
* @remix-run/react v0.0.0-nightly-910b900-20231207
* @remix-run/react v0.0.0-nightly-91184a743-20240823
*

@@ -21,2 +21,4 @@ * Copyright (c) Remix Software Inc.

var markup = require('./markup.js');
var singleFetch = require('./single-fetch.js');
var fogOfWar = require('./fog-of-war.js');

@@ -69,2 +71,9 @@ function _interopNamespace(e) {

/**
* Defines the discovery behavior of the link:
*
* - "render": Eagerly discover when the link is rendered (default)
* - "none": No eager discovery - discover when the link is clicked
*/
/**
* Defines the prefetching behavior of the link:

@@ -77,2 +86,3 @@ *

*/
function usePrefetchBehavior(prefetch, theirElementProps) {

@@ -138,2 +148,5 @@ let [maybePrefetch, setMaybePrefetch] = React__namespace.useState(false);

const ABSOLUTE_URL_REGEX = /^(?:[a-z][a-z0-9+.-]*:|\/\/)/i;
function getDiscoverAttr(discover, isAbsolute, reloadDocument) {
return discover === "render" && !isAbsolute && !reloadDocument ? "true" : undefined;
}

@@ -148,2 +161,3 @@ /**

prefetch = "none",
discover = "render",
...props

@@ -156,3 +170,4 @@ }, forwardedRef) => {

ref: mergeRefs(forwardedRef, ref),
to: to
to: to,
"data-discover": getDiscoverAttr(discover, isAbsolute, props.reloadDocument)
})), shouldPrefetch && !isAbsolute ? /*#__PURE__*/React__namespace.createElement(PrefetchPageLinks, {

@@ -173,2 +188,3 @@ page: href

prefetch = "none",
discover = "render",
...props

@@ -181,3 +197,4 @@ }, forwardedRef) => {

ref: mergeRefs(forwardedRef, ref),
to: to
to: to,
"data-discover": getDiscoverAttr(discover, isAbsolute, props.reloadDocument)
})), shouldPrefetch && !isAbsolute ? /*#__PURE__*/React__namespace.createElement(PrefetchPageLinks, {

@@ -188,2 +205,19 @@ page: href

Link.displayName = "Link";
/**
* This component renders a form tag and is the primary way the user will
* submit information via your website.
*
* @see https://remix.run/components/form
*/
let Form = /*#__PURE__*/React__namespace.forwardRef(({
discover = "render",
...props
}, forwardedRef) => {
let isAbsolute = typeof props.action === "string" && ABSOLUTE_URL_REGEX.test(props.action);
return /*#__PURE__*/React__namespace.createElement(reactRouterDom.Form, _rollupPluginBabelHelpers["extends"]({}, props, {
ref: forwardedRef,
"data-discover": getDiscoverAttr(discover, isAbsolute, props.reloadDocument)
}));
});
Form.displayName = "Form";
function composeEventHandlers(theirHandler, ourHandler) {

@@ -198,2 +232,18 @@ return event => {

// Return the matches actively being displayed:
// - In SPA Mode we only SSR/hydrate the root match, and include all matches
// after hydration. This lets the router handle initial match loads via lazy().
// - When an error boundary is rendered, we slice off matches up to the
// boundary for <Links>/<Meta>
function getActiveMatches(matches, errors, isSpaMode) {
if (isSpaMode && !isHydrated) {
return [matches[0]];
}
if (errors) {
let errorIdx = matches.findIndex(m => errors[m.route.id] !== undefined);
return matches.slice(0, errorIdx + 1);
}
return matches;
}
/**

@@ -206,2 +256,3 @@ * Renders the `<link>` tags for the current routes.

let {
isSpaMode,
manifest,

@@ -215,3 +266,3 @@ routeModules,

} = useDataRouterStateContext();
let matches = errors ? routerMatches.slice(0, routerMatches.findIndex(m => errors[m.route.id]) + 1) : routerMatches;
let matches = getActiveMatches(routerMatches, errors, isSpaMode);
let keyedLinks = React__namespace.useMemo(() => links.getKeyedLinksForMatches(matches, routeModules, manifest), [matches, routeModules, manifest]);

@@ -248,3 +299,3 @@ return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, criticalCss ? /*#__PURE__*/React__namespace.createElement("style", {

} = useDataRouterContext();
let matches = React__namespace.useMemo(() => reactRouterDom.matchRoutes(router.routes, page), [router.routes, page]);
let matches = React__namespace.useMemo(() => reactRouterDom.matchRoutes(router.routes, page, router.basename), [router.routes, page, router.basename]);
if (!matches) {

@@ -285,3 +336,5 @@ console.warn(`Tried to prefetch ${page} but no routes matched.`);

let {
manifest
future,
manifest,
routeModules
} = useRemixContext();

@@ -299,9 +352,25 @@ let {

let keyedPrefetchLinks = useKeyedPrefetchLinks(newMatchesForAssets);
return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, dataHrefs.map(href => /*#__PURE__*/React__namespace.createElement("link", _rollupPluginBabelHelpers["extends"]({
let linksToRender = null;
if (!future.unstable_singleFetch) {
// Non-single-fetch prefetching
linksToRender = dataHrefs.map(href => /*#__PURE__*/React__namespace.createElement("link", _rollupPluginBabelHelpers["extends"]({
key: href,
rel: "prefetch",
as: "fetch",
href: href
}, linkProps)));
} else if (newMatchesForData.length > 0) {
// Single-fetch with routes that require data
let url = singleFetch.addRevalidationParam(manifest, routeModules, nextMatches.map(m => m.route), newMatchesForData.map(m => m.route), singleFetch.singleFetchUrl(page));
if (url.searchParams.get("_routes") !== "") {
linksToRender = /*#__PURE__*/React__namespace.createElement("link", _rollupPluginBabelHelpers["extends"]({
key: url.pathname + url.search,
rel: "prefetch",
as: "fetch",
href: url.pathname + url.search
}, linkProps));
}
} else ;
return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, linksToRender, moduleHrefs.map(href => /*#__PURE__*/React__namespace.createElement("link", _rollupPluginBabelHelpers["extends"]({
key: href,
rel: "prefetch",
as: "fetch",
href: href
}, linkProps))), moduleHrefs.map(href => /*#__PURE__*/React__namespace.createElement("link", _rollupPluginBabelHelpers["extends"]({
key: href,
rel: "modulepreload",

@@ -328,2 +397,3 @@ href: href

let {
isSpaMode,
routeModules

@@ -337,8 +407,6 @@ } = useRemixContext();

let location = reactRouterDom.useLocation();
let _matches = routerMatches;
let _matches = getActiveMatches(routerMatches, errors, isSpaMode);
let error = null;
if (errors) {
let errorIdx = routerMatches.findIndex(m => errors[m.route.id]);
_matches = routerMatches.slice(0, errorIdx + 1);
error = errors[routerMatches[errorIdx].route.id];
error = errors[_matches[_matches.length - 1].route.id];
}

@@ -467,3 +535,6 @@ let meta = [];

abortDelay,
serializeError
serializeError,
isSpaMode,
future,
renderMeta
} = useRemixContext();

@@ -476,5 +547,12 @@ let {

let {
matches
matches: routerMatches
} = useDataRouterStateContext();
let navigation = reactRouterDom.useNavigation();
let enableFogOfWar = fogOfWar.isFogOfWarEnabled(future, isSpaMode);
// Let <RemixServer> know that we hydrated and we should render the single
// fetch streaming scripts
if (renderMeta) {
renderMeta.didRenderScripts = true;
}
let matches = getActiveMatches(routerMatches, null, isSpaMode);
React__namespace.useEffect(() => {

@@ -522,4 +600,10 @@ isHydrated = true;

var _manifest$hmr;
let contextScript = staticContext ? `window.__remixContext = ${serverHandoffString};` : " ";
let activeDeferreds = staticContext === null || staticContext === void 0 ? void 0 : staticContext.activeDeferreds;
let streamScript = future.unstable_singleFetch ?
// prettier-ignore
"window.__remixContext.stream = new ReadableStream({" + "start(controller){" + "window.__remixContext.streamController = controller;" + "}" + "}).pipeThrough(new TextEncoderStream());" : "";
let contextScript = staticContext ? `window.__remixContext = ${serverHandoffString};${streamScript}` : " ";
// When single fetch is enabled, deferred is handled by turbo-stream
let activeDeferreds = future.unstable_singleFetch ? undefined : staticContext === null || staticContext === void 0 ? void 0 : staticContext.activeDeferreds;
// This sets up the __remixContext with utility functions used by the

@@ -562,4 +646,7 @@ // deferred scripts.

}).join("\n") + (deferredScripts.length > 0 ? `__remixContext.a=${deferredScripts.length};` : "");
let routeModulesScript = !isStatic ? " " : `${(_manifest$hmr = manifest.hmr) !== null && _manifest$hmr !== void 0 && _manifest$hmr.runtime ? `import ${JSON.stringify(manifest.hmr.runtime)};` : ""}import ${JSON.stringify(manifest.url)};
let routeModulesScript = !isStatic ? " " : `${(_manifest$hmr = manifest.hmr) !== null && _manifest$hmr !== void 0 && _manifest$hmr.runtime ? `import ${JSON.stringify(manifest.hmr.runtime)};` : ""}${enableFogOfWar ? "" : `import ${JSON.stringify(manifest.url)}`};
${matches.map((match, index) => `import * as route${index} from ${JSON.stringify(manifest.routes[match.route.id].module)};`).join("\n")}
${enableFogOfWar ?
// Inline a minimal manifest with the SSR matches
`window.__remixManifest = ${JSON.stringify(fogOfWar.getPartialManifest(manifest, router), null, 2)};` : ""}
window.__remixRouteModules = {${matches.map((match, index) => `${JSON.stringify(match.route.id)}:route${index}`).join(",")}};

@@ -593,14 +680,3 @@

}
// avoid waterfall when importing the next route module
let nextMatches = React__namespace.useMemo(() => {
if (navigation.location) {
// FIXME: can probably use transitionManager `nextMatches`
let matches = reactRouterDom.matchRoutes(router.routes, navigation.location);
invariant(matches, `No routes match path "${navigation.location.pathname}"`);
return matches;
}
return [];
}, [navigation.location, router.routes]);
let routePreloads = matches.concat(nextMatches).map(match => {
let routePreloads = matches.map(match => {
let route = manifest.routes[match.route.id];

@@ -610,7 +686,7 @@ return (route.imports || []).concat([route.module]);

let preloads = isHydrated ? [] : manifest.entry.imports.concat(routePreloads);
return isHydrated ? null : /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement("link", {
return isHydrated ? null : /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, !enableFogOfWar ? /*#__PURE__*/React__namespace.createElement("link", {
rel: "modulepreload",
href: manifest.url,
crossOrigin: props.crossOrigin
}), /*#__PURE__*/React__namespace.createElement("link", {
}) : null, /*#__PURE__*/React__namespace.createElement("link", {
rel: "modulepreload",

@@ -749,3 +825,3 @@ href: manifest.entry.module,

process.env.NODE_ENV !== "development" ? () => null : function LiveReload({
origin = process.env.REMIX_DEV_ORIGIN,
origin,
port,

@@ -755,2 +831,3 @@ timeoutMs = 1000,

}) {
origin ??= process.env.REMIX_DEV_ORIGIN;
let js = String.raw;

@@ -865,2 +942,3 @@ return /*#__PURE__*/React__namespace.createElement("script", {

exports.Await = Await;
exports.Form = Form;
exports.Link = Link;

@@ -879,2 +957,3 @@ exports.Links = Links;

exports.useMatches = useMatches;
exports.useRemixContext = useRemixContext;
exports.useRouteLoaderData = useRouteLoaderData;

@@ -14,2 +14,3 @@ import { UNSAFE_DeferredData as DeferredData } from "@remix-run/router";

export declare function fetchData(request: Request, routeId: string, retry?: number): Promise<Response | Error>;
export declare function createRequestInit(request: Request): Promise<RequestInit>;
export declare function parseDeferredReadableStream(stream: ReadableStream<Uint8Array>): Promise<DeferredData>;
/**
* @remix-run/react v0.0.0-nightly-910b900-20231207
* @remix-run/react v0.0.0-nightly-91184a743-20240823
*

@@ -31,3 +31,3 @@ * Copyright (c) Remix Software Inc.

// server, and instead receive a 4xx/5xx from somewhere in between (like
// Cloudflare), then we get a false negative n the isErrorResponse check and
// Cloudflare), then we get a false negative in the isErrorResponse check and
// we incorrectly assume that the user returns the 4xx/5xx response and

@@ -57,27 +57,2 @@ // consider it successful. To alleviate this, we add X-Remix-Response to any

url.searchParams.set("_data", routeId);
let init = {
signal: request.signal
};
if (request.method !== "GET") {
init.method = request.method;
let contentType = request.headers.get("Content-Type");
// Check between word boundaries instead of startsWith() due to the last
// paragraph of https://httpwg.org/specs/rfc9110.html#field.content-type
if (contentType && /\bapplication\/json\b/.test(contentType)) {
init.headers = {
"Content-Type": contentType
};
init.body = JSON.stringify(await request.json());
} else if (contentType && /\btext\/plain\b/.test(contentType)) {
init.headers = {
"Content-Type": contentType
};
init.body = await request.text();
} else if (contentType && /\bapplication\/x-www-form-urlencoded\b/.test(contentType)) {
init.body = new URLSearchParams(await request.text());
} else {
init.body = await request.formData();
}
}
if (retry > 0) {

@@ -88,2 +63,3 @@ // Retry up to 3 times waiting 50, 250, 1250 ms

}
let init = await createRequestInit(request);
let revalidation = window.__remixRevalidation;

@@ -110,2 +86,30 @@ let response = await fetch(url.href, init).catch(error => {

}
async function createRequestInit(request) {
let init = {
signal: request.signal
};
if (request.method !== "GET") {
init.method = request.method;
let contentType = request.headers.get("Content-Type");
// Check between word boundaries instead of startsWith() due to the last
// paragraph of https://httpwg.org/specs/rfc9110.html#field.content-type
if (contentType && /\bapplication\/json\b/.test(contentType)) {
init.headers = {
"Content-Type": contentType
};
init.body = JSON.stringify(await request.json());
} else if (contentType && /\btext\/plain\b/.test(contentType)) {
init.headers = {
"Content-Type": contentType
};
init.body = await request.text();
} else if (contentType && /\bapplication\/x-www-form-urlencoded\b/.test(contentType)) {
init.body = new URLSearchParams(await request.text());
} else {
init.body = await request.formData();
}
}
return init;
}
const DEFERRED_VALUE_PLACEHOLDER_PREFIX = "__deferred_promise:";

@@ -271,2 +275,3 @@ async function parseDeferredReadableStream(stream) {

exports.createRequestInit = createRequestInit;
exports.fetchData = fetchData;

@@ -273,0 +278,0 @@ exports.isCatchResponse = isCatchResponse;

@@ -14,7 +14,19 @@ import type { StaticHandlerContext } from "@remix-run/router";

future: FutureConfig;
isSpaMode: boolean;
abortDelay?: number;
serializeError?(error: Error): SerializedError;
renderMeta?: {
didRenderScripts?: boolean;
streamCache?: Record<number, Promise<void> & {
result?: {
done: boolean;
value: string;
};
error?: unknown;
}>;
};
}
export interface EntryContext extends RemixContextObject {
staticHandlerContext: StaticHandlerContext;
serverHandoffStream?: ReadableStream<Uint8Array>;
}

@@ -24,2 +36,4 @@ export interface FutureConfig {

v3_relativeSplatPath: boolean;
unstable_lazyRouteDiscovery: boolean;
unstable_singleFetch: boolean;
}

@@ -26,0 +40,0 @@ export interface AssetsManifest {

@@ -5,2 +5,3 @@ import * as React from "react";

location: Location;
isOutsideRemixApp?: boolean;
error?: Error;

@@ -26,5 +27,12 @@ }>;

*/
export declare function RemixRootDefaultErrorBoundary({ error }: {
export declare function RemixRootDefaultErrorBoundary({ error, isOutsideRemixApp, }: {
error: unknown;
isOutsideRemixApp?: boolean;
}): React.JSX.Element;
export declare function BoundaryShell({ title, renderScripts, isOutsideRemixApp, children, }: {
title: string;
renderScripts?: boolean;
isOutsideRemixApp?: boolean;
children: React.ReactNode | React.ReactNode[];
}): string | number | boolean | Iterable<React.ReactNode> | React.JSX.Element | null | undefined;
export {};
/**
* @remix-run/react v0.0.0-nightly-910b900-20231207
* @remix-run/react v0.0.0-nightly-91184a743-20240823
*

@@ -17,2 +17,3 @@ * Copyright (c) Remix Software Inc.

var reactRouterDom = require('react-router-dom');
var components = require('./components.js');

@@ -81,3 +82,4 @@ function _interopNamespace(e) {

return /*#__PURE__*/React__namespace.createElement(RemixRootDefaultErrorBoundary, {
error: this.state.error
error: this.state.error,
isOutsideRemixApp: true
});

@@ -94,5 +96,15 @@ } else {

function RemixRootDefaultErrorBoundary({
error
error,
isOutsideRemixApp
}) {
console.error(error);
let heyDeveloper = /*#__PURE__*/React__namespace.createElement("script", {
dangerouslySetInnerHTML: {
__html: `
console.log(
"💿 Hey developer 👋. You can provide a way better UX than this when your app throws errors. Check out https://remix.run/guides/errors for more information."
);
`
}
});
if (reactRouterDom.isRouteErrorResponse(error)) {

@@ -103,6 +115,5 @@ return /*#__PURE__*/React__namespace.createElement(BoundaryShell, {

style: {
fontFamily: "system-ui, sans-serif",
padding: "2rem"
fontSize: "24px"
}
}, error.status, " ", error.statusText));
}, error.status, " ", error.statusText), heyDeveloper);
}

@@ -117,8 +128,4 @@ let errorInstance;

return /*#__PURE__*/React__namespace.createElement(BoundaryShell, {
title: "Application Error!"
}, /*#__PURE__*/React__namespace.createElement("main", {
style: {
fontFamily: "system-ui, sans-serif",
padding: "2rem"
}
title: "Application Error!",
isOutsideRemixApp: isOutsideRemixApp
}, /*#__PURE__*/React__namespace.createElement("h1", {

@@ -135,8 +142,34 @@ style: {

}
}, errorInstance.stack)));
}, errorInstance.stack), heyDeveloper);
}
function BoundaryShell({
title,
renderScripts,
isOutsideRemixApp,
children
}) {
var _routeModules$root;
let {
routeModules
} = components.useRemixContext();
// Generally speaking, when the root route has a Layout we want to use that
// as the app shell instead of the default `BoundaryShell` wrapper markup below.
// This is true for `loader`/`action` errors, most render errors, and
// `HydrateFallback` scenarios.
// However, render errors thrown from the `Layout` present a bit of an issue
// because if the `Layout` itself throws during the `ErrorBoundary` pass and
// we bubble outside the `RouterProvider` to the wrapping `RemixErrorBoundary`,
// by returning only `children` here we'll be trying to append a `<div>` to
// the `document` and the DOM will throw, putting React into an error/hydration
// loop.
// Instead, if we're ever rendering from the outermost `RemixErrorBoundary`
// during hydration that wraps `RouterProvider`, then we can't trust the
// `Layout` and should fallback to the default app shell so we're always
// returning an `<html>` document.
if ((_routeModules$root = routeModules.root) !== null && _routeModules$root !== void 0 && _routeModules$root.Layout && !isOutsideRemixApp) {
return children;
}
return /*#__PURE__*/React__namespace.createElement("html", {

@@ -149,14 +182,12 @@ lang: "en"

content: "width=device-width,initial-scale=1,viewport-fit=cover"
}), /*#__PURE__*/React__namespace.createElement("title", null, title)), /*#__PURE__*/React__namespace.createElement("body", null, children, /*#__PURE__*/React__namespace.createElement("script", {
dangerouslySetInnerHTML: {
__html: `
console.log(
"💿 Hey developer 👋. You can provide a way better UX than this when your app throws errors. Check out https://remix.run/guides/errors for more information."
);
`
}), /*#__PURE__*/React__namespace.createElement("title", null, title)), /*#__PURE__*/React__namespace.createElement("body", null, /*#__PURE__*/React__namespace.createElement("main", {
style: {
fontFamily: "system-ui, sans-serif",
padding: "2rem"
}
})));
}, children, renderScripts ? /*#__PURE__*/React__namespace.createElement(components.Scripts, null) : null)));
}
exports.BoundaryShell = BoundaryShell;
exports.RemixErrorBoundary = RemixErrorBoundary;
exports.RemixRootDefaultErrorBoundary = RemixRootDefaultErrorBoundary;
/**
* @remix-run/react v0.0.0-nightly-910b900-20231207
* @remix-run/react v0.0.0-nightly-91184a743-20240823
*

@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc.

/**
* @remix-run/react v0.0.0-nightly-910b900-20231207
* @remix-run/react v0.0.0-nightly-91184a743-20240823
*

@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc.

/**
* @remix-run/react v0.0.0-nightly-910b900-20231207
* @remix-run/react v0.0.0-nightly-91184a743-20240823
*

@@ -18,3 +18,6 @@ * Copyright (c) Remix Software Inc.

import { deserializeErrors } from './errors.js';
import { createClientRoutesWithHMRRevalidationOptOut, createClientRoutes } from './routes.js';
import { createClientRoutesWithHMRRevalidationOptOut, createClientRoutes, shouldHydrateRouteLoader } from './routes.js';
import { decodeViaTurboStream, getSingleFetchDataStrategy } from './single-fetch.js';
import invariant from './invariant.js';
import { getPatchRoutesOnNavigationFunction, useFogOFWarDiscovery } from './fog-of-war.js';

@@ -25,4 +28,4 @@ /* eslint-disable prefer-let/prefer-let */

let stateDecodingPromise;
let router;
let didServerRenderFallback = false;
let routerInitialized = false;

@@ -43,5 +46,6 @@ let hmrAbortController;

});
// The critical CSS can only be cleared, so the reducer always returns undefined
let criticalCssReducer = () => undefined;
// @ts-expect-error
if (import.meta && import.meta.hot) {
// @ts-expect-error
import.meta.hot.accept("remix:manifest", async ({

@@ -82,3 +86,3 @@ assetsManifest,

// Create new routes
let routes = createClientRoutesWithHMRRevalidationOptOut(needsRevalidation, assetsManifest.routes, window.__remixRouteModules, window.__remixContext.state, window.__remixContext.future);
let routes = createClientRoutesWithHMRRevalidationOptOut(needsRevalidation, assetsManifest.routes, window.__remixRouteModules, window.__remixContext.state, window.__remixContext.future, window.__remixContext.isSpaMode);

@@ -115,55 +119,67 @@ // This is temporary API and will be more granular before release

if (!router) {
// Hard reload if the path we tried to load is not the current path.
// This is usually the result of 2 rapid back/forward clicks from an
// external site into a Remix app, where we initially start the load for
// one URL and while the JS chunks are loading a second forward click moves
// us to a new URL. Avoid comparing search params because of CDNs which
// can be configured to ignore certain params and only pathname is relevant
// towards determining the route matches.
let initialPathname = window.__remixContext.url;
let hydratedPathname = window.location.pathname;
if (initialPathname !== hydratedPathname) {
let errorMsg = `Initial URL (${initialPathname}) does not match URL at time of hydration ` + `(${hydratedPathname}), reloading page...`;
console.error(errorMsg);
window.location.reload();
// Get out of here so the reload can happen - don't create the router
// since it'll then kick off unnecessary route.lazy() loads
return /*#__PURE__*/React.createElement(React.Fragment, null);
// When single fetch is enabled, we need to suspend until the initial state
// snapshot is decoded into window.__remixContext.state
if (window.__remixContext.future.unstable_singleFetch) {
// Note: `stateDecodingPromise` is not coupled to `router` - we'll reach this
// code potentially many times waiting for our state to arrive, but we'll
// then only get past here and create the `router` one time
if (!stateDecodingPromise) {
let stream = window.__remixContext.stream;
invariant(stream, "No stream found for single fetch decoding");
window.__remixContext.stream = undefined;
stateDecodingPromise = decodeViaTurboStream(stream, window).then(value => {
window.__remixContext.state = value.value;
stateDecodingPromise.value = true;
}).catch(e => {
stateDecodingPromise.error = e;
});
}
if (stateDecodingPromise.error) {
throw stateDecodingPromise.error;
}
if (!stateDecodingPromise.value) {
throw stateDecodingPromise;
}
}
let routes = createClientRoutes(window.__remixManifest.routes, window.__remixRouteModules, window.__remixContext.state, window.__remixContext.future);
// Create a shallow clone of `loaderData` we can mutate for partial hydration.
// When a route exports a `clientLoader` and a `HydrateFallback`, the SSR will
// render the fallback so we need the client to do the same for hydration.
// The server loader data has already been exposed to these route `clientLoader`'s
// in `createClientRoutes` above, so we need to clear out the version we pass to
// `createBrowserRouter` so it initializes and runs the client loaders.
let hydrationData = {
...window.__remixContext.state,
loaderData: {
...window.__remixContext.state.loaderData
}
};
let initialMatches = matchRoutes(routes, window.location);
if (initialMatches) {
for (let match of initialMatches) {
let routeId = match.route.id;
let route = window.__remixRouteModules[routeId];
let manifestRoute = window.__remixManifest.routes[routeId];
if (route && route.clientLoader && route.HydrateFallback) {
hydrationData.loaderData[routeId] = undefined;
didServerRenderFallback = true;
} else if (manifestRoute && !manifestRoute.hasLoader) {
// Since every Remix route gets a `loader` on the client side to load
// the route JS module, we need to add a `null` value to `loaderData`
// for any routes that don't have server loaders so our partial
// hydration logic doesn't kick off the route module loaders during
// hydration
hydrationData.loaderData[routeId] = null;
let routes = createClientRoutes(window.__remixManifest.routes, window.__remixRouteModules, window.__remixContext.state, window.__remixContext.future, window.__remixContext.isSpaMode);
let hydrationData = undefined;
if (!window.__remixContext.isSpaMode) {
// Create a shallow clone of `loaderData` we can mutate for partial hydration.
// When a route exports a `clientLoader` and a `HydrateFallback`, the SSR will
// render the fallback so we need the client to do the same for hydration.
// The server loader data has already been exposed to these route `clientLoader`'s
// in `createClientRoutes` above, so we need to clear out the version we pass to
// `createBrowserRouter` so it initializes and runs the client loaders.
hydrationData = {
...window.__remixContext.state,
loaderData: {
...window.__remixContext.state.loaderData
}
};
let initialMatches = matchRoutes(routes, window.location, window.__remixContext.basename);
if (initialMatches) {
for (let match of initialMatches) {
let routeId = match.route.id;
let route = window.__remixRouteModules[routeId];
let manifestRoute = window.__remixManifest.routes[routeId];
// Clear out the loaderData to avoid rendering the route component when the
// route opted into clientLoader hydration and either:
// * gave us a HydrateFallback
// * or doesn't have a server loader and we have no data to render
if (route && shouldHydrateRouteLoader(manifestRoute, route, window.__remixContext.isSpaMode) && (route.HydrateFallback || !manifestRoute.hasLoader)) {
hydrationData.loaderData[routeId] = undefined;
} else if (manifestRoute && !manifestRoute.hasLoader) {
// Since every Remix route gets a `loader` on the client side to load
// the route JS module, we need to add a `null` value to `loaderData`
// for any routes that don't have server loaders so our partial
// hydration logic doesn't kick off the route module loaders during
// hydration
hydrationData.loaderData[routeId] = null;
}
}
}
if (hydrationData && hydrationData.errors) {
hydrationData.errors = deserializeErrors(hydrationData.errors);
}
}
if (hydrationData && hydrationData.errors) {
hydrationData.errors = deserializeErrors(hydrationData.errors);
}

@@ -175,2 +191,3 @@ // We don't use createBrowserRouter here because we need fine-grained control

history: createBrowserHistory(),
basename: window.__remixContext.basename,
future: {

@@ -181,11 +198,16 @@ v7_normalizeFormMethod: true,

v7_prependBasename: true,
v7_relativeSplatPath: window.__remixContext.future.v3_relativeSplatPath
v7_relativeSplatPath: window.__remixContext.future.v3_relativeSplatPath,
// Single fetch enables this underlying behavior
v7_skipActionErrorRevalidation: window.__remixContext.future.unstable_singleFetch === true
},
hydrationData,
mapRouteProperties: UNSAFE_mapRouteProperties
mapRouteProperties: UNSAFE_mapRouteProperties,
unstable_dataStrategy: window.__remixContext.future.unstable_singleFetch ? getSingleFetchDataStrategy(window.__remixManifest, window.__remixRouteModules) : undefined,
unstable_patchRoutesOnNavigation: getPatchRoutesOnNavigationFunction(window.__remixManifest, window.__remixRouteModules, window.__remixContext.future, window.__remixContext.isSpaMode, window.__remixContext.basename)
});
// As long as we didn't SSR a `HydrateFallback`, we can initialize immediately since
// there's no initial client-side data loading to perform
if (!didServerRenderFallback) {
// We can call initialize() immediately if the router doesn't have any
// loaders to run on hydration
if (router.state.initialized) {
routerInitialized = true;
router.initialize();

@@ -207,18 +229,17 @@ }

// server HTML. This allows our HMR logic to clear the critical CSS state.
// eslint-disable-next-line react-hooks/rules-of-hooks
let [criticalCss, clearCriticalCss] = React.useReducer(criticalCssReducer, window.__remixContext.criticalCss);
window.__remixClearCriticalCss = clearCriticalCss;
let [criticalCss, setCriticalCss] = React.useState(process.env.NODE_ENV === "development" ? window.__remixContext.criticalCss : undefined);
if (process.env.NODE_ENV === "development") {
window.__remixClearCriticalCss = () => setCriticalCss(undefined);
}
// This is due to the short circuit return above when the pathname doesn't
// match and we force a hard reload. This is an exceptional scenario in which
// we can't hydrate anyway.
// eslint-disable-next-line react-hooks/rules-of-hooks
let [location, setLocation] = React.useState(router.state.location);
// eslint-disable-next-line react-hooks/rules-of-hooks
React.useLayoutEffect(() => {
// If we rendered a `HydrateFallback` on the server, delay initialization until
// after we've hydrated with the `HydrateFallback` in case the client loaders
// are synchronous
if (didServerRenderFallback && !routerInitialized) {
// If we had to run clientLoaders on hydration, we delay initialization until
// after we've hydrated to avoid hydration issues from synchronous client loaders
if (!routerInitialized) {
routerInitialized = true;

@@ -228,4 +249,2 @@ router.initialize();

}, []);
// eslint-disable-next-line react-hooks/rules-of-hooks
React.useLayoutEffect(() => {

@@ -238,2 +257,3 @@ return router.subscribe(newState => {

}, [location]);
useFogOFWarDiscovery(router, window.__remixManifest, window.__remixRouteModules, window.__remixContext.future, window.__remixContext.isSpaMode);

@@ -244,20 +264,26 @@ // We need to include a wrapper RemixErrorBoundary here in case the root error

// out of there
return /*#__PURE__*/React.createElement(RemixContext.Provider, {
value: {
manifest: window.__remixManifest,
routeModules: window.__remixRouteModules,
future: window.__remixContext.future,
criticalCss
}
}, /*#__PURE__*/React.createElement(RemixErrorBoundary, {
location: location
}, /*#__PURE__*/React.createElement(RouterProvider, {
router: router,
fallbackElement: null,
future: {
v7_startTransition: true
}
})));
return (
/*#__PURE__*/
// This fragment is important to ensure we match the <RemixServer> JSX
// structure so that useId values hydrate correctly
React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(RemixContext.Provider, {
value: {
manifest: window.__remixManifest,
routeModules: window.__remixRouteModules,
future: window.__remixContext.future,
criticalCss,
isSpaMode: window.__remixContext.isSpaMode
}
}, /*#__PURE__*/React.createElement(RemixErrorBoundary, {
location: location
}, /*#__PURE__*/React.createElement(RouterProvider, {
router: router,
fallbackElement: null,
future: {
v7_startTransition: true
}
}))), window.__remixContext.future.unstable_singleFetch ? /*#__PURE__*/React.createElement(React.Fragment, null) : null)
);
}
export { RemixBrowser };
/**
* @remix-run/react v0.0.0-nightly-910b900-20231207
* @remix-run/react v0.0.0-nightly-91184a743-20240823
*

@@ -13,6 +13,8 @@ * Copyright (c) Remix Software Inc.

import * as React from 'react';
import { useHref, NavLink as NavLink$1, Link as Link$1, matchRoutes, useLocation, Await as Await$1, useNavigation, useAsyncError, useMatches as useMatches$1, useLoaderData as useLoaderData$1, useRouteLoaderData as useRouteLoaderData$1, useActionData as useActionData$1, useFetcher as useFetcher$1, UNSAFE_DataRouterContext, UNSAFE_DataRouterStateContext } from 'react-router-dom';
import { useHref, NavLink as NavLink$1, Link as Link$1, Form as Form$1, matchRoutes, useLocation, Await as Await$1, useAsyncError, useMatches as useMatches$1, useLoaderData as useLoaderData$1, useRouteLoaderData as useRouteLoaderData$1, useActionData as useActionData$1, useFetcher as useFetcher$1, UNSAFE_DataRouterContext, UNSAFE_DataRouterStateContext } from 'react-router-dom';
import invariant from './invariant.js';
import { getKeyedLinksForMatches, isPageLinkDescriptor, getNewMatchesForLinks, getDataLinkHrefs, getModuleLinkHrefs, getKeyedPrefetchLinks } from './links.js';
import { escapeHtml, createHtml } from './markup.js';
import { addRevalidationParam, singleFetchUrl } from './single-fetch.js';
import { isFogOfWarEnabled, getPartialManifest } from './fog-of-war.js';

@@ -45,2 +47,9 @@ function useDataRouterContext() {

/**
* Defines the discovery behavior of the link:
*
* - "render": Eagerly discover when the link is rendered (default)
* - "none": No eager discovery - discover when the link is clicked
*/
/**
* Defines the prefetching behavior of the link:

@@ -53,2 +62,3 @@ *

*/
function usePrefetchBehavior(prefetch, theirElementProps) {

@@ -114,2 +124,5 @@ let [maybePrefetch, setMaybePrefetch] = React.useState(false);

const ABSOLUTE_URL_REGEX = /^(?:[a-z][a-z0-9+.-]*:|\/\/)/i;
function getDiscoverAttr(discover, isAbsolute, reloadDocument) {
return discover === "render" && !isAbsolute && !reloadDocument ? "true" : undefined;
}

@@ -124,2 +137,3 @@ /**

prefetch = "none",
discover = "render",
...props

@@ -132,3 +146,4 @@ }, forwardedRef) => {

ref: mergeRefs(forwardedRef, ref),
to: to
to: to,
"data-discover": getDiscoverAttr(discover, isAbsolute, props.reloadDocument)
})), shouldPrefetch && !isAbsolute ? /*#__PURE__*/React.createElement(PrefetchPageLinks, {

@@ -149,2 +164,3 @@ page: href

prefetch = "none",
discover = "render",
...props

@@ -157,3 +173,4 @@ }, forwardedRef) => {

ref: mergeRefs(forwardedRef, ref),
to: to
to: to,
"data-discover": getDiscoverAttr(discover, isAbsolute, props.reloadDocument)
})), shouldPrefetch && !isAbsolute ? /*#__PURE__*/React.createElement(PrefetchPageLinks, {

@@ -164,2 +181,19 @@ page: href

Link.displayName = "Link";
/**
* This component renders a form tag and is the primary way the user will
* submit information via your website.
*
* @see https://remix.run/components/form
*/
let Form = /*#__PURE__*/React.forwardRef(({
discover = "render",
...props
}, forwardedRef) => {
let isAbsolute = typeof props.action === "string" && ABSOLUTE_URL_REGEX.test(props.action);
return /*#__PURE__*/React.createElement(Form$1, _extends({}, props, {
ref: forwardedRef,
"data-discover": getDiscoverAttr(discover, isAbsolute, props.reloadDocument)
}));
});
Form.displayName = "Form";
function composeEventHandlers(theirHandler, ourHandler) {

@@ -174,2 +208,18 @@ return event => {

// Return the matches actively being displayed:
// - In SPA Mode we only SSR/hydrate the root match, and include all matches
// after hydration. This lets the router handle initial match loads via lazy().
// - When an error boundary is rendered, we slice off matches up to the
// boundary for <Links>/<Meta>
function getActiveMatches(matches, errors, isSpaMode) {
if (isSpaMode && !isHydrated) {
return [matches[0]];
}
if (errors) {
let errorIdx = matches.findIndex(m => errors[m.route.id] !== undefined);
return matches.slice(0, errorIdx + 1);
}
return matches;
}
/**

@@ -182,2 +232,3 @@ * Renders the `<link>` tags for the current routes.

let {
isSpaMode,
manifest,

@@ -191,3 +242,3 @@ routeModules,

} = useDataRouterStateContext();
let matches = errors ? routerMatches.slice(0, routerMatches.findIndex(m => errors[m.route.id]) + 1) : routerMatches;
let matches = getActiveMatches(routerMatches, errors, isSpaMode);
let keyedLinks = React.useMemo(() => getKeyedLinksForMatches(matches, routeModules, manifest), [matches, routeModules, manifest]);

@@ -224,3 +275,3 @@ return /*#__PURE__*/React.createElement(React.Fragment, null, criticalCss ? /*#__PURE__*/React.createElement("style", {

} = useDataRouterContext();
let matches = React.useMemo(() => matchRoutes(router.routes, page), [router.routes, page]);
let matches = React.useMemo(() => matchRoutes(router.routes, page, router.basename), [router.routes, page, router.basename]);
if (!matches) {

@@ -261,3 +312,5 @@ console.warn(`Tried to prefetch ${page} but no routes matched.`);

let {
manifest
future,
manifest,
routeModules
} = useRemixContext();

@@ -275,9 +328,25 @@ let {

let keyedPrefetchLinks = useKeyedPrefetchLinks(newMatchesForAssets);
return /*#__PURE__*/React.createElement(React.Fragment, null, dataHrefs.map(href => /*#__PURE__*/React.createElement("link", _extends({
let linksToRender = null;
if (!future.unstable_singleFetch) {
// Non-single-fetch prefetching
linksToRender = dataHrefs.map(href => /*#__PURE__*/React.createElement("link", _extends({
key: href,
rel: "prefetch",
as: "fetch",
href: href
}, linkProps)));
} else if (newMatchesForData.length > 0) {
// Single-fetch with routes that require data
let url = addRevalidationParam(manifest, routeModules, nextMatches.map(m => m.route), newMatchesForData.map(m => m.route), singleFetchUrl(page));
if (url.searchParams.get("_routes") !== "") {
linksToRender = /*#__PURE__*/React.createElement("link", _extends({
key: url.pathname + url.search,
rel: "prefetch",
as: "fetch",
href: url.pathname + url.search
}, linkProps));
}
} else ;
return /*#__PURE__*/React.createElement(React.Fragment, null, linksToRender, moduleHrefs.map(href => /*#__PURE__*/React.createElement("link", _extends({
key: href,
rel: "prefetch",
as: "fetch",
href: href
}, linkProps))), moduleHrefs.map(href => /*#__PURE__*/React.createElement("link", _extends({
key: href,
rel: "modulepreload",

@@ -304,2 +373,3 @@ href: href

let {
isSpaMode,
routeModules

@@ -313,8 +383,6 @@ } = useRemixContext();

let location = useLocation();
let _matches = routerMatches;
let _matches = getActiveMatches(routerMatches, errors, isSpaMode);
let error = null;
if (errors) {
let errorIdx = routerMatches.findIndex(m => errors[m.route.id]);
_matches = routerMatches.slice(0, errorIdx + 1);
error = errors[routerMatches[errorIdx].route.id];
error = errors[_matches[_matches.length - 1].route.id];
}

@@ -443,3 +511,6 @@ let meta = [];

abortDelay,
serializeError
serializeError,
isSpaMode,
future,
renderMeta
} = useRemixContext();

@@ -452,5 +523,12 @@ let {

let {
matches
matches: routerMatches
} = useDataRouterStateContext();
let navigation = useNavigation();
let enableFogOfWar = isFogOfWarEnabled(future, isSpaMode);
// Let <RemixServer> know that we hydrated and we should render the single
// fetch streaming scripts
if (renderMeta) {
renderMeta.didRenderScripts = true;
}
let matches = getActiveMatches(routerMatches, null, isSpaMode);
React.useEffect(() => {

@@ -498,4 +576,10 @@ isHydrated = true;

var _manifest$hmr;
let contextScript = staticContext ? `window.__remixContext = ${serverHandoffString};` : " ";
let activeDeferreds = staticContext === null || staticContext === void 0 ? void 0 : staticContext.activeDeferreds;
let streamScript = future.unstable_singleFetch ?
// prettier-ignore
"window.__remixContext.stream = new ReadableStream({" + "start(controller){" + "window.__remixContext.streamController = controller;" + "}" + "}).pipeThrough(new TextEncoderStream());" : "";
let contextScript = staticContext ? `window.__remixContext = ${serverHandoffString};${streamScript}` : " ";
// When single fetch is enabled, deferred is handled by turbo-stream
let activeDeferreds = future.unstable_singleFetch ? undefined : staticContext === null || staticContext === void 0 ? void 0 : staticContext.activeDeferreds;
// This sets up the __remixContext with utility functions used by the

@@ -538,4 +622,7 @@ // deferred scripts.

}).join("\n") + (deferredScripts.length > 0 ? `__remixContext.a=${deferredScripts.length};` : "");
let routeModulesScript = !isStatic ? " " : `${(_manifest$hmr = manifest.hmr) !== null && _manifest$hmr !== void 0 && _manifest$hmr.runtime ? `import ${JSON.stringify(manifest.hmr.runtime)};` : ""}import ${JSON.stringify(manifest.url)};
let routeModulesScript = !isStatic ? " " : `${(_manifest$hmr = manifest.hmr) !== null && _manifest$hmr !== void 0 && _manifest$hmr.runtime ? `import ${JSON.stringify(manifest.hmr.runtime)};` : ""}${enableFogOfWar ? "" : `import ${JSON.stringify(manifest.url)}`};
${matches.map((match, index) => `import * as route${index} from ${JSON.stringify(manifest.routes[match.route.id].module)};`).join("\n")}
${enableFogOfWar ?
// Inline a minimal manifest with the SSR matches
`window.__remixManifest = ${JSON.stringify(getPartialManifest(manifest, router), null, 2)};` : ""}
window.__remixRouteModules = {${matches.map((match, index) => `${JSON.stringify(match.route.id)}:route${index}`).join(",")}};

@@ -569,14 +656,3 @@

}
// avoid waterfall when importing the next route module
let nextMatches = React.useMemo(() => {
if (navigation.location) {
// FIXME: can probably use transitionManager `nextMatches`
let matches = matchRoutes(router.routes, navigation.location);
invariant(matches, `No routes match path "${navigation.location.pathname}"`);
return matches;
}
return [];
}, [navigation.location, router.routes]);
let routePreloads = matches.concat(nextMatches).map(match => {
let routePreloads = matches.map(match => {
let route = manifest.routes[match.route.id];

@@ -586,7 +662,7 @@ return (route.imports || []).concat([route.module]);

let preloads = isHydrated ? [] : manifest.entry.imports.concat(routePreloads);
return isHydrated ? null : /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("link", {
return isHydrated ? null : /*#__PURE__*/React.createElement(React.Fragment, null, !enableFogOfWar ? /*#__PURE__*/React.createElement("link", {
rel: "modulepreload",
href: manifest.url,
crossOrigin: props.crossOrigin
}), /*#__PURE__*/React.createElement("link", {
}) : null, /*#__PURE__*/React.createElement("link", {
rel: "modulepreload",

@@ -725,3 +801,3 @@ href: manifest.entry.module,

process.env.NODE_ENV !== "development" ? () => null : function LiveReload({
origin = process.env.REMIX_DEV_ORIGIN,
origin,
port,

@@ -731,2 +807,9 @@ timeoutMs = 1000,

}) {
// @ts-expect-error
let isViteClient = import.meta && import.meta.env !== undefined;
if (isViteClient) {
console.warn(["`<LiveReload />` is obsolete when using Vite and can conflict with Vite's built-in HMR runtime.", "", "Remove `<LiveReload />` from your code and instead only use `<Scripts />`.", "Then refresh the page to remove lingering scripts from `<LiveReload />`."].join("\n"));
return null;
}
origin ??= process.env.REMIX_DEV_ORIGIN;
let js = String.raw;

@@ -840,2 +923,2 @@ return /*#__PURE__*/React.createElement("script", {

export { Await, Link, Links, LiveReload, Meta, NavLink, PrefetchPageLinks, RemixContext, Scripts, composeEventHandlers, useActionData, useFetcher, useLoaderData, useMatches, useRouteLoaderData };
export { Await, Form, Link, Links, LiveReload, Meta, NavLink, PrefetchPageLinks, RemixContext, Scripts, composeEventHandlers, useActionData, useFetcher, useLoaderData, useMatches, useRemixContext, useRouteLoaderData };
/**
* @remix-run/react v0.0.0-nightly-910b900-20231207
* @remix-run/react v0.0.0-nightly-91184a743-20240823
*

@@ -27,3 +27,3 @@ * Copyright (c) Remix Software Inc.

// server, and instead receive a 4xx/5xx from somewhere in between (like
// Cloudflare), then we get a false negative n the isErrorResponse check and
// Cloudflare), then we get a false negative in the isErrorResponse check and
// we incorrectly assume that the user returns the 4xx/5xx response and

@@ -53,27 +53,2 @@ // consider it successful. To alleviate this, we add X-Remix-Response to any

url.searchParams.set("_data", routeId);
let init = {
signal: request.signal
};
if (request.method !== "GET") {
init.method = request.method;
let contentType = request.headers.get("Content-Type");
// Check between word boundaries instead of startsWith() due to the last
// paragraph of https://httpwg.org/specs/rfc9110.html#field.content-type
if (contentType && /\bapplication\/json\b/.test(contentType)) {
init.headers = {
"Content-Type": contentType
};
init.body = JSON.stringify(await request.json());
} else if (contentType && /\btext\/plain\b/.test(contentType)) {
init.headers = {
"Content-Type": contentType
};
init.body = await request.text();
} else if (contentType && /\bapplication\/x-www-form-urlencoded\b/.test(contentType)) {
init.body = new URLSearchParams(await request.text());
} else {
init.body = await request.formData();
}
}
if (retry > 0) {

@@ -84,2 +59,3 @@ // Retry up to 3 times waiting 50, 250, 1250 ms

}
let init = await createRequestInit(request);
let revalidation = window.__remixRevalidation;

@@ -106,2 +82,30 @@ let response = await fetch(url.href, init).catch(error => {

}
async function createRequestInit(request) {
let init = {
signal: request.signal
};
if (request.method !== "GET") {
init.method = request.method;
let contentType = request.headers.get("Content-Type");
// Check between word boundaries instead of startsWith() due to the last
// paragraph of https://httpwg.org/specs/rfc9110.html#field.content-type
if (contentType && /\bapplication\/json\b/.test(contentType)) {
init.headers = {
"Content-Type": contentType
};
init.body = JSON.stringify(await request.json());
} else if (contentType && /\btext\/plain\b/.test(contentType)) {
init.headers = {
"Content-Type": contentType
};
init.body = await request.text();
} else if (contentType && /\bapplication\/x-www-form-urlencoded\b/.test(contentType)) {
init.body = new URLSearchParams(await request.text());
} else {
init.body = await request.formData();
}
}
return init;
}
const DEFERRED_VALUE_PLACEHOLDER_PREFIX = "__deferred_promise:";

@@ -267,2 +271,2 @@ async function parseDeferredReadableStream(stream) {

export { fetchData, isCatchResponse, isDeferredData, isDeferredResponse, isErrorResponse, isNetworkErrorResponse, isRedirectResponse, isResponse, parseDeferredReadableStream };
export { createRequestInit, fetchData, isCatchResponse, isDeferredData, isDeferredResponse, isErrorResponse, isNetworkErrorResponse, isRedirectResponse, isResponse, parseDeferredReadableStream };
/**
* @remix-run/react v0.0.0-nightly-910b900-20231207
* @remix-run/react v0.0.0-nightly-91184a743-20240823
*

@@ -13,2 +13,3 @@ * Copyright (c) Remix Software Inc.

import { isRouteErrorResponse } from 'react-router-dom';
import { useRemixContext, Scripts } from './components.js';

@@ -57,3 +58,4 @@ class RemixErrorBoundary extends React.Component {

return /*#__PURE__*/React.createElement(RemixRootDefaultErrorBoundary, {
error: this.state.error
error: this.state.error,
isOutsideRemixApp: true
});

@@ -70,5 +72,15 @@ } else {

function RemixRootDefaultErrorBoundary({
error
error,
isOutsideRemixApp
}) {
console.error(error);
let heyDeveloper = /*#__PURE__*/React.createElement("script", {
dangerouslySetInnerHTML: {
__html: `
console.log(
"💿 Hey developer 👋. You can provide a way better UX than this when your app throws errors. Check out https://remix.run/guides/errors for more information."
);
`
}
});
if (isRouteErrorResponse(error)) {

@@ -79,6 +91,5 @@ return /*#__PURE__*/React.createElement(BoundaryShell, {

style: {
fontFamily: "system-ui, sans-serif",
padding: "2rem"
fontSize: "24px"
}
}, error.status, " ", error.statusText));
}, error.status, " ", error.statusText), heyDeveloper);
}

@@ -93,8 +104,4 @@ let errorInstance;

return /*#__PURE__*/React.createElement(BoundaryShell, {
title: "Application Error!"
}, /*#__PURE__*/React.createElement("main", {
style: {
fontFamily: "system-ui, sans-serif",
padding: "2rem"
}
title: "Application Error!",
isOutsideRemixApp: isOutsideRemixApp
}, /*#__PURE__*/React.createElement("h1", {

@@ -111,8 +118,34 @@ style: {

}
}, errorInstance.stack)));
}, errorInstance.stack), heyDeveloper);
}
function BoundaryShell({
title,
renderScripts,
isOutsideRemixApp,
children
}) {
var _routeModules$root;
let {
routeModules
} = useRemixContext();
// Generally speaking, when the root route has a Layout we want to use that
// as the app shell instead of the default `BoundaryShell` wrapper markup below.
// This is true for `loader`/`action` errors, most render errors, and
// `HydrateFallback` scenarios.
// However, render errors thrown from the `Layout` present a bit of an issue
// because if the `Layout` itself throws during the `ErrorBoundary` pass and
// we bubble outside the `RouterProvider` to the wrapping `RemixErrorBoundary`,
// by returning only `children` here we'll be trying to append a `<div>` to
// the `document` and the DOM will throw, putting React into an error/hydration
// loop.
// Instead, if we're ever rendering from the outermost `RemixErrorBoundary`
// during hydration that wraps `RouterProvider`, then we can't trust the
// `Layout` and should fallback to the default app shell so we're always
// returning an `<html>` document.
if ((_routeModules$root = routeModules.root) !== null && _routeModules$root !== void 0 && _routeModules$root.Layout && !isOutsideRemixApp) {
return children;
}
return /*#__PURE__*/React.createElement("html", {

@@ -125,13 +158,10 @@ lang: "en"

content: "width=device-width,initial-scale=1,viewport-fit=cover"
}), /*#__PURE__*/React.createElement("title", null, title)), /*#__PURE__*/React.createElement("body", null, children, /*#__PURE__*/React.createElement("script", {
dangerouslySetInnerHTML: {
__html: `
console.log(
"💿 Hey developer 👋. You can provide a way better UX than this when your app throws errors. Check out https://remix.run/guides/errors for more information."
);
`
}), /*#__PURE__*/React.createElement("title", null, title)), /*#__PURE__*/React.createElement("body", null, /*#__PURE__*/React.createElement("main", {
style: {
fontFamily: "system-ui, sans-serif",
padding: "2rem"
}
})));
}, children, renderScripts ? /*#__PURE__*/React.createElement(Scripts, null) : null)));
}
export { RemixErrorBoundary, RemixRootDefaultErrorBoundary };
export { BoundaryShell, RemixErrorBoundary, RemixRootDefaultErrorBoundary };
/**
* @remix-run/react v0.0.0-nightly-910b900-20231207
* @remix-run/react v0.0.0-nightly-91184a743-20240823
*

@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc.

/**
* @remix-run/react v0.0.0-nightly-910b900-20231207
* @remix-run/react v0.0.0-nightly-91184a743-20240823
*

@@ -12,3 +12,3 @@ * Copyright (c) Remix Software Inc.

import * as React from 'react';
import { Scripts } from './components.js';
import { BoundaryShell } from './errorBoundaries.js';

@@ -20,10 +20,6 @@ // If the user sets `clientLoader.hydrate=true` somewhere but does not

function RemixRootDefaultHydrateFallback() {
return /*#__PURE__*/React.createElement("html", {
lang: "en"
}, /*#__PURE__*/React.createElement("head", null, /*#__PURE__*/React.createElement("meta", {
charSet: "utf-8"
}), /*#__PURE__*/React.createElement("meta", {
name: "viewport",
content: "width=device-width,initial-scale=1,viewport-fit=cover"
})), /*#__PURE__*/React.createElement("body", null, /*#__PURE__*/React.createElement(Scripts, null), /*#__PURE__*/React.createElement("script", {
return /*#__PURE__*/React.createElement(BoundaryShell, {
title: "Loading...",
renderScripts: true
}, /*#__PURE__*/React.createElement("script", {
dangerouslySetInnerHTML: {

@@ -33,10 +29,11 @@ __html: `

"💿 Hey developer 👋. You can provide a way better UX than this " +
"when your app is running \`clientLoader\` functions on hydration. " +
"Check out https://remix.run/route/hydrate-fallback for more information."
"when your app is loading JS modules and/or running \`clientLoader\` " +
"functions. Check out https://remix.run/route/hydrate-fallback " +
"for more information."
);
`
}
}), " "));
}));
}
export { RemixRootDefaultHydrateFallback };
/**
* @remix-run/react v0.0.0-nightly-910b900-20231207
* @remix-run/react v0.0.0-nightly-91184a743-20240823
*

@@ -11,6 +11,8 @@ * Copyright (c) Remix Software Inc.

*/
export { Navigate, NavigationType, Outlet, Route, Routes, createPath, createRoutesFromChildren, createRoutesFromElements, createSearchParams, generatePath, isRouteErrorResponse, matchPath, matchRoutes, parsePath, renderMatches, resolvePath, unstable_usePrompt, unstable_useViewTransitionState, useAsyncError, useAsyncValue, useBeforeUnload, useBlocker, useFetchers, useFormAction, useHref, useInRouterContext, useLinkClickHandler, useLocation, useMatch, useNavigate, useNavigation, useNavigationType, useOutlet, useOutletContext, useParams, useResolvedPath, useRevalidator, useRouteError, useRoutes, useSearchParams, useSubmit } from 'react-router-dom';
export { defer, json, redirect, redirectDocument, replace, unstable_data } from '@remix-run/server-runtime';
export { RemixBrowser } from './browser.js';
export { Form, Outlet, createPath, generatePath, isRouteErrorResponse, matchPath, matchRoutes, parsePath, resolvePath, unstable_usePrompt, unstable_useViewTransitionState, useAsyncError, useAsyncValue, useBeforeUnload, useBlocker, useFetchers, useFormAction, useHref, useLocation, useMatch, useNavigate, useNavigation, useNavigationType, useOutlet, useOutletContext, useParams, useResolvedPath, useRevalidator, useRouteError, useSearchParams, useSubmit } from 'react-router-dom';
export { Await, Link, Links, LiveReload, Meta, NavLink, PrefetchPageLinks, Scripts, RemixContext as UNSAFE_RemixContext, useActionData, useFetcher, useLoaderData, useMatches, useRouteLoaderData } from './components.js';
export { Await, Form, Link, Links, LiveReload, Meta, NavLink, PrefetchPageLinks, Scripts, RemixContext as UNSAFE_RemixContext, useActionData, useFetcher, useLoaderData, useMatches, useRouteLoaderData } from './components.js';
export { ScrollRestoration } from './scroll-restoration.js';
export { RemixServer } from './server.js';
export { defineClientAction as unstable_defineClientAction, defineClientLoader as unstable_defineClientLoader } from './single-fetch.js';
/**
* @remix-run/react v0.0.0-nightly-910b900-20231207
* @remix-run/react v0.0.0-nightly-91184a743-20240823
*

@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc.

/**
* @remix-run/react v0.0.0-nightly-910b900-20231207
* @remix-run/react v0.0.0-nightly-91184a743-20240823
*

@@ -21,2 +21,3 @@ * Copyright (c) Remix Software Inc.

////////////////////////////////////////////////////////////////////////////////
/**

@@ -34,3 +35,3 @@ * Gets all the links for a set of matches. The modules are assumed to have been

href
})) : [], ((_module$links = module.links) === null || _module$links === void 0 ? void 0 : _module$links.call(module)) || []];
})) : [], (module === null || module === void 0 ? void 0 : (_module$links = module.links) === null || _module$links === void 0 ? void 0 : _module$links.call(module)) || []];
}).flat(2);

@@ -173,3 +174,3 @@ let preloads = getCurrentPageModulePreloadHrefs(matches, manifest);

let path = parsePathPatch(page);
return dedupeHrefs(matches.filter(match => manifest.routes[match.route.id].hasLoader).map(match => {
return dedupeHrefs(matches.filter(match => manifest.routes[match.route.id].hasLoader && !manifest.routes[match.route.id].hasClientLoader).map(match => {
let {

@@ -176,0 +177,0 @@ pathname,

/**
* @remix-run/react v0.0.0-nightly-910b900-20231207
* @remix-run/react v0.0.0-nightly-91184a743-20240823
*

@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc.

/**
* @remix-run/react v0.0.0-nightly-910b900-20231207
* @remix-run/react v0.0.0-nightly-91184a743-20240823
*

@@ -37,2 +37,8 @@ * Copyright (c) Remix Software Inc.

/**
* Optional, root-only `<Route Layout>` component to wrap the root content in.
* Useful for defining the <html>/<head>/<body> document shell shared by the
* Component, HydrateFallback, and ErrorBoundary
*/
/**
* A function that defines `<link>` tags to be inserted into the `<head>` of

@@ -63,6 +69,23 @@ * the document on route transitions.

} catch (error) {
// User got caught in the middle of a deploy and the CDN no longer has the
// asset we're trying to import! Reload from the server and the user
// (should) get the new manifest--unless the developer purged the static
// assets, the manifest path, but not the documents 😬
// If we can't load the route it's likely one of 2 things:
// - User got caught in the middle of a deploy and the CDN no longer has the
// asset we're trying to import! Reload from the server and the user
// (should) get the new manifest--unless the developer purged the static
// assets, the manifest path, but not the documents 😬
// - Or, the asset trying to be imported has an error (usually in vite dev
// mode), so the best we can do here is log the error for visibility
// (via `Preserve log`) and reload
// Log the error so it can be accessed via the `Preserve Log` setting
console.error(`Error loading route module \`${route.module}\`, reloading page...`);
console.error(error);
if (window.__remixContext.isSpaMode &&
// @ts-expect-error
typeof import.meta.hot !== "undefined") {
// In SPA Mode (which implies vite) we don't want to perform a hard reload
// on dev-time errors since it's a vite compilation error and a reload is
// just going to fail with the same issue. Let the UI bubble to the error
// boundary and let them see the error in the overlay or the dev server log
throw error;
}
window.location.reload();

@@ -69,0 +92,0 @@ return new Promise(() => {

/**
* @remix-run/react v0.0.0-nightly-910b900-20231207
* @remix-run/react v0.0.0-nightly-91184a743-20240823
*

@@ -15,6 +15,7 @@ * Copyright (c) Remix Software Inc.

import { loadRouteModule } from './routeModules.js';
import { isDeferredData, isResponse, fetchData, isRedirectResponse, isCatchResponse, isDeferredResponse, parseDeferredReadableStream } from './data.js';
import { fetchData, isRedirectResponse, isCatchResponse, isDeferredResponse, parseDeferredReadableStream, isDeferredData, isResponse } from './data.js';
import { prefetchStyleLinks } from './links.js';
import { RemixRootDefaultErrorBoundary } from './errorBoundaries.js';
import { RemixRootDefaultHydrateFallback } from './fallback.js';
import invariant from './invariant.js';

@@ -38,16 +39,52 @@ // NOTE: make sure to change the Route in server-runtime if you change this

}
function createServerRoutes(manifest, routeModules, future, parentId = "", routesByParentId = groupRoutesByParentId(manifest)) {
function getRouteComponents(route, routeModule, isSpaMode) {
let Component = getRouteModuleComponent(routeModule);
// HydrateFallback can only exist on the root route in SPA Mode
let HydrateFallback = routeModule.HydrateFallback && (!isSpaMode || route.id === "root") ? routeModule.HydrateFallback : route.id === "root" ? RemixRootDefaultHydrateFallback : undefined;
let ErrorBoundary = routeModule.ErrorBoundary ? routeModule.ErrorBoundary : route.id === "root" ? () => /*#__PURE__*/React.createElement(RemixRootDefaultErrorBoundary, {
error: useRouteError()
}) : undefined;
if (route.id === "root" && routeModule.Layout) {
return {
...(Component ? {
element: /*#__PURE__*/React.createElement(routeModule.Layout, null, /*#__PURE__*/React.createElement(Component, null))
} : {
Component
}),
...(ErrorBoundary ? {
errorElement: /*#__PURE__*/React.createElement(routeModule.Layout, null, /*#__PURE__*/React.createElement(ErrorBoundary, null))
} : {
ErrorBoundary
}),
...(HydrateFallback ? {
hydrateFallbackElement: /*#__PURE__*/React.createElement(routeModule.Layout, null, /*#__PURE__*/React.createElement(HydrateFallback, null))
} : {
HydrateFallback
})
};
}
return {
Component,
ErrorBoundary,
HydrateFallback
};
}
function createServerRoutes(manifest, routeModules, future, isSpaMode, parentId = "", routesByParentId = groupRoutesByParentId(manifest), spaModeLazyPromise = Promise.resolve({
Component: () => null
})) {
return (routesByParentId[parentId] || []).map(route => {
let routeModule = routeModules[route.id];
invariant(routeModule, "No `routeModule` available to create server routes");
let dataRoute = {
...getRouteComponents(route, routeModule, isSpaMode),
caseSensitive: route.caseSensitive,
Component: getRouteModuleComponent(routeModule),
HydrateFallback: routeModule.HydrateFallback ? routeModule.HydrateFallback : route.id === "root" ? RemixRootDefaultHydrateFallback : undefined,
ErrorBoundary: routeModule.ErrorBoundary ? routeModule.ErrorBoundary : route.id === "root" ? () => /*#__PURE__*/React.createElement(RemixRootDefaultErrorBoundary, {
error: useRouteError()
}) : undefined,
id: route.id,
index: route.index,
path: route.path,
handle: routeModules[route.id].handle,
handle: routeModule.handle,
// For SPA Mode, all routes are lazy except root. However we tell the
// router root is also lazy here too since we don't need a full
// implementation - we just need a `lazy` prop to tell the RR rendering
// where to stop which is always at the root route in SPA mode
lazy: isSpaMode ? () => spaModeLazyPromise : undefined,
// For partial hydration rendering, we need to indicate when the route

@@ -61,4 +98,3 @@ // has a loader/clientLoader, but it won't ever be called during the static

};
let children = createServerRoutes(manifest, routeModules, future, route.id, routesByParentId);
let children = createServerRoutes(manifest, routeModules, future, isSpaMode, route.id, routesByParentId, spaModeLazyPromise);
if (children.length > 0) dataRoute.children = children;

@@ -68,24 +104,57 @@ return dataRoute;

}
function createClientRoutesWithHMRRevalidationOptOut(needsRevalidation, manifest, routeModulesCache, initialState, future) {
return createClientRoutes(manifest, routeModulesCache, initialState, future, "", groupRoutesByParentId(manifest), needsRevalidation);
function createClientRoutesWithHMRRevalidationOptOut(needsRevalidation, manifest, routeModulesCache, initialState, future, isSpaMode) {
return createClientRoutes(manifest, routeModulesCache, initialState, future, isSpaMode, "", groupRoutesByParentId(manifest), needsRevalidation);
}
function createClientRoutes(manifest, routeModulesCache, initialState, future, parentId = "", routesByParentId = groupRoutesByParentId(manifest), needsRevalidation) {
function preventInvalidServerHandlerCall(type, route, isSpaMode) {
if (isSpaMode) {
let fn = type === "action" ? "serverAction()" : "serverLoader()";
let msg = `You cannot call ${fn} in SPA Mode (routeId: "${route.id}")`;
console.error(msg);
throw new UNSAFE_ErrorResponseImpl(400, "Bad Request", new Error(msg), true);
}
let fn = type === "action" ? "serverAction()" : "serverLoader()";
let msg = `You are trying to call ${fn} on a route that does not have a server ` + `${type} (routeId: "${route.id}")`;
if (type === "loader" && !route.hasLoader || type === "action" && !route.hasAction) {
console.error(msg);
throw new UNSAFE_ErrorResponseImpl(400, "Bad Request", new Error(msg), true);
}
}
function noActionDefinedError(type, routeId) {
let article = type === "clientAction" ? "a" : "an";
let msg = `Route "${routeId}" does not have ${article} ${type}, but you are trying to ` + `submit to it. To fix this, please add ${article} \`${type}\` function to the route`;
console.error(msg);
throw new UNSAFE_ErrorResponseImpl(405, "Method Not Allowed", new Error(msg), true);
}
function createClientRoutes(manifest, routeModulesCache, initialState, future, isSpaMode, parentId = "", routesByParentId = groupRoutesByParentId(manifest), needsRevalidation) {
return (routesByParentId[parentId] || []).map(route => {
let routeModule = routeModulesCache[route.id];
async function fetchServerLoader(request) {
if (!route.hasLoader) return null;
return fetchServerHandler(request, route);
// Fetch data from the server either via single fetch or the standard `?_data`
// request. Unwrap it when called via `serverLoader`/`serverAction` in a
// client handler, otherwise return the raw response for the router to unwrap
async function fetchServerHandlerAndMaybeUnwrap(request, unwrap, singleFetch) {
if (typeof singleFetch === "function") {
let result = await singleFetch();
return result;
}
let result = await fetchServerHandler(request, route);
return unwrap ? unwrapServerResponse(result) : result;
}
async function fetchServerAction(request) {
function fetchServerLoader(request, unwrap, singleFetch) {
if (!route.hasLoader) return Promise.resolve(null);
return fetchServerHandlerAndMaybeUnwrap(request, unwrap, singleFetch);
}
function fetchServerAction(request, unwrap, singleFetch) {
if (!route.hasAction) {
let msg = `Route "${route.id}" does not have an action, but you are trying ` + `to submit to it. To fix this, please add an \`action\` function to the route`;
console.error(msg);
throw new UNSAFE_ErrorResponseImpl(405, "Method Not Allowed", new Error(msg), true);
throw noActionDefinedError("action", route.id);
}
return fetchServerHandler(request, route);
return fetchServerHandlerAndMaybeUnwrap(request, unwrap, singleFetch);
}
async function prefetchStylesAndCallHandler(handler) {
// Only prefetch links if we've been loaded into the cache, route.lazy
// will handle initial loads
let linkPrefetchPromise = routeModulesCache[route.id] ? prefetchStyleLinks(route, routeModulesCache[route.id]) : Promise.resolve();
// Only prefetch links if we exist in the routeModulesCache (critical modules
// and navigating back to pages previously loaded via route.lazy). Initial
// execution of route.lazy (when the module is not in the cache) will handle
// prefetching style links via loadRouteModuleWithBlockingLinks.
let cachedModule = routeModulesCache[route.id];
let linkPrefetchPromise = cachedModule ? prefetchStyleLinks(route, cachedModule) : Promise.resolve();
try {

@@ -103,59 +172,65 @@ return handler();

if (routeModule) {
var _initialState$loaderD, _initialState$errors, _routeModule$clientLo;
// Use critical path modules directly
Object.assign(dataRoute, {
...dataRoute,
Component: getRouteModuleComponent(routeModule),
HydrateFallback: routeModule.HydrateFallback ? routeModule.HydrateFallback : route.id === "root" ? RemixRootDefaultHydrateFallback : undefined,
ErrorBoundary: routeModule.ErrorBoundary ? routeModule.ErrorBoundary : route.id === "root" ? () => /*#__PURE__*/React.createElement(RemixRootDefaultErrorBoundary, {
error: useRouteError()
}) : undefined,
...getRouteComponents(route, routeModule, isSpaMode),
handle: routeModule.handle,
shouldRevalidate: needsRevalidation ? wrapShouldRevalidateForHdr(route.id, routeModule.shouldRevalidate, needsRevalidation) : routeModule.shouldRevalidate
});
let initialData = initialState && initialState.loaderData && initialState.loaderData[route.id];
let isHydrationRequest = needsRevalidation == null && routeModule.clientLoader != null && routeModule.clientLoader.hydrate === true;
dataRoute.loader = ({
let initialData = initialState === null || initialState === void 0 ? void 0 : (_initialState$loaderD = initialState.loaderData) === null || _initialState$loaderD === void 0 ? void 0 : _initialState$loaderD[route.id];
let initialError = initialState === null || initialState === void 0 ? void 0 : (_initialState$errors = initialState.errors) === null || _initialState$errors === void 0 ? void 0 : _initialState$errors[route.id];
let isHydrationRequest = needsRevalidation == null && (((_routeModule$clientLo = routeModule.clientLoader) === null || _routeModule$clientLo === void 0 ? void 0 : _routeModule$clientLo.hydrate) === true || !route.hasLoader);
dataRoute.loader = async ({
request,
params
}) => {
return prefetchStylesAndCallHandler(async () => {
if (!routeModule.clientLoader) {
// Call the server when no client loader exists
return fetchServerLoader(request);
}
return routeModule.clientLoader({
request,
params,
async serverLoader() {
if (isHydrationRequest) {
isHydrationRequest = false;
}, singleFetch) => {
try {
let result = await prefetchStylesAndCallHandler(async () => {
invariant(routeModule, "No `routeModule` available for critical-route loader");
if (!routeModule.clientLoader) {
if (isSpaMode) return null;
// Call the server when no client loader exists
return fetchServerLoader(request, false, singleFetch);
}
return routeModule.clientLoader({
request,
params,
async serverLoader() {
preventInvalidServerHandlerCall("loader", route, isSpaMode);
// Throw an error if a clientLoader tries to call a serverLoader that doesn't exist
if (initialData === undefined) {
throw new Error(`You are trying to call serverLoader() on a route that does " +
"not have a server loader (routeId: "${route.id}")`);
// On the first call, resolve with the server result
if (isHydrationRequest) {
if (initialError !== undefined) {
throw initialError;
}
return initialData;
}
// Otherwise, resolve the hydration clientLoader with the pre-loaded server data
return initialData;
// Call the server loader for client-side navigations
return fetchServerLoader(request, true, singleFetch);
}
// Call the server loader for client-side navigations
let result = await fetchServerLoader(request);
let unwrapped = await unwrapServerResponse(result);
return unwrapped;
}
});
});
});
return result;
} finally {
// Whether or not the user calls `serverLoader`, we only let this
// stick around as true for one loader call
isHydrationRequest = false;
}
};
// Let React Router know whether to run this on hydration
dataRoute.loader.hydrate = routeModule.clientLoader != null && (routeModule.clientLoader.hydrate === true || route.hasLoader !== true);
dataRoute.loader.hydrate = shouldHydrateRouteLoader(route, routeModule, isSpaMode);
dataRoute.action = ({
request,
params
}) => {
}, singleFetch) => {
return prefetchStylesAndCallHandler(async () => {
invariant(routeModule, "No `routeModule` available for critical-route action");
if (!routeModule.clientAction) {
return fetchServerAction(request);
if (isSpaMode) {
throw noActionDefinedError("clientAction", route.id);
}
return fetchServerAction(request, false, singleFetch);
}

@@ -166,5 +241,4 @@ return routeModule.clientAction({

async serverAction() {
let result = await fetchServerAction(request);
let unwrapped = await unwrapServerResponse(result);
return unwrapped;
preventInvalidServerHandlerCall("action", route, isSpaMode);
return fetchServerAction(request, true, singleFetch);
}

@@ -181,3 +255,6 @@ });

request
}) => prefetchStylesAndCallHandler(() => fetchServerLoader(request));
}, singleFetch) => prefetchStylesAndCallHandler(() => {
if (isSpaMode) return Promise.resolve(null);
return fetchServerLoader(request, false, singleFetch);
});
}

@@ -187,3 +264,8 @@ if (!route.hasClientAction) {

request
}) => prefetchStylesAndCallHandler(() => fetchServerAction(request));
}, singleFetch) => prefetchStylesAndCallHandler(() => {
if (isSpaMode) {
throw noActionDefinedError("clientAction", route.id);
}
return fetchServerAction(request, false, singleFetch);
});
}

@@ -199,8 +281,7 @@

let clientLoader = mod.clientLoader;
lazyRoute.loader = args => clientLoader({
lazyRoute.loader = (args, singleFetch) => clientLoader({
...args,
async serverLoader() {
let response = await fetchServerLoader(args.request);
let result = await unwrapServerResponse(response);
return result;
preventInvalidServerHandlerCall("loader", route, isSpaMode);
return fetchServerLoader(args.request, true, singleFetch);
}

@@ -211,8 +292,7 @@ });

let clientAction = mod.clientAction;
lazyRoute.action = args => clientAction({
lazyRoute.action = (args, singleFetch) => clientAction({
...args,
async serverAction() {
let response = await fetchServerAction(args.request);
let result = await unwrapServerResponse(response);
return result;
preventInvalidServerHandlerCall("action", route, isSpaMode);
return fetchServerAction(args.request, true, singleFetch);
}

@@ -234,2 +314,4 @@ });

handle: lazyRoute.handle,
// No need to wrap these in layout since the root route is never
// loaded via route.lazy()
Component: lazyRoute.Component,

@@ -240,3 +322,3 @@ ErrorBoundary: lazyRoute.ErrorBoundary

}
let children = createClientRoutes(manifest, routeModulesCache, initialState, future, route.id, routesByParentId, needsRevalidation);
let children = createClientRoutes(manifest, routeModulesCache, initialState, future, isSpaMode, route.id, routesByParentId, needsRevalidation);
if (children.length > 0) dataRoute.children = children;

@@ -320,2 +402,6 @@ return dataRoute;

}
let replace = response.headers.get("X-Remix-Replace");
if (replace) {
headers["X-Remix-Replace"] = replace;
}
return redirect(url, {

@@ -338,3 +424,6 @@ status,

}
function shouldHydrateRouteLoader(route, routeModule, isSpaMode) {
return isSpaMode && route.id !== "root" || routeModule.clientLoader != null && (routeModule.clientLoader.hydrate === true || route.hasLoader !== true);
}
export { createClientRoutes, createClientRoutesWithHMRRevalidationOptOut, createServerRoutes };
export { createClientRoutes, createClientRoutesWithHMRRevalidationOptOut, createServerRoutes, shouldHydrateRouteLoader };
/**
* @remix-run/react v0.0.0-nightly-910b900-20231207
* @remix-run/react v0.0.0-nightly-91184a743-20240823
*

@@ -14,2 +14,3 @@ * Copyright (c) Remix Software Inc.

import { useLocation, useMatches, UNSAFE_useScrollRestoration } from 'react-router-dom';
import { useRemixContext } from './components.js';

@@ -28,2 +29,5 @@ let STORAGE_KEY = "positions";

}) {
let {
isSpaMode
} = useRemixContext();
let location = useLocation();

@@ -50,2 +54,8 @@ let matches = useMatches();

[]);
// In SPA Mode, there's nothing to restore on initial render since we didn't
// render anything on the server
if (isSpaMode) {
return null;
}
let restoreScroll = ((STORAGE_KEY, restoreKey) => {

@@ -52,0 +62,0 @@ if (!window.history.state || !window.history.state.key) {

/**
* @remix-run/react v0.0.0-nightly-910b900-20231207
* @remix-run/react v0.0.0-nightly-91184a743-20240823
*

@@ -15,3 +15,4 @@ * Copyright (c) Remix Software Inc.

import { RemixErrorBoundary } from './errorBoundaries.js';
import { createServerRoutes } from './routes.js';
import { createServerRoutes, shouldHydrateRouteLoader } from './routes.js';
import { StreamTransfer } from './single-fetch.js';

@@ -26,3 +27,4 @@ /**

url,
abortDelay
abortDelay,
nonce
}) {

@@ -38,3 +40,3 @@ if (typeof url === "string") {

} = context;
let routes = createServerRoutes(manifest.routes, routeModules, context.future);
let routes = createServerRoutes(manifest.routes, routeModules, context.future, context.isSpaMode);

@@ -53,11 +55,7 @@ // Create a shallow clone of `loaderData` we can mutate for partial hydration.

let manifestRoute = context.manifest.routes[routeId];
if (
// This route specifically gave us a HydrateFallback
route && route.clientLoader && route.HydrateFallback ||
// This handles routes without a server loader but _with_ a clientLoader
// that will automatically opt-into clientLoader.hydrate=true. The
// staticHandler always puts a `null` in loaderData for non-loader routes
// for proper serialization but we need to set that back to `undefined`
// so _renderMatches will detect a required fallback at this level
manifestRoute && manifestRoute.hasLoader == false && context.staticHandlerContext.loaderData[routeId] === null) {
// Clear out the loaderData to avoid rendering the route component when the
// route opted into clientLoader hydration and either:
// * gave us a HydrateFallback
// * or doesn't have a server loader and we have no data to render
if (route && shouldHydrateRouteLoader(manifestRoute, route, context.isSpaMode) && (route.HydrateFallback || !manifestRoute.hasLoader)) {
context.staticHandlerContext.loaderData[routeId] = undefined;

@@ -72,3 +70,3 @@ }

});
return /*#__PURE__*/React.createElement(RemixContext.Provider, {
return /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(RemixContext.Provider, {
value: {

@@ -80,4 +78,6 @@ manifest,

future: context.future,
isSpaMode: context.isSpaMode,
serializeError: context.serializeError,
abortDelay
abortDelay,
renderMeta: context.renderMeta
}

@@ -90,5 +90,11 @@ }, /*#__PURE__*/React.createElement(RemixErrorBoundary, {

hydrate: false
})));
}))), context.future.unstable_singleFetch && context.serverHandoffStream ? /*#__PURE__*/React.createElement(React.Suspense, null, /*#__PURE__*/React.createElement(StreamTransfer, {
context: context,
identifier: 0,
reader: context.serverHandoffStream.getReader(),
textDecoder: new TextDecoder(),
nonce: nonce
})) : null);
}
export { RemixServer };
/**
* @remix-run/react v0.0.0-nightly-910b900-20231207
* @remix-run/react v0.0.0-nightly-91184a743-20240823
*

@@ -16,3 +16,3 @@ * Copyright (c) Remix Software Inc.

var React = require('react');
var components = require('./components.js');
var errorBoundaries = require('./errorBoundaries.js');

@@ -44,10 +44,6 @@ function _interopNamespace(e) {

function RemixRootDefaultHydrateFallback() {
return /*#__PURE__*/React__namespace.createElement("html", {
lang: "en"
}, /*#__PURE__*/React__namespace.createElement("head", null, /*#__PURE__*/React__namespace.createElement("meta", {
charSet: "utf-8"
}), /*#__PURE__*/React__namespace.createElement("meta", {
name: "viewport",
content: "width=device-width,initial-scale=1,viewport-fit=cover"
})), /*#__PURE__*/React__namespace.createElement("body", null, /*#__PURE__*/React__namespace.createElement(components.Scripts, null), /*#__PURE__*/React__namespace.createElement("script", {
return /*#__PURE__*/React__namespace.createElement(errorBoundaries.BoundaryShell, {
title: "Loading...",
renderScripts: true
}, /*#__PURE__*/React__namespace.createElement("script", {
dangerouslySetInnerHTML: {

@@ -57,10 +53,11 @@ __html: `

"💿 Hey developer 👋. You can provide a way better UX than this " +
"when your app is running \`clientLoader\` functions on hydration. " +
"Check out https://remix.run/route/hydrate-fallback for more information."
"when your app is loading JS modules and/or running \`clientLoader\` " +
"functions. Check out https://remix.run/route/hydrate-fallback " +
"for more information."
);
`
}
}), " "));
}));
}
exports.RemixRootDefaultHydrateFallback = RemixRootDefaultHydrateFallback;

@@ -0,13 +1,16 @@

export type { ErrorResponse, Fetcher, FetcherWithComponents, FormEncType, FormMethod, Location, NavigateFunction, Navigation, Params, Path, ShouldRevalidateFunction, ShouldRevalidateFunctionArgs, SubmitFunction, SubmitOptions, Blocker, BlockerFunction, } from "react-router-dom";
export { createPath, createRoutesFromChildren, createRoutesFromElements, createSearchParams, generatePath, matchPath, matchRoutes, parsePath, renderMatches, resolvePath, Navigate, NavigationType, Outlet, Route, Routes, useAsyncError, useAsyncValue, isRouteErrorResponse, useBeforeUnload, useFetchers, useFormAction, useHref, useInRouterContext, useLinkClickHandler, useLocation, useMatch, useNavigate, useNavigation, useNavigationType, useOutlet, useOutletContext, useParams, useResolvedPath, useRevalidator, useRouteError, useRoutes, useSearchParams, useSubmit, useBlocker, unstable_usePrompt, unstable_useViewTransitionState, } from "react-router-dom";
export { defer, json, redirect, redirectDocument, replace, unstable_data, } from "@remix-run/server-runtime";
export type { RemixBrowserProps } from "./browser";
export { RemixBrowser } from "./browser";
export type { ErrorResponse, Fetcher, FetcherWithComponents, FormEncType, FormMethod, FormProps, Location, NavigateFunction, Navigation, Params, Path, ShouldRevalidateFunction, ShouldRevalidateFunctionArgs, SubmitFunction, SubmitOptions, unstable_Blocker, unstable_BlockerFunction, } from "react-router-dom";
export { createPath, generatePath, matchPath, matchRoutes, parsePath, resolvePath, Form, Outlet, useAsyncError, useAsyncValue, isRouteErrorResponse, useBeforeUnload, useFetchers, useFormAction, useHref, useLocation, useMatch, useNavigate, useNavigation, useNavigationType, useOutlet, useOutletContext, useParams, useResolvedPath, useRevalidator, useRouteError, useSearchParams, useSubmit, useBlocker, unstable_usePrompt, unstable_useViewTransitionState, } from "react-router-dom";
export type { AwaitProps, RemixNavLinkProps as NavLinkProps, RemixLinkProps as LinkProps, UIMatch, } from "./components";
export { Await, Meta, Links, Scripts, Link, NavLink, PrefetchPageLinks, LiveReload, useFetcher, useLoaderData, useRouteLoaderData, useActionData, useMatches, RemixContext as UNSAFE_RemixContext, } from "./components";
export type { AwaitProps, RemixFormProps as FormProps, RemixNavLinkProps as NavLinkProps, RemixLinkProps as LinkProps, UIMatch, } from "./components";
export { Await, Meta, Links, Scripts, Form, Link, NavLink, PrefetchPageLinks, LiveReload, useFetcher, useLoaderData, useRouteLoaderData, useActionData, useMatches, RemixContext as UNSAFE_RemixContext, } from "./components";
export type { HtmlLinkDescriptor } from "./links";
export type { ClientActionFunction, ClientActionFunctionArgs, ClientLoaderFunction, ClientLoaderFunctionArgs, MetaArgs, MetaDescriptor, MetaFunction, RouteModules as UNSAFE_RouteModules, } from "./routeModules";
export type { ClientActionFunction, ClientActionFunctionArgs, ClientLoaderFunction, ClientLoaderFunctionArgs, MetaArgs, MetaMatch as UNSAFE_MetaMatch, MetaDescriptor, MetaFunction, RouteModules as UNSAFE_RouteModules, } from "./routeModules";
export { ScrollRestoration } from "./scroll-restoration";
export type { RemixServerProps } from "./server";
export { RemixServer } from "./server";
export type { ClientAction as unstable_ClientAction, ClientLoader as unstable_ClientLoader, } from "./single-fetch";
export { defineClientAction as unstable_defineClientAction, defineClientLoader as unstable_defineClientLoader, } from "./single-fetch";
export type { FutureConfig as UNSAFE_FutureConfig, AssetsManifest as UNSAFE_AssetsManifest, RemixContextObject as UNSAFE_RemixContextObject, } from "./entry";
export type { EntryRoute as UNSAFE_EntryRoute, RouteManifest as UNSAFE_RouteManifest, } from "./routes";
/**
* @remix-run/react v0.0.0-nightly-910b900-20231207
* @remix-run/react v0.0.0-nightly-91184a743-20240823
*

@@ -15,15 +15,20 @@ * Copyright (c) Remix Software Inc.

var reactRouterDom = require('react-router-dom');
var serverRuntime = require('@remix-run/server-runtime');
var browser = require('./browser.js');
var reactRouterDom = require('react-router-dom');
var components = require('./components.js');
var scrollRestoration = require('./scroll-restoration.js');
var server = require('./server.js');
var singleFetch = require('./single-fetch.js');
exports.RemixBrowser = browser.RemixBrowser;
Object.defineProperty(exports, 'Form', {
Object.defineProperty(exports, 'Navigate', {
enumerable: true,
get: function () { return reactRouterDom.Form; }
get: function () { return reactRouterDom.Navigate; }
});
Object.defineProperty(exports, 'NavigationType', {
enumerable: true,
get: function () { return reactRouterDom.NavigationType; }
});
Object.defineProperty(exports, 'Outlet', {

@@ -33,2 +38,10 @@ enumerable: true,

});
Object.defineProperty(exports, 'Route', {
enumerable: true,
get: function () { return reactRouterDom.Route; }
});
Object.defineProperty(exports, 'Routes', {
enumerable: true,
get: function () { return reactRouterDom.Routes; }
});
Object.defineProperty(exports, 'createPath', {

@@ -38,2 +51,14 @@ enumerable: true,

});
Object.defineProperty(exports, 'createRoutesFromChildren', {
enumerable: true,
get: function () { return reactRouterDom.createRoutesFromChildren; }
});
Object.defineProperty(exports, 'createRoutesFromElements', {
enumerable: true,
get: function () { return reactRouterDom.createRoutesFromElements; }
});
Object.defineProperty(exports, 'createSearchParams', {
enumerable: true,
get: function () { return reactRouterDom.createSearchParams; }
});
Object.defineProperty(exports, 'generatePath', {

@@ -59,2 +84,6 @@ enumerable: true,

});
Object.defineProperty(exports, 'renderMatches', {
enumerable: true,
get: function () { return reactRouterDom.renderMatches; }
});
Object.defineProperty(exports, 'resolvePath', {

@@ -100,2 +129,10 @@ enumerable: true,

});
Object.defineProperty(exports, 'useInRouterContext', {
enumerable: true,
get: function () { return reactRouterDom.useInRouterContext; }
});
Object.defineProperty(exports, 'useLinkClickHandler', {
enumerable: true,
get: function () { return reactRouterDom.useLinkClickHandler; }
});
Object.defineProperty(exports, 'useLocation', {

@@ -145,2 +182,6 @@ enumerable: true,

});
Object.defineProperty(exports, 'useRoutes', {
enumerable: true,
get: function () { return reactRouterDom.useRoutes; }
});
Object.defineProperty(exports, 'useSearchParams', {

@@ -154,3 +195,29 @@ enumerable: true,

});
Object.defineProperty(exports, 'defer', {
enumerable: true,
get: function () { return serverRuntime.defer; }
});
Object.defineProperty(exports, 'json', {
enumerable: true,
get: function () { return serverRuntime.json; }
});
Object.defineProperty(exports, 'redirect', {
enumerable: true,
get: function () { return serverRuntime.redirect; }
});
Object.defineProperty(exports, 'redirectDocument', {
enumerable: true,
get: function () { return serverRuntime.redirectDocument; }
});
Object.defineProperty(exports, 'replace', {
enumerable: true,
get: function () { return serverRuntime.replace; }
});
Object.defineProperty(exports, 'unstable_data', {
enumerable: true,
get: function () { return serverRuntime.unstable_data; }
});
exports.RemixBrowser = browser.RemixBrowser;
exports.Await = components.Await;
exports.Form = components.Form;
exports.Link = components.Link;

@@ -171,1 +238,3 @@ exports.Links = components.Links;

exports.RemixServer = server.RemixServer;
exports.unstable_defineClientAction = singleFetch.defineClientAction;
exports.unstable_defineClientLoader = singleFetch.defineClientLoader;
/**
* @remix-run/react v0.0.0-nightly-910b900-20231207
* @remix-run/react v0.0.0-nightly-91184a743-20240823
*

@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc.

/**
* @remix-run/react v0.0.0-nightly-910b900-20231207
* @remix-run/react v0.0.0-nightly-91184a743-20240823
*

@@ -25,2 +25,3 @@ * Copyright (c) Remix Software Inc.

////////////////////////////////////////////////////////////////////////////////
/**

@@ -38,3 +39,3 @@ * Gets all the links for a set of matches. The modules are assumed to have been

href
})) : [], ((_module$links = module.links) === null || _module$links === void 0 ? void 0 : _module$links.call(module)) || []];
})) : [], (module === null || module === void 0 ? void 0 : (_module$links = module.links) === null || _module$links === void 0 ? void 0 : _module$links.call(module)) || []];
}).flat(2);

@@ -177,3 +178,3 @@ let preloads = getCurrentPageModulePreloadHrefs(matches, manifest);

let path = parsePathPatch(page);
return dedupeHrefs(matches.filter(match => manifest.routes[match.route.id].hasLoader).map(match => {
return dedupeHrefs(matches.filter(match => manifest.routes[match.route.id].hasLoader && !manifest.routes[match.route.id].hasClientLoader).map(match => {
let {

@@ -180,0 +181,0 @@ pathname,

/**
* @remix-run/react v0.0.0-nightly-910b900-20231207
* @remix-run/react v0.0.0-nightly-91184a743-20240823
*

@@ -4,0 +4,0 @@ * Copyright (c) Remix Software Inc.

@@ -1,2 +0,2 @@

import type { ComponentType } from "react";
import type { ComponentType, ReactElement } from "react";
import type { ActionFunction as RRActionFunction, ActionFunctionArgs as RRActionFunctionArgs, LoaderFunction as RRLoaderFunction, LoaderFunctionArgs as RRLoaderFunctionArgs, DataRouteMatch, Params, Location, ShouldRevalidateFunction } from "react-router-dom";

@@ -8,3 +8,3 @@ import type { LoaderFunction, SerializeFrom } from "@remix-run/server-runtime";

export interface RouteModules {
[routeId: string]: RouteModule;
[routeId: string]: RouteModule | undefined;
}

@@ -16,2 +16,3 @@ export interface RouteModule {

HydrateFallback?: HydrateFallbackComponent;
Layout?: LayoutComponent;
default: RouteComponent;

@@ -55,2 +56,10 @@ handle?: RouteHandle;

/**
* Optional, root-only `<Route Layout>` component to wrap the root content in.
* Useful for defining the <html>/<head>/<body> document shell shared by the
* Component, HydrateFallback, and ErrorBoundary
*/
export type LayoutComponent = ComponentType<{
children: ReactElement<unknown, ErrorBoundaryComponent | HydrateFallbackComponent | RouteComponent>;
}>;
/**
* A function that defines `<link>` tags to be inserted into the `<head>` of

@@ -57,0 +66,0 @@ * the document on route transitions.

/**
* @remix-run/react v0.0.0-nightly-910b900-20231207
* @remix-run/react v0.0.0-nightly-91184a743-20240823
*

@@ -59,2 +59,8 @@ * Copyright (c) Remix Software Inc.

/**
* Optional, root-only `<Route Layout>` component to wrap the root content in.
* Useful for defining the <html>/<head>/<body> document shell shared by the
* Component, HydrateFallback, and ErrorBoundary
*/
/**
* A function that defines `<link>` tags to be inserted into the `<head>` of

@@ -85,6 +91,23 @@ * the document on route transitions.

} catch (error) {
// User got caught in the middle of a deploy and the CDN no longer has the
// asset we're trying to import! Reload from the server and the user
// (should) get the new manifest--unless the developer purged the static
// assets, the manifest path, but not the documents 😬
// If we can't load the route it's likely one of 2 things:
// - User got caught in the middle of a deploy and the CDN no longer has the
// asset we're trying to import! Reload from the server and the user
// (should) get the new manifest--unless the developer purged the static
// assets, the manifest path, but not the documents 😬
// - Or, the asset trying to be imported has an error (usually in vite dev
// mode), so the best we can do here is log the error for visibility
// (via `Preserve log`) and reload
// Log the error so it can be accessed via the `Preserve Log` setting
console.error(`Error loading route module \`${route.module}\`, reloading page...`);
console.error(error);
if (window.__remixContext.isSpaMode &&
// @ts-expect-error
typeof undefined !== "undefined") {
// In SPA Mode (which implies vite) we don't want to perform a hard reload
// on dev-time errors since it's a vite compilation error and a reload is
// just going to fail with the same issue. Let the UI bubble to the error
// boundary and let them see the error in the overlay or the dev server log
throw error;
}
window.location.reload();

@@ -91,0 +114,0 @@ return new Promise(() => {

import type { HydrationState } from "@remix-run/router";
import type { DataRouteObject } from "react-router-dom";
import type { RouteModules } from "./routeModules";
import type { RouteModule, RouteModules } from "./routeModules";
import type { FutureConfig } from "./entry";

@@ -26,5 +26,8 @@ export interface RouteManifest<Route> {

}
export declare function createServerRoutes(manifest: RouteManifest<EntryRoute>, routeModules: RouteModules, future: FutureConfig, parentId?: string, routesByParentId?: Record<string, Omit<EntryRoute, "children">[]>): DataRouteObject[];
export declare function createClientRoutesWithHMRRevalidationOptOut(needsRevalidation: Set<string>, manifest: RouteManifest<EntryRoute>, routeModulesCache: RouteModules, initialState: HydrationState, future: FutureConfig): DataRouteObject[];
export declare function createClientRoutes(manifest: RouteManifest<EntryRoute>, routeModulesCache: RouteModules, initialState: HydrationState, future: FutureConfig, parentId?: string, routesByParentId?: Record<string, Omit<EntryRoute, "children">[]>, needsRevalidation?: Set<string>): DataRouteObject[];
export declare function createServerRoutes(manifest: RouteManifest<EntryRoute>, routeModules: RouteModules, future: FutureConfig, isSpaMode: boolean, parentId?: string, routesByParentId?: Record<string, Omit<EntryRoute, "children">[]>, spaModeLazyPromise?: Promise<{
Component: () => null;
}>): DataRouteObject[];
export declare function createClientRoutesWithHMRRevalidationOptOut(needsRevalidation: Set<string>, manifest: RouteManifest<EntryRoute>, routeModulesCache: RouteModules, initialState: HydrationState, future: FutureConfig, isSpaMode: boolean): DataRouteObject[];
export declare function createClientRoutes(manifest: RouteManifest<EntryRoute>, routeModulesCache: RouteModules, initialState: HydrationState | null, future: FutureConfig, isSpaMode: boolean, parentId?: string, routesByParentId?: Record<string, Omit<EntryRoute, "children">[]>, needsRevalidation?: Set<string>): DataRouteObject[];
export declare function shouldHydrateRouteLoader(route: EntryRoute, routeModule: RouteModule, isSpaMode: boolean): boolean;
export {};
/**
* @remix-run/react v0.0.0-nightly-910b900-20231207
* @remix-run/react v0.0.0-nightly-91184a743-20240823
*

@@ -23,2 +23,3 @@ * Copyright (c) Remix Software Inc.

var fallback = require('./fallback.js');
var invariant = require('./invariant.js');

@@ -62,16 +63,52 @@ function _interopNamespace(e) {

}
function createServerRoutes(manifest, routeModules, future, parentId = "", routesByParentId = groupRoutesByParentId(manifest)) {
function getRouteComponents(route, routeModule, isSpaMode) {
let Component = getRouteModuleComponent(routeModule);
// HydrateFallback can only exist on the root route in SPA Mode
let HydrateFallback = routeModule.HydrateFallback && (!isSpaMode || route.id === "root") ? routeModule.HydrateFallback : route.id === "root" ? fallback.RemixRootDefaultHydrateFallback : undefined;
let ErrorBoundary = routeModule.ErrorBoundary ? routeModule.ErrorBoundary : route.id === "root" ? () => /*#__PURE__*/React__namespace.createElement(errorBoundaries.RemixRootDefaultErrorBoundary, {
error: reactRouterDom.useRouteError()
}) : undefined;
if (route.id === "root" && routeModule.Layout) {
return {
...(Component ? {
element: /*#__PURE__*/React__namespace.createElement(routeModule.Layout, null, /*#__PURE__*/React__namespace.createElement(Component, null))
} : {
Component
}),
...(ErrorBoundary ? {
errorElement: /*#__PURE__*/React__namespace.createElement(routeModule.Layout, null, /*#__PURE__*/React__namespace.createElement(ErrorBoundary, null))
} : {
ErrorBoundary
}),
...(HydrateFallback ? {
hydrateFallbackElement: /*#__PURE__*/React__namespace.createElement(routeModule.Layout, null, /*#__PURE__*/React__namespace.createElement(HydrateFallback, null))
} : {
HydrateFallback
})
};
}
return {
Component,
ErrorBoundary,
HydrateFallback
};
}
function createServerRoutes(manifest, routeModules, future, isSpaMode, parentId = "", routesByParentId = groupRoutesByParentId(manifest), spaModeLazyPromise = Promise.resolve({
Component: () => null
})) {
return (routesByParentId[parentId] || []).map(route => {
let routeModule = routeModules[route.id];
invariant(routeModule, "No `routeModule` available to create server routes");
let dataRoute = {
...getRouteComponents(route, routeModule, isSpaMode),
caseSensitive: route.caseSensitive,
Component: getRouteModuleComponent(routeModule),
HydrateFallback: routeModule.HydrateFallback ? routeModule.HydrateFallback : route.id === "root" ? fallback.RemixRootDefaultHydrateFallback : undefined,
ErrorBoundary: routeModule.ErrorBoundary ? routeModule.ErrorBoundary : route.id === "root" ? () => /*#__PURE__*/React__namespace.createElement(errorBoundaries.RemixRootDefaultErrorBoundary, {
error: reactRouterDom.useRouteError()
}) : undefined,
id: route.id,
index: route.index,
path: route.path,
handle: routeModules[route.id].handle,
handle: routeModule.handle,
// For SPA Mode, all routes are lazy except root. However we tell the
// router root is also lazy here too since we don't need a full
// implementation - we just need a `lazy` prop to tell the RR rendering
// where to stop which is always at the root route in SPA mode
lazy: isSpaMode ? () => spaModeLazyPromise : undefined,
// For partial hydration rendering, we need to indicate when the route

@@ -85,4 +122,3 @@ // has a loader/clientLoader, but it won't ever be called during the static

};
let children = createServerRoutes(manifest, routeModules, future, route.id, routesByParentId);
let children = createServerRoutes(manifest, routeModules, future, isSpaMode, route.id, routesByParentId, spaModeLazyPromise);
if (children.length > 0) dataRoute.children = children;

@@ -92,24 +128,57 @@ return dataRoute;

}
function createClientRoutesWithHMRRevalidationOptOut(needsRevalidation, manifest, routeModulesCache, initialState, future) {
return createClientRoutes(manifest, routeModulesCache, initialState, future, "", groupRoutesByParentId(manifest), needsRevalidation);
function createClientRoutesWithHMRRevalidationOptOut(needsRevalidation, manifest, routeModulesCache, initialState, future, isSpaMode) {
return createClientRoutes(manifest, routeModulesCache, initialState, future, isSpaMode, "", groupRoutesByParentId(manifest), needsRevalidation);
}
function createClientRoutes(manifest, routeModulesCache, initialState, future, parentId = "", routesByParentId = groupRoutesByParentId(manifest), needsRevalidation) {
function preventInvalidServerHandlerCall(type, route, isSpaMode) {
if (isSpaMode) {
let fn = type === "action" ? "serverAction()" : "serverLoader()";
let msg = `You cannot call ${fn} in SPA Mode (routeId: "${route.id}")`;
console.error(msg);
throw new router.UNSAFE_ErrorResponseImpl(400, "Bad Request", new Error(msg), true);
}
let fn = type === "action" ? "serverAction()" : "serverLoader()";
let msg = `You are trying to call ${fn} on a route that does not have a server ` + `${type} (routeId: "${route.id}")`;
if (type === "loader" && !route.hasLoader || type === "action" && !route.hasAction) {
console.error(msg);
throw new router.UNSAFE_ErrorResponseImpl(400, "Bad Request", new Error(msg), true);
}
}
function noActionDefinedError(type, routeId) {
let article = type === "clientAction" ? "a" : "an";
let msg = `Route "${routeId}" does not have ${article} ${type}, but you are trying to ` + `submit to it. To fix this, please add ${article} \`${type}\` function to the route`;
console.error(msg);
throw new router.UNSAFE_ErrorResponseImpl(405, "Method Not Allowed", new Error(msg), true);
}
function createClientRoutes(manifest, routeModulesCache, initialState, future, isSpaMode, parentId = "", routesByParentId = groupRoutesByParentId(manifest), needsRevalidation) {
return (routesByParentId[parentId] || []).map(route => {
let routeModule = routeModulesCache[route.id];
async function fetchServerLoader(request) {
if (!route.hasLoader) return null;
return fetchServerHandler(request, route);
// Fetch data from the server either via single fetch or the standard `?_data`
// request. Unwrap it when called via `serverLoader`/`serverAction` in a
// client handler, otherwise return the raw response for the router to unwrap
async function fetchServerHandlerAndMaybeUnwrap(request, unwrap, singleFetch) {
if (typeof singleFetch === "function") {
let result = await singleFetch();
return result;
}
let result = await fetchServerHandler(request, route);
return unwrap ? unwrapServerResponse(result) : result;
}
async function fetchServerAction(request) {
function fetchServerLoader(request, unwrap, singleFetch) {
if (!route.hasLoader) return Promise.resolve(null);
return fetchServerHandlerAndMaybeUnwrap(request, unwrap, singleFetch);
}
function fetchServerAction(request, unwrap, singleFetch) {
if (!route.hasAction) {
let msg = `Route "${route.id}" does not have an action, but you are trying ` + `to submit to it. To fix this, please add an \`action\` function to the route`;
console.error(msg);
throw new router.UNSAFE_ErrorResponseImpl(405, "Method Not Allowed", new Error(msg), true);
throw noActionDefinedError("action", route.id);
}
return fetchServerHandler(request, route);
return fetchServerHandlerAndMaybeUnwrap(request, unwrap, singleFetch);
}
async function prefetchStylesAndCallHandler(handler) {
// Only prefetch links if we've been loaded into the cache, route.lazy
// will handle initial loads
let linkPrefetchPromise = routeModulesCache[route.id] ? links.prefetchStyleLinks(route, routeModulesCache[route.id]) : Promise.resolve();
// Only prefetch links if we exist in the routeModulesCache (critical modules
// and navigating back to pages previously loaded via route.lazy). Initial
// execution of route.lazy (when the module is not in the cache) will handle
// prefetching style links via loadRouteModuleWithBlockingLinks.
let cachedModule = routeModulesCache[route.id];
let linkPrefetchPromise = cachedModule ? links.prefetchStyleLinks(route, cachedModule) : Promise.resolve();
try {

@@ -127,59 +196,65 @@ return handler();

if (routeModule) {
var _initialState$loaderD, _initialState$errors, _routeModule$clientLo;
// Use critical path modules directly
Object.assign(dataRoute, {
...dataRoute,
Component: getRouteModuleComponent(routeModule),
HydrateFallback: routeModule.HydrateFallback ? routeModule.HydrateFallback : route.id === "root" ? fallback.RemixRootDefaultHydrateFallback : undefined,
ErrorBoundary: routeModule.ErrorBoundary ? routeModule.ErrorBoundary : route.id === "root" ? () => /*#__PURE__*/React__namespace.createElement(errorBoundaries.RemixRootDefaultErrorBoundary, {
error: reactRouterDom.useRouteError()
}) : undefined,
...getRouteComponents(route, routeModule, isSpaMode),
handle: routeModule.handle,
shouldRevalidate: needsRevalidation ? wrapShouldRevalidateForHdr(route.id, routeModule.shouldRevalidate, needsRevalidation) : routeModule.shouldRevalidate
});
let initialData = initialState && initialState.loaderData && initialState.loaderData[route.id];
let isHydrationRequest = needsRevalidation == null && routeModule.clientLoader != null && routeModule.clientLoader.hydrate === true;
dataRoute.loader = ({
let initialData = initialState === null || initialState === void 0 ? void 0 : (_initialState$loaderD = initialState.loaderData) === null || _initialState$loaderD === void 0 ? void 0 : _initialState$loaderD[route.id];
let initialError = initialState === null || initialState === void 0 ? void 0 : (_initialState$errors = initialState.errors) === null || _initialState$errors === void 0 ? void 0 : _initialState$errors[route.id];
let isHydrationRequest = needsRevalidation == null && (((_routeModule$clientLo = routeModule.clientLoader) === null || _routeModule$clientLo === void 0 ? void 0 : _routeModule$clientLo.hydrate) === true || !route.hasLoader);
dataRoute.loader = async ({
request,
params
}) => {
return prefetchStylesAndCallHandler(async () => {
if (!routeModule.clientLoader) {
// Call the server when no client loader exists
return fetchServerLoader(request);
}
return routeModule.clientLoader({
request,
params,
async serverLoader() {
if (isHydrationRequest) {
isHydrationRequest = false;
}, singleFetch) => {
try {
let result = await prefetchStylesAndCallHandler(async () => {
invariant(routeModule, "No `routeModule` available for critical-route loader");
if (!routeModule.clientLoader) {
if (isSpaMode) return null;
// Call the server when no client loader exists
return fetchServerLoader(request, false, singleFetch);
}
return routeModule.clientLoader({
request,
params,
async serverLoader() {
preventInvalidServerHandlerCall("loader", route, isSpaMode);
// Throw an error if a clientLoader tries to call a serverLoader that doesn't exist
if (initialData === undefined) {
throw new Error(`You are trying to call serverLoader() on a route that does " +
"not have a server loader (routeId: "${route.id}")`);
// On the first call, resolve with the server result
if (isHydrationRequest) {
if (initialError !== undefined) {
throw initialError;
}
return initialData;
}
// Otherwise, resolve the hydration clientLoader with the pre-loaded server data
return initialData;
// Call the server loader for client-side navigations
return fetchServerLoader(request, true, singleFetch);
}
// Call the server loader for client-side navigations
let result = await fetchServerLoader(request);
let unwrapped = await unwrapServerResponse(result);
return unwrapped;
}
});
});
});
return result;
} finally {
// Whether or not the user calls `serverLoader`, we only let this
// stick around as true for one loader call
isHydrationRequest = false;
}
};
// Let React Router know whether to run this on hydration
dataRoute.loader.hydrate = routeModule.clientLoader != null && (routeModule.clientLoader.hydrate === true || route.hasLoader !== true);
dataRoute.loader.hydrate = shouldHydrateRouteLoader(route, routeModule, isSpaMode);
dataRoute.action = ({
request,
params
}) => {
}, singleFetch) => {
return prefetchStylesAndCallHandler(async () => {
invariant(routeModule, "No `routeModule` available for critical-route action");
if (!routeModule.clientAction) {
return fetchServerAction(request);
if (isSpaMode) {
throw noActionDefinedError("clientAction", route.id);
}
return fetchServerAction(request, false, singleFetch);
}

@@ -190,5 +265,4 @@ return routeModule.clientAction({

async serverAction() {
let result = await fetchServerAction(request);
let unwrapped = await unwrapServerResponse(result);
return unwrapped;
preventInvalidServerHandlerCall("action", route, isSpaMode);
return fetchServerAction(request, true, singleFetch);
}

@@ -205,3 +279,6 @@ });

request
}) => prefetchStylesAndCallHandler(() => fetchServerLoader(request));
}, singleFetch) => prefetchStylesAndCallHandler(() => {
if (isSpaMode) return Promise.resolve(null);
return fetchServerLoader(request, false, singleFetch);
});
}

@@ -211,3 +288,8 @@ if (!route.hasClientAction) {

request
}) => prefetchStylesAndCallHandler(() => fetchServerAction(request));
}, singleFetch) => prefetchStylesAndCallHandler(() => {
if (isSpaMode) {
throw noActionDefinedError("clientAction", route.id);
}
return fetchServerAction(request, false, singleFetch);
});
}

@@ -223,8 +305,7 @@

let clientLoader = mod.clientLoader;
lazyRoute.loader = args => clientLoader({
lazyRoute.loader = (args, singleFetch) => clientLoader({
...args,
async serverLoader() {
let response = await fetchServerLoader(args.request);
let result = await unwrapServerResponse(response);
return result;
preventInvalidServerHandlerCall("loader", route, isSpaMode);
return fetchServerLoader(args.request, true, singleFetch);
}

@@ -235,8 +316,7 @@ });

let clientAction = mod.clientAction;
lazyRoute.action = args => clientAction({
lazyRoute.action = (args, singleFetch) => clientAction({
...args,
async serverAction() {
let response = await fetchServerAction(args.request);
let result = await unwrapServerResponse(response);
return result;
preventInvalidServerHandlerCall("action", route, isSpaMode);
return fetchServerAction(args.request, true, singleFetch);
}

@@ -258,2 +338,4 @@ });

handle: lazyRoute.handle,
// No need to wrap these in layout since the root route is never
// loaded via route.lazy()
Component: lazyRoute.Component,

@@ -264,3 +346,3 @@ ErrorBoundary: lazyRoute.ErrorBoundary

}
let children = createClientRoutes(manifest, routeModulesCache, initialState, future, route.id, routesByParentId, needsRevalidation);
let children = createClientRoutes(manifest, routeModulesCache, initialState, future, isSpaMode, route.id, routesByParentId, needsRevalidation);
if (children.length > 0) dataRoute.children = children;

@@ -344,2 +426,6 @@ return dataRoute;

}
let replace = response.headers.get("X-Remix-Replace");
if (replace) {
headers["X-Remix-Replace"] = replace;
}
return reactRouterDom.redirect(url, {

@@ -362,2 +448,5 @@ status,

}
function shouldHydrateRouteLoader(route, routeModule, isSpaMode) {
return isSpaMode && route.id !== "root" || routeModule.clientLoader != null && (routeModule.clientLoader.hydrate === true || route.hasLoader !== true);
}

@@ -367,1 +456,2 @@ exports.createClientRoutes = createClientRoutes;

exports.createServerRoutes = createServerRoutes;
exports.shouldHydrateRouteLoader = shouldHydrateRouteLoader;

@@ -12,2 +12,2 @@ import * as React from "react";

getKey?: ScrollRestorationPropsRR["getKey"];
}): React.JSX.Element;
}): React.JSX.Element | null;
/**
* @remix-run/react v0.0.0-nightly-910b900-20231207
* @remix-run/react v0.0.0-nightly-91184a743-20240823
*

@@ -18,2 +18,3 @@ * Copyright (c) Remix Software Inc.

var reactRouterDom = require('react-router-dom');
var components = require('./components.js');

@@ -52,2 +53,5 @@ function _interopNamespace(e) {

}) {
let {
isSpaMode
} = components.useRemixContext();
let location = reactRouterDom.useLocation();

@@ -74,2 +78,8 @@ let matches = reactRouterDom.useMatches();

[]);
// In SPA Mode, there's nothing to restore on initial render since we didn't
// render anything on the server
if (isSpaMode) {
return null;
}
let restoreScroll = ((STORAGE_KEY, restoreKey) => {

@@ -76,0 +86,0 @@ if (!window.history.state || !window.history.state.key) {

@@ -7,2 +7,3 @@ import type { ReactElement } from "react";

abortDelay?: number;
nonce?: string;
}

@@ -14,2 +15,2 @@ /**

*/
export declare function RemixServer({ context, url, abortDelay, }: RemixServerProps): ReactElement;
export declare function RemixServer({ context, url, abortDelay, nonce, }: RemixServerProps): ReactElement;
/**
* @remix-run/react v0.0.0-nightly-910b900-20231207
* @remix-run/react v0.0.0-nightly-91184a743-20240823
*

@@ -20,2 +20,3 @@ * Copyright (c) Remix Software Inc.

var routes = require('./routes.js');
var singleFetch = require('./single-fetch.js');

@@ -50,3 +51,4 @@ function _interopNamespace(e) {

url,
abortDelay
abortDelay,
nonce
}) {

@@ -62,3 +64,3 @@ if (typeof url === "string") {

} = context;
let routes$1 = routes.createServerRoutes(manifest.routes, routeModules, context.future);
let routes$1 = routes.createServerRoutes(manifest.routes, routeModules, context.future, context.isSpaMode);

@@ -77,11 +79,7 @@ // Create a shallow clone of `loaderData` we can mutate for partial hydration.

let manifestRoute = context.manifest.routes[routeId];
if (
// This route specifically gave us a HydrateFallback
route && route.clientLoader && route.HydrateFallback ||
// This handles routes without a server loader but _with_ a clientLoader
// that will automatically opt-into clientLoader.hydrate=true. The
// staticHandler always puts a `null` in loaderData for non-loader routes
// for proper serialization but we need to set that back to `undefined`
// so _renderMatches will detect a required fallback at this level
manifestRoute && manifestRoute.hasLoader == false && context.staticHandlerContext.loaderData[routeId] === null) {
// Clear out the loaderData to avoid rendering the route component when the
// route opted into clientLoader hydration and either:
// * gave us a HydrateFallback
// * or doesn't have a server loader and we have no data to render
if (route && routes.shouldHydrateRouteLoader(manifestRoute, route, context.isSpaMode) && (route.HydrateFallback || !manifestRoute.hasLoader)) {
context.staticHandlerContext.loaderData[routeId] = undefined;

@@ -96,3 +94,3 @@ }

});
return /*#__PURE__*/React__namespace.createElement(components.RemixContext.Provider, {
return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(components.RemixContext.Provider, {
value: {

@@ -104,4 +102,6 @@ manifest,

future: context.future,
isSpaMode: context.isSpaMode,
serializeError: context.serializeError,
abortDelay
abortDelay,
renderMeta: context.renderMeta
}

@@ -114,5 +114,11 @@ }, /*#__PURE__*/React__namespace.createElement(errorBoundaries.RemixErrorBoundary, {

hydrate: false
})));
}))), context.future.unstable_singleFetch && context.serverHandoffStream ? /*#__PURE__*/React__namespace.createElement(React__namespace.Suspense, null, /*#__PURE__*/React__namespace.createElement(singleFetch.StreamTransfer, {
context: context,
identifier: 0,
reader: context.serverHandoffStream.getReader(),
textDecoder: new TextDecoder(),
nonce: nonce
})) : null);
}
exports.RemixServer = RemixServer;
MIT License
Copyright (c) Remix Software Inc. 2020-2021
Copyright (c) Shopify Inc. 2022-2023
Copyright (c) Shopify Inc. 2022-2024

@@ -6,0 +6,0 @@ Permission is hereby granted, free of charge, to any person obtaining a copy

{
"name": "@remix-run/react",
"version": "0.0.0-nightly-910b900-20231207",
"version": "0.0.0-nightly-91184a743-20240823",
"description": "React DOM bindings for Remix",

@@ -19,8 +19,11 @@ "bugs": {

"dependencies": {
"@remix-run/router": "1.14.0-pre.0",
"@remix-run/server-runtime": "0.0.0-nightly-910b900-20231207",
"react-router": "6.21.0-pre.0",
"react-router-dom": "6.21.0-pre.0"
"@remix-run/router": "1.19.1",
"@remix-run/server-runtime": "0.0.0-nightly-91184a743-20240823",
"react-router": "6.26.1",
"react-router-dom": "6.26.1",
"turbo-stream": "2.3.0"
},
"devDependencies": {
"@remix-run/node": "0.0.0-nightly-91184a743-20240823",
"@remix-run/react": "0.0.0-nightly-91184a743-20240823",
"@testing-library/jest-dom": "^5.17.0",

@@ -49,6 +52,10 @@ "@testing-library/react": "^13.3.0",

"dist/",
"future/",
"CHANGELOG.md",
"LICENSE.md",
"README.md"
]
}
],
"scripts": {
"tsc": "tsc"
}
}
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc