'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var React = require('react'); var router = require('@remix-run/router'); var reactRouter = require('react-router'); var reactRouterDom = require('react-router-dom'); function _interopNamespace(e) { if (e && e.__esModule) return e; var n = Object.create(null); if (e) { Object.keys(e).forEach(function (k) { if (k !== 'default') { var d = Object.getOwnPropertyDescriptor(e, k); Object.defineProperty(n, k, d.get ? d : { enumerable: true, get: function () { return e[k]; } }); } }); } n["default"] = e; return Object.freeze(n); } var React__namespace = /*#__PURE__*/_interopNamespace(React); /** * A `` that may not navigate to any other location. This is useful * on the server where there is no stateful UI. */ function StaticRouter({ basename, children, location: locationProp = "/", future }) { if (typeof locationProp === "string") { locationProp = reactRouterDom.parsePath(locationProp); } let action = router.Action.Pop; let location = { pathname: locationProp.pathname || "/", search: locationProp.search || "", hash: locationProp.hash || "", state: locationProp.state != null ? locationProp.state : null, key: locationProp.key || "default" }; let staticNavigator = getStatelessNavigator(); return /*#__PURE__*/React__namespace.createElement(reactRouterDom.Router, { basename: basename, children: children, location: location, navigationType: action, navigator: staticNavigator, future: future, static: true }); } /** * A Data Router that may not navigate to any other location. This is useful * on the server where there is no stateful UI. */ function StaticRouterProvider({ context, router: router$1, hydrate = true, nonce }) { !(router$1 && context) ? process.env.NODE_ENV !== "production" ? router.UNSAFE_invariant(false, "You must provide `router` and `context` to ") : router.UNSAFE_invariant(false) : void 0; let dataRouterContext = { router: router$1, navigator: getStatelessNavigator(), static: true, staticContext: context, basename: context.basename || "/" }; let fetchersContext = new Map(); let hydrateScript = ""; if (hydrate !== false) { let data = { loaderData: context.loaderData, actionData: context.actionData, errors: serializeErrors(context.errors) }; // Use JSON.parse here instead of embedding a raw JS object here to speed // up parsing on the client. Dual-stringify is needed to ensure all quotes // are properly escaped in the resulting string. See: // https://v8.dev/blog/cost-of-javascript-2019#json let json = htmlEscape(JSON.stringify(JSON.stringify(data))); hydrateScript = `window.__staticRouterHydrationData = JSON.parse(${json});`; } let { state } = dataRouterContext.router; return /*#__PURE__*/React__namespace.createElement(React__namespace.Fragment, null, /*#__PURE__*/React__namespace.createElement(reactRouterDom.UNSAFE_DataRouterContext.Provider, { value: dataRouterContext }, /*#__PURE__*/React__namespace.createElement(reactRouterDom.UNSAFE_DataRouterStateContext.Provider, { value: state }, /*#__PURE__*/React__namespace.createElement(reactRouterDom.UNSAFE_FetchersContext.Provider, { value: fetchersContext }, /*#__PURE__*/React__namespace.createElement(reactRouterDom.UNSAFE_ViewTransitionContext.Provider, { value: { isTransitioning: false } }, /*#__PURE__*/React__namespace.createElement(reactRouterDom.Router, { basename: dataRouterContext.basename, location: state.location, navigationType: state.historyAction, navigator: dataRouterContext.navigator, static: dataRouterContext.static, future: { v7_relativeSplatPath: router$1.future.v7_relativeSplatPath } }, /*#__PURE__*/React__namespace.createElement(DataRoutes, { routes: router$1.routes, future: router$1.future, state: state })))))), hydrateScript ? /*#__PURE__*/React__namespace.createElement("script", { suppressHydrationWarning: true, nonce: nonce, dangerouslySetInnerHTML: { __html: hydrateScript } }) : null); } function DataRoutes({ routes, future, state }) { return reactRouter.UNSAFE_useRoutesImpl(routes, undefined, state, future); } function serializeErrors(errors) { if (!errors) return null; let entries = Object.entries(errors); let serialized = {}; for (let [key, val] of entries) { // Hey you! If you change this, please change the corresponding logic in // deserializeErrors in react-router-dom/index.tsx :) if (router.isRouteErrorResponse(val)) { serialized[key] = { ...val, __type: "RouteErrorResponse" }; } else if (val instanceof Error) { // Do not serialize stack traces from SSR for security reasons serialized[key] = { message: val.message, __type: "Error", // If this is a subclass (i.e., ReferenceError), send up the type so we // can re-create the same type during hydration. ...(val.name !== "Error" ? { __subType: val.name } : {}) }; } else { serialized[key] = val; } } return serialized; } function getStatelessNavigator() { return { createHref, encodeLocation, push(to) { throw new Error(`You cannot use navigator.push() on the server because it is a stateless ` + `environment. This error was probably triggered when you did a ` + `\`navigate(${JSON.stringify(to)})\` somewhere in your app.`); }, replace(to) { throw new Error(`You cannot use navigator.replace() on the server because it is a stateless ` + `environment. This error was probably triggered when you did a ` + `\`navigate(${JSON.stringify(to)}, { replace: true })\` somewhere ` + `in your app.`); }, go(delta) { throw new Error(`You cannot use navigator.go() on the server because it is a stateless ` + `environment. This error was probably triggered when you did a ` + `\`navigate(${delta})\` somewhere in your app.`); }, back() { throw new Error(`You cannot use navigator.back() on the server because it is a stateless ` + `environment.`); }, forward() { throw new Error(`You cannot use navigator.forward() on the server because it is a stateless ` + `environment.`); } }; } function createStaticHandler(routes, opts) { return router.createStaticHandler(routes, { ...opts, mapRouteProperties: reactRouter.UNSAFE_mapRouteProperties }); } function createStaticRouter(routes, context, opts = {}) { let manifest = {}; let dataRoutes = router.UNSAFE_convertRoutesToDataRoutes(routes, reactRouter.UNSAFE_mapRouteProperties, undefined, manifest); // Because our context matches may be from a framework-agnostic set of // routes passed to createStaticHandler(), we update them here with our // newly created/enhanced data routes let matches = context.matches.map(match => { let route = manifest[match.route.id] || match.route; return { ...match, route }; }); let msg = method => `You cannot use router.${method}() on the server because it is a stateless environment`; return { get basename() { return context.basename; }, get future() { return { v7_fetcherPersist: false, v7_normalizeFormMethod: false, v7_partialHydration: opts.future?.v7_partialHydration === true, v7_prependBasename: false, v7_relativeSplatPath: opts.future?.v7_relativeSplatPath === true, v7_skipActionErrorRevalidation: false }; }, get state() { return { historyAction: router.Action.Pop, location: context.location, matches, loaderData: context.loaderData, actionData: context.actionData, errors: context.errors, initialized: true, navigation: router.IDLE_NAVIGATION, restoreScrollPosition: null, preventScrollReset: false, revalidation: "idle", fetchers: new Map(), blockers: new Map() }; }, get routes() { return dataRoutes; }, get window() { return undefined; }, initialize() { throw msg("initialize"); }, subscribe() { throw msg("subscribe"); }, enableScrollRestoration() { throw msg("enableScrollRestoration"); }, navigate() { throw msg("navigate"); }, fetch() { throw msg("fetch"); }, revalidate() { throw msg("revalidate"); }, createHref, encodeLocation, getFetcher() { return router.IDLE_FETCHER; }, deleteFetcher() { throw msg("deleteFetcher"); }, dispose() { throw msg("dispose"); }, getBlocker() { return router.IDLE_BLOCKER; }, deleteBlocker() { throw msg("deleteBlocker"); }, patchRoutes() { throw msg("patchRoutes"); }, _internalFetchControllers: new Map(), _internalActiveDeferreds: new Map(), _internalSetRoutes() { throw msg("_internalSetRoutes"); } }; } function createHref(to) { return typeof to === "string" ? to : reactRouterDom.createPath(to); } function encodeLocation(to) { let href = typeof to === "string" ? to : reactRouterDom.createPath(to); // Treating this as a full URL will strip any trailing spaces so we need to // pre-encode them since they might be part of a matching splat param from // an ancestor route href = href.replace(/ $/, "%20"); let encoded = ABSOLUTE_URL_REGEX.test(href) ? new URL(href) : new URL(href, "http://localhost"); return { pathname: encoded.pathname, search: encoded.search, hash: encoded.hash }; } const ABSOLUTE_URL_REGEX = /^(?:[a-z][a-z0-9+.-]*:|\/\/)/i; // This utility is based on https://github.com/zertosh/htmlescape // License: https://github.com/zertosh/htmlescape/blob/0527ca7156a524d256101bb310a9f970f63078ad/LICENSE const ESCAPE_LOOKUP = { "&": "\\u0026", ">": "\\u003e", "<": "\\u003c", "\u2028": "\\u2028", "\u2029": "\\u2029" }; const ESCAPE_REGEX = /[&><\u2028\u2029]/g; function htmlEscape(str) { return str.replace(ESCAPE_REGEX, match => ESCAPE_LOOKUP[match]); } exports.StaticRouter = StaticRouter; exports.StaticRouterProvider = StaticRouterProvider; exports.createStaticHandler = createStaticHandler; exports.createStaticRouter = createStaticRouter;