@rshono/core 1.0.0-rc.23 → 1.0.0-rc.25

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -103,7 +103,9 @@ export default async function Profile({ params, ctx }: PageProps<'/profile/:id'>
103
103
 
104
104
  - Pages receive `{ url, params, ctx }` — `PageProps<'/profile/:id'>` types `params.id`, and `url` is a real
105
105
  `URL`. The same pair reaches a `'use client'` component from `useNavigation()`, so a read moves across the
106
- boundary unchanged.
106
+ boundary unchanged — except the fragment, which a browser never sends to the server: `PageProps.url` never
107
+ has one, while `useNavigation().url.hash` is read from the address bar after hydration and follows in-page
108
+ links and Back/Forward.
107
109
  - **`ctx` is the request context** — `ctx.req`, cookies, env, middleware variables, the proxy-aware URL. It is
108
110
  the same object `getRequestContext()` returns from `@rshono/core/server`, handed over so a page needs no
109
111
  import. Reading it on a `render: 'static'` page throws: a page rendered once at build time has no request.
package/dist/router.d.ts CHANGED
@@ -57,9 +57,11 @@ export interface PageProps<Path extends string = string, E extends Env = Env> {
57
57
  * On a `render: 'static'` route this is the build-time URL — rendered once against `siteUrl`, so the
58
58
  * origin is `siteUrl`'s and `url.searchParams` is always empty, on first paint and after a soft
59
59
  * navigation alike. **`useNavigation().url` is the same frozen URL, not a way around it**: the payload
60
- * carries one `href` and both readings come from it. Mark the route `render: 'dynamic'` if the page
61
- * depends on the query; a `'use client'` component that only wants it after hydration can read
62
- * `location.search` in an effect.
60
+ * carries one `href` and both readings come from it. The fragment is the one part no payload can carry
61
+ * — a browser never sends `#…` with the request — so this prop never has one, while
62
+ * `useNavigation().url.hash` is read from the browser after hydration. Mark the route
63
+ * `render: 'dynamic'` if the page depends on the query; a `'use client'` component that only wants it
64
+ * after hydration can read `location.search` in an effect.
63
65
  */
64
66
  url: URL;
65
67
  /** Matched route params for this request, e.g. `{ id: '42' }` for `/profile/:id`. */
@@ -1 +1 @@
1
- {"version":3,"file":"router.js","sourceRoot":"","sources":["../src/router.ts"],"names":[],"mappings":"AAkQA;;;;;GAKG;AACH,MAAM,UAAU,WAAW,CAAC,KAAY;IACtC,OAAO,KAAK,CAAC,IAAI,KAAK,UAAU,CAAC;AACnC,CAAC;AA6LD,MAAM,UAAU,YAAY,CAAC,KAAqC;IAChE,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC,CAAE,KAAqB,CAAC;AAC3E,CAAC","sourcesContent":["import type { Env, Handler } from 'hono';\nimport type { ParamKeys, ParamKeyToRecord } from 'hono/types';\nimport type { ReactNode } from 'react';\n// Type-only, so importing `@rshono/core` pulls in none of `context.ts`'s runtime machinery.\nimport type { RequestContext } from './runtime/context.js';\n\ntype Simplify<T> = { [K in keyof T]: T[K] } & {};\ntype UnionToIntersection<U> = (U extends unknown ? (k: U) => void : never) extends (k: infer I) => void ? I : never;\n\n/**\n * The `params` record implied by a route path pattern — one required `string` key per `:param`\n * segment, `Record<string, never>` for a path with none. Paths use Hono's syntax, so `:id`,\n * `:id{[0-9]+}` and `*` all work.\n *\n * You rarely name this directly; {@link PageProps} applies it for you.\n *\n * @typeParam P - The literal route path, e.g. `'/users/:id/posts/:postId'`.\n *\n * @example\n * ```ts\n * type P = PathParams<'/users/:id/posts/:postId'>; // { id: string; postId: string }\n * ```\n *\n * @see {@link https://hono.dev/docs/api/routing#path-parameter | Hono — path parameters}\n */\nexport type PathParams<P extends string> =\n ParamKeys<P> extends never ? Record<string, never> : Simplify<UnionToIntersection<ParamKeyToRecord<ParamKeys<P>>>>;\n\n/**\n * Props every page component receives. Pass the route's path as the type argument to get `params`\n * typed key-by-key; without it `params` falls back to an open `Record<string, string>`.\n *\n * `defineRoutes` checks each page's props against `PageProps<path>`, so a mismatched path literal is\n * a type error at the route definition. `url` and `params` mirror what `useNavigation()` gives a\n * `'use client'` component, so a read moves across the server/client line unchanged.\n *\n * @typeParam Path - The literal path this page is mounted at, e.g. `'/profile/:id'`.\n * @typeParam E - The app's Hono {@link Env}, to type {@link RequestContext.var} and\n * {@link RequestContext.env} on {@link PageProps.ctx}.\n *\n * @example\n * ```tsx\n * import type { PageProps } from '@rshono/core';\n *\n * export default async function Profile({ params, url }: PageProps<'/profile/:id'>) {\n * const user = await db.getUser(params.id); // params.id is string\n * const tab = url.searchParams.get('tab') ?? 'overview';\n * return <Layout>{user.name} — {tab}</Layout>;\n * }\n * ```\n *\n * @see {@link https://www.rshono.com/docs/pages#page-props | Docs — page props}\n */\nexport interface PageProps<Path extends string = string, E extends Env = Env> {\n /**\n * The absolute browser-facing request {@link URL}, proxy-header aware (`X-Forwarded-Host` /\n * `-Proto`). A fresh instance per request, so mutating it is local to the page; it is not\n * serializable, so hand a `'use client'` component `url.href` rather than `url`.\n *\n * On a `render: 'static'` route this is the build-time URL — rendered once against `siteUrl`, so the\n * origin is `siteUrl`'s and `url.searchParams` is always empty, on first paint and after a soft\n * navigation alike. **`useNavigation().url` is the same frozen URL, not a way around it**: the payload\n * carries one `href` and both readings come from it. Mark the route `render: 'dynamic'` if the page\n * depends on the query; a `'use client'` component that only wants it after hydration can read\n * `location.search` in an effect.\n */\n url: URL;\n /** Matched route params for this request, e.g. `{ id: '42' }` for `/profile/:id`. */\n params: string extends Path ? Record<string, string> : PathParams<Path>;\n /**\n * The request context — the object `getRequestContext()` returns, handed to the page so cookies,\n * headers, env and middleware variables are reachable without an import.\n *\n * Server-only, non-enumerable (a `{...props}` spread and `JSON.stringify` both skip it) and never\n * serialized. Passing it to a `'use client'` component fails the render, because it wraps the live\n * request — read what you need here and pass plain values down.\n *\n * Non-enumerable is the one place this API breaks a JavaScript expectation, and it is unavoidable: an\n * enumerable `ctx` would put `ctx.hono.env` — every binding and secret — into React's dev-only\n * serialization of a server component's props, which walks own enumerable properties. So `<Child\n * {...props} />` hands a **server** child `ctx: undefined` with no error, while the type says otherwise.\n * Nested server components are meant to call `getRequestContext()` for the same object rather than\n * receive it, which is also the fix if a spread has already cost you an afternoon.\n *\n * Reading it on a `render: 'static'` route throws: a prerendered page has no per-request context.\n * Mark the route `render: 'dynamic'`, or use the `url` / `params` props.\n *\n * @example\n * ```tsx\n * export default function Dashboard({ ctx }: PageProps) {\n * const session = ctx.cookies.get('session');\n * if (!session) redirect('/login');\n * return <Layout>Signed in as {session}</Layout>;\n * }\n * ```\n */\n ctx: RequestContext<E>;\n}\n\n/**\n * A page: a React **server component** rendering the entire document (`<html>…</html>`), usually via\n * a shared layout. It may be `async` and await data directly.\n *\n * Each page module default-exports exactly one. Interactive parts belong in `'use client'` components\n * the page imports — only those ship JS.\n *\n * @typeParam P - The component's props; for a page these are {@link PageProps}.\n *\n * @see {@link https://react.dev/reference/rsc/server-components | React — Server Components}\n * @see {@link https://www.rshono.com/docs/pages | Docs — pages}\n */\n// `any`, not `unknown`: this default is what an unparameterised `PageComponent` means in a user's own\n// annotation, and `unknown` props would reject every component that declares the props it actually takes.\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type PageComponent<P = any> = (props: P) => ReactNode | Promise<ReactNode>;\n\n/**\n * The shape an `{ type: 'endpoint' }` route's server module must have: a single named `handler`\n * export. It only ever loads on the server, so importing a database client or reading secrets from it\n * is safe.\n *\n * @example\n * ```ts\n * // src/health.ts\n * import type { Handler } from 'hono';\n *\n * export const handler: Handler = (c) => c.json({ ok: true });\n * ```\n *\n * @see {@link https://www.rshono.com/docs/routing#endpoint-routes | Docs — endpoint routes}\n */\nexport interface EndpointServerModule {\n /**\n * A Hono {@link Handler} for every request the route matches. It is passed Hono's `Context`, so the\n * request, the response builders (`c.json`, `c.text`, `c.body`) and middleware variables are all\n * reached through it.\n *\n * @see {@link https://hono.dev/docs/api/context | Hono — Context}\n */\n handler: Handler;\n}\n\n/**\n * A page route — a path rendered by a server component. This is the default\n * route kind, so `type` can be omitted.\n *\n * @example\n * ```ts\n * { path: '/profile/:id', component: () => import('./components/profile') }\n * ```\n */\nexport interface PageRoute {\n /** Discriminates a page from an endpoint; optional because `'page'` is the default. */\n type?: 'page';\n /**\n * Hono-style path pattern, e.g. `/`, `/profile/:id`, `/files/*`. Routes are matched in\n * declaration order.\n *\n * @see {@link https://hono.dev/docs/api/routing | Hono — routing}\n */\n path: string;\n /**\n * Dynamic import of the page module, whose default export is the {@link PageComponent}.\n *\n * Write it inline as `() => import('…')`: the framework detects that exact form and injects the\n * `'use server-entry'` directive that attaches the page's client JS and CSS. Wire the component up\n * any other way — a variable, a barrel re-export, a computed specifier — and you have to put\n * `'use server-entry'` on the page module's first line yourself.\n *\n * @example\n * ```ts\n * component: () => import('./components/profile')\n * ```\n *\n * @see {@link https://www.rshono.com/docs/pages#the-use-server-entry-directive | Docs — the `'use server-entry'` directive}\n */\n component: () => Promise<{ default: PageComponent }>;\n /** `'static'` prerenders the route at build time; `'dynamic'` (the default) renders per request. */\n render?: 'static' | 'dynamic';\n /**\n * For a `render: 'static'` route with params: the param sets to prerender, one page each. Runs at\n * build time on the server, so it may hit a database or read the filesystem.\n *\n * A parameterised static route without this falls back to rendering per request, with a build\n * warning. Wildcard (`*`), optional and regex params cannot be prerendered.\n *\n * **Every value has to be one portable file name**, since that is what a prerendered page is stored as,\n * and the build fails naming the value rather than writing a page nothing will serve. So: no\n * `\\ / : * ? \" < > |` or control characters, no trailing `.` or space, and not a reserved Windows device\n * name (`CON`, `NUL`, `COM1`, …) — the last two enforced everywhere, so a build that works on macOS is\n * not one that fails in CI on Windows.\n *\n * @example\n * ```ts\n * {\n * path: '/docs/:slug',\n * render: 'static',\n * component: () => import('./components/documentation'),\n * staticPaths: async () => (await db.docs.all()).map((d) => ({ slug: d.slug })),\n * }\n * ```\n *\n * @see {@link https://www.rshono.com/docs/routing#static-rendering | Docs — static rendering}\n */\n staticPaths?: () => Array<Record<string, string>> | Promise<Array<Record<string, string>>>;\n}\n\n/**\n * An endpoint route — a path served by a raw Hono handler instead of a React\n * component. Use it for JSON APIs, webhooks, redirects, feeds, or anything that\n * isn't an HTML page.\n *\n * @example\n * ```ts\n * { type: 'endpoint', path: '/api/health', server: () => import('./health') }\n * ```\n *\n * @see {@link https://www.rshono.com/docs/routing#endpoint-routes | Docs — endpoint routes}\n */\nexport interface EndpointRoute {\n /** Marks this route as an endpoint rather than a page. Required. */\n type: 'endpoint';\n /**\n * Hono-style path pattern, e.g. `/api/health`, `/api/users/:id`.\n *\n * @see {@link https://hono.dev/docs/api/routing | Hono — routing}\n */\n path: string;\n /**\n * HTTP method to match, or a list of them. Defaults to `'all'` — every method.\n *\n * There is no `'head'`: Hono dispatches a `HEAD` as a `GET` and strips the body off the response, so a\n * `HEAD` is already answered by the `'get'` handler (and by `'all'`), and a route registered for `HEAD`\n * alone would never be reached.\n *\n * A list is how a two-method endpoint says so; `'all'` inside one is refused, since it is either the\n * whole thing or a mistake. A method the route does not name gets Hono's 404 rather than the handler.\n *\n * @example\n * ```ts\n * { type: 'endpoint', path: '/api/session', method: ['get', 'delete'], server: () => import('./session') }\n * ```\n */\n method?: HTTPMethod | readonly HTTPMethod[];\n /** Dynamic import of the {@link EndpointServerModule} exporting `handler`. */\n server: () => Promise<EndpointServerModule>;\n}\n\n/**\n * HTTP methods an {@link EndpointRoute} can match. `'all'` matches every method.\n *\n * No `'head'`, deliberately — see {@link EndpointRoute.method}. A `HEAD` reaches the `'get'` handler.\n */\nexport type HTTPMethod = 'get' | 'post' | 'put' | 'patch' | 'delete' | 'options' | 'all';\n\n/** Any entry in the `routes` array: a {@link PageRoute} or an {@link EndpointRoute}. */\nexport type Route = PageRoute | EndpointRoute;\n\n/**\n * Narrows a {@link Route} to a {@link PageRoute} — `type` is optional on page routes, so anything not\n * explicitly `'endpoint'` is one.\n *\n * @internal\n */\nexport function isPageRoute(route: Route): route is PageRoute {\n return route.type !== 'endpoint';\n}\n\n/**\n * A page the framework falls back to rather than routes to — `notFound` and `error` in\n * {@link RouteConfig}. Same contract as a {@link PageRoute} `component`, without a path of its own.\n */\nexport interface FallbackPage {\n /** Dynamic import of the page module; its default export is the {@link PageComponent}. */\n component: () => Promise<{ default: PageComponent }>;\n}\n\n/**\n * The error detail handed to the `error` page. Redacted in production — a generic\n * `'Internal Server Error'` and no `stack`; in dev, the real message and stack.\n */\nexport interface ErrorPageInfo {\n /** The thrown error's message in dev; `'Internal Server Error'` in production. */\n message: string;\n /**\n * The stack trace — **dev only**, and `undefined` in every build. Optional for that reason rather than\n * because some errors lack one, so a page that renders it should guard on it, not on a mode flag.\n */\n stack?: string;\n}\n\n/**\n * Props for the `error` page declared in {@link RouteConfig.error} — the usual {@link PageProps} plus\n * the redaction-aware {@link ErrorPageInfo}.\n *\n * In a build `error.message` is the generic `'Internal Server Error'` and `error.stack` is `undefined`, so\n * the page below guards on the stack rather than on a mode flag — there is no mode flag to guard on.\n *\n * @typeParam E - The app's Hono {@link Env}, forwarded to {@link PageProps.ctx}.\n *\n * @example\n * ```tsx\n * import type { ErrorPageProps } from '@rshono/core';\n *\n * export default function ServerError({ error }: ErrorPageProps) {\n * return (\n * <html>\n * <body>\n * <h1>Something went wrong</h1>\n * <p>{error.message}</p>\n * {error.stack && <pre>{error.stack}</pre>}\n * </body>\n * </html>\n * );\n * }\n * ```\n */\nexport type ErrorPageProps<E extends Env = Env> = PageProps<string, E> & {\n /** The error that failed the request, redacted in production — see {@link ErrorPageInfo}. */\n error: ErrorPageInfo;\n};\n\n/**\n * The object form accepted by {@link defineRoutes}: the route table plus the two\n * optional framework-owned pages.\n *\n * @typeParam TRoutes - Inferred tuple of route literals, which is what makes the\n * per-route `path` → props check possible.\n *\n * @see {@link https://www.rshono.com/docs/routing#notfound-and-error | Docs — notFound and error pages}\n */\nexport interface RouteConfig<TRoutes extends readonly Route[] = readonly Route[]> {\n /** Every page and endpoint in the app, matched in order. */\n routes: TRoutes;\n /** Page rendered with a 404 status for unmatched paths and for `notFound()` calls. */\n notFound?: FallbackPage;\n /**\n * Page rendered with a 500 status when a request throws — a page component, a page module that will not\n * load, an endpoint, a server action, or middleware. Receives {@link ErrorPageProps}.\n *\n * It is a *fresh* render, with its own flight payload, so it hydrates and behaves like any other page.\n * An app that declares none gets the framework's plain 500 document instead. If the `error` page itself\n * throws, that is reported too and the framework's document answers.\n */\n error?: FallbackPage;\n}\n\n/**\n * The same check for `staticPaths`, whose param sets have to fill the route's own path: a key that does not\n * is otherwise a build-time throw from `interpolatePath` rather than a type error.\n *\n * Keys only, not full assignability, because the declared field type is `Record<string, string>` and a\n * `staticPaths` annotated as returning exactly that has to stay accepted — an index signature carries no\n * key to check, so it passes. Skipped where the path has no params, because `staticPaths` is not called for\n * such a route at all and an error there would be about the wrong thing.\n */\ntype ValidateStaticPaths<R, P extends string> =\n ParamKeys<P> extends never\n ? R\n : R extends { staticPaths: () => infer Sets }\n ? Awaited<Sets> extends ReadonlyArray<infer Set>\n ? [keyof PathParams<P>] extends [keyof Set]\n ? R\n : R & { staticPaths: `every param set staticPaths returns needs the params of '${P}'` }\n : R\n : R;\n\n// `PageProps<P, any>`, not `PageProps<P>`: only the *path* is being checked, and pinning the Env would\n// fail every page that declares its own (`PageProps<'/x', MyEnv>`, to type `ctx.var`).\ntype ValidateRoute<R> = R extends {\n path: infer P extends string;\n component: () => Promise<{ default: PageComponent<infer CP> }>;\n}\n ? // eslint-disable-next-line @typescript-eslint/no-explicit-any -- the Env is deliberately unpinned; see above.\n [PageProps<P, any>] extends [CP]\n ? ValidateStaticPaths<R, P>\n : R & { component: `component props are not satisfied by PageProps<'${P}'>` }\n : R;\n\ntype ValidateRoutes<TRoutes extends readonly Route[]> = { [K in keyof TRoutes]: ValidateRoute<TRoutes[K]> };\n\n/**\n * Refuses a key that is not a {@link RouteConfig} field — a typo'd `notfound` is otherwise a fallback page\n * that never renders, and nothing at runtime looks for one.\n *\n * Excess-property checking did this while the object form was an overload of its own with a concrete\n * parameter type. It cannot once the parameter is generic and inferred from the argument, because the\n * inferred type *has* the extra key. The message here is the better one anyway: it lands on the field.\n */\ntype ValidateConfigKeys<T> =\n Exclude<keyof T, keyof RouteConfig> extends never\n ? T\n : T & Record<Exclude<keyof T, keyof RouteConfig>, 'not a defineRoutes field — the fields are routes, notFound and error'>;\n\n/** The check for whichever of the two accepted shapes was passed. */\ntype ValidateInput<T> = T extends readonly Route[]\n ? ValidateRoutes<T>\n : T extends { routes: infer R extends readonly Route[] }\n ? ValidateConfigKeys<T> & { routes: ValidateRoutes<R> }\n : T;\n\n/** The route tuple inside either shape, so the return type carries the literals through both. */\ntype RoutesOf<T> = T extends readonly Route[] ? T : T extends { routes: infer R extends readonly Route[] } ? R : readonly Route[];\n\n/**\n * Declares the app's route table. Export the result as `routes` from `src/routes.ts` — the one file\n * rshono requires. It only ever runs on the server, so importing server-only modules from it (inside\n * `staticPaths`, say) is safe.\n *\n * Takes a {@link RouteConfig} — the `routes` array plus the optional `notFound` and `error` pages — or a\n * bare {@link Route} array as shorthand for an app with neither.\n *\n * Beyond typing the config, every page is cross-checked against its own path: props not satisfied by\n * `PageProps<'<its path>'>` make the `component` field a type error, and a `staticPaths` whose param sets do\n * not fill the path makes that field one.\n *\n * **One signature over both shapes, deliberately.** The array form used to be a second overload, which meant\n * a mistake inside a bare array was reported as an overload-resolution failure whose *first* line was the\n * object form's complaint — \"Property 'routes' is missing\" — pointing at a change the author should not make.\n * The real message was on line 8. A single signature reports the argument once, at the field that is wrong.\n *\n * @param input - A {@link RouteConfig}, or the bare `routes` array.\n * @returns The config, unchanged and fully typed; an array is wrapped as `{ routes }`.\n *\n * @example\n * ```ts\n * // src/routes.ts\n * import { defineRoutes } from '@rshono/core';\n *\n * export const routes = defineRoutes({\n * routes: [\n * { path: '/', component: () => import('./components/home') },\n * { path: '/profile/:id', component: () => import('./components/profile') },\n * {\n * path: '/docs/:slug',\n * render: 'static',\n * component: () => import('./components/documentation'),\n * staticPaths: async () => [{ slug: 'getting-started' }, { slug: 'deployment' }],\n * },\n * { type: 'endpoint', path: '/api/health', server: () => import('./health') },\n * ],\n * notFound: { component: () => import('./components/404') },\n * error: { component: () => import('./components/500') },\n * });\n * ```\n *\n * @example\n * ```ts\n * // The shorthand, for an app with no notFound or error page.\n * export const routes = defineRoutes([{ path: '/', component: () => import('./components/home') }]);\n * ```\n *\n * @see {@link https://www.rshono.com/docs/routing | Docs — routing}\n */\nexport function defineRoutes<const T extends readonly Route[] | RouteConfig<readonly Route[]>>(input: T & ValidateInput<T>): RouteConfig<RoutesOf<T>>;\nexport function defineRoutes(input: readonly Route[] | RouteConfig): RouteConfig {\n return Array.isArray(input) ? { routes: input } : (input as RouteConfig);\n}\n"]}
1
+ {"version":3,"file":"router.js","sourceRoot":"","sources":["../src/router.ts"],"names":[],"mappings":"AAoQA;;;;;GAKG;AACH,MAAM,UAAU,WAAW,CAAC,KAAY;IACtC,OAAO,KAAK,CAAC,IAAI,KAAK,UAAU,CAAC;AACnC,CAAC;AA6LD,MAAM,UAAU,YAAY,CAAC,KAAqC;IAChE,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC,CAAE,KAAqB,CAAC;AAC3E,CAAC","sourcesContent":["import type { Env, Handler } from 'hono';\nimport type { ParamKeys, ParamKeyToRecord } from 'hono/types';\nimport type { ReactNode } from 'react';\n// Type-only, so importing `@rshono/core` pulls in none of `context.ts`'s runtime machinery.\nimport type { RequestContext } from './runtime/context.js';\n\ntype Simplify<T> = { [K in keyof T]: T[K] } & {};\ntype UnionToIntersection<U> = (U extends unknown ? (k: U) => void : never) extends (k: infer I) => void ? I : never;\n\n/**\n * The `params` record implied by a route path pattern — one required `string` key per `:param`\n * segment, `Record<string, never>` for a path with none. Paths use Hono's syntax, so `:id`,\n * `:id{[0-9]+}` and `*` all work.\n *\n * You rarely name this directly; {@link PageProps} applies it for you.\n *\n * @typeParam P - The literal route path, e.g. `'/users/:id/posts/:postId'`.\n *\n * @example\n * ```ts\n * type P = PathParams<'/users/:id/posts/:postId'>; // { id: string; postId: string }\n * ```\n *\n * @see {@link https://hono.dev/docs/api/routing#path-parameter | Hono — path parameters}\n */\nexport type PathParams<P extends string> =\n ParamKeys<P> extends never ? Record<string, never> : Simplify<UnionToIntersection<ParamKeyToRecord<ParamKeys<P>>>>;\n\n/**\n * Props every page component receives. Pass the route's path as the type argument to get `params`\n * typed key-by-key; without it `params` falls back to an open `Record<string, string>`.\n *\n * `defineRoutes` checks each page's props against `PageProps<path>`, so a mismatched path literal is\n * a type error at the route definition. `url` and `params` mirror what `useNavigation()` gives a\n * `'use client'` component, so a read moves across the server/client line unchanged.\n *\n * @typeParam Path - The literal path this page is mounted at, e.g. `'/profile/:id'`.\n * @typeParam E - The app's Hono {@link Env}, to type {@link RequestContext.var} and\n * {@link RequestContext.env} on {@link PageProps.ctx}.\n *\n * @example\n * ```tsx\n * import type { PageProps } from '@rshono/core';\n *\n * export default async function Profile({ params, url }: PageProps<'/profile/:id'>) {\n * const user = await db.getUser(params.id); // params.id is string\n * const tab = url.searchParams.get('tab') ?? 'overview';\n * return <Layout>{user.name} — {tab}</Layout>;\n * }\n * ```\n *\n * @see {@link https://www.rshono.com/docs/pages#page-props | Docs — page props}\n */\nexport interface PageProps<Path extends string = string, E extends Env = Env> {\n /**\n * The absolute browser-facing request {@link URL}, proxy-header aware (`X-Forwarded-Host` /\n * `-Proto`). A fresh instance per request, so mutating it is local to the page; it is not\n * serializable, so hand a `'use client'` component `url.href` rather than `url`.\n *\n * On a `render: 'static'` route this is the build-time URL — rendered once against `siteUrl`, so the\n * origin is `siteUrl`'s and `url.searchParams` is always empty, on first paint and after a soft\n * navigation alike. **`useNavigation().url` is the same frozen URL, not a way around it**: the payload\n * carries one `href` and both readings come from it. The fragment is the one part no payload can carry\n * — a browser never sends `#…` with the request — so this prop never has one, while\n * `useNavigation().url.hash` is read from the browser after hydration. Mark the route\n * `render: 'dynamic'` if the page depends on the query; a `'use client'` component that only wants it\n * after hydration can read `location.search` in an effect.\n */\n url: URL;\n /** Matched route params for this request, e.g. `{ id: '42' }` for `/profile/:id`. */\n params: string extends Path ? Record<string, string> : PathParams<Path>;\n /**\n * The request context — the object `getRequestContext()` returns, handed to the page so cookies,\n * headers, env and middleware variables are reachable without an import.\n *\n * Server-only, non-enumerable (a `{...props}` spread and `JSON.stringify` both skip it) and never\n * serialized. Passing it to a `'use client'` component fails the render, because it wraps the live\n * request — read what you need here and pass plain values down.\n *\n * Non-enumerable is the one place this API breaks a JavaScript expectation, and it is unavoidable: an\n * enumerable `ctx` would put `ctx.hono.env` — every binding and secret — into React's dev-only\n * serialization of a server component's props, which walks own enumerable properties. So `<Child\n * {...props} />` hands a **server** child `ctx: undefined` with no error, while the type says otherwise.\n * Nested server components are meant to call `getRequestContext()` for the same object rather than\n * receive it, which is also the fix if a spread has already cost you an afternoon.\n *\n * Reading it on a `render: 'static'` route throws: a prerendered page has no per-request context.\n * Mark the route `render: 'dynamic'`, or use the `url` / `params` props.\n *\n * @example\n * ```tsx\n * export default function Dashboard({ ctx }: PageProps) {\n * const session = ctx.cookies.get('session');\n * if (!session) redirect('/login');\n * return <Layout>Signed in as {session}</Layout>;\n * }\n * ```\n */\n ctx: RequestContext<E>;\n}\n\n/**\n * A page: a React **server component** rendering the entire document (`<html>…</html>`), usually via\n * a shared layout. It may be `async` and await data directly.\n *\n * Each page module default-exports exactly one. Interactive parts belong in `'use client'` components\n * the page imports — only those ship JS.\n *\n * @typeParam P - The component's props; for a page these are {@link PageProps}.\n *\n * @see {@link https://react.dev/reference/rsc/server-components | React — Server Components}\n * @see {@link https://www.rshono.com/docs/pages | Docs — pages}\n */\n// `any`, not `unknown`: this default is what an unparameterised `PageComponent` means in a user's own\n// annotation, and `unknown` props would reject every component that declares the props it actually takes.\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type PageComponent<P = any> = (props: P) => ReactNode | Promise<ReactNode>;\n\n/**\n * The shape an `{ type: 'endpoint' }` route's server module must have: a single named `handler`\n * export. It only ever loads on the server, so importing a database client or reading secrets from it\n * is safe.\n *\n * @example\n * ```ts\n * // src/health.ts\n * import type { Handler } from 'hono';\n *\n * export const handler: Handler = (c) => c.json({ ok: true });\n * ```\n *\n * @see {@link https://www.rshono.com/docs/routing#endpoint-routes | Docs — endpoint routes}\n */\nexport interface EndpointServerModule {\n /**\n * A Hono {@link Handler} for every request the route matches. It is passed Hono's `Context`, so the\n * request, the response builders (`c.json`, `c.text`, `c.body`) and middleware variables are all\n * reached through it.\n *\n * @see {@link https://hono.dev/docs/api/context | Hono — Context}\n */\n handler: Handler;\n}\n\n/**\n * A page route — a path rendered by a server component. This is the default\n * route kind, so `type` can be omitted.\n *\n * @example\n * ```ts\n * { path: '/profile/:id', component: () => import('./components/profile') }\n * ```\n */\nexport interface PageRoute {\n /** Discriminates a page from an endpoint; optional because `'page'` is the default. */\n type?: 'page';\n /**\n * Hono-style path pattern, e.g. `/`, `/profile/:id`, `/files/*`. Routes are matched in\n * declaration order.\n *\n * @see {@link https://hono.dev/docs/api/routing | Hono — routing}\n */\n path: string;\n /**\n * Dynamic import of the page module, whose default export is the {@link PageComponent}.\n *\n * Write it inline as `() => import('…')`: the framework detects that exact form and injects the\n * `'use server-entry'` directive that attaches the page's client JS and CSS. Wire the component up\n * any other way — a variable, a barrel re-export, a computed specifier — and you have to put\n * `'use server-entry'` on the page module's first line yourself.\n *\n * @example\n * ```ts\n * component: () => import('./components/profile')\n * ```\n *\n * @see {@link https://www.rshono.com/docs/pages#the-use-server-entry-directive | Docs — the `'use server-entry'` directive}\n */\n component: () => Promise<{ default: PageComponent }>;\n /** `'static'` prerenders the route at build time; `'dynamic'` (the default) renders per request. */\n render?: 'static' | 'dynamic';\n /**\n * For a `render: 'static'` route with params: the param sets to prerender, one page each. Runs at\n * build time on the server, so it may hit a database or read the filesystem.\n *\n * A parameterised static route without this falls back to rendering per request, with a build\n * warning. Wildcard (`*`), optional and regex params cannot be prerendered.\n *\n * **Every value has to be one portable file name**, since that is what a prerendered page is stored as,\n * and the build fails naming the value rather than writing a page nothing will serve. So: no\n * `\\ / : * ? \" < > |` or control characters, no trailing `.` or space, and not a reserved Windows device\n * name (`CON`, `NUL`, `COM1`, …) — the last two enforced everywhere, so a build that works on macOS is\n * not one that fails in CI on Windows.\n *\n * @example\n * ```ts\n * {\n * path: '/docs/:slug',\n * render: 'static',\n * component: () => import('./components/documentation'),\n * staticPaths: async () => (await db.docs.all()).map((d) => ({ slug: d.slug })),\n * }\n * ```\n *\n * @see {@link https://www.rshono.com/docs/routing#static-rendering | Docs — static rendering}\n */\n staticPaths?: () => Array<Record<string, string>> | Promise<Array<Record<string, string>>>;\n}\n\n/**\n * An endpoint route — a path served by a raw Hono handler instead of a React\n * component. Use it for JSON APIs, webhooks, redirects, feeds, or anything that\n * isn't an HTML page.\n *\n * @example\n * ```ts\n * { type: 'endpoint', path: '/api/health', server: () => import('./health') }\n * ```\n *\n * @see {@link https://www.rshono.com/docs/routing#endpoint-routes | Docs — endpoint routes}\n */\nexport interface EndpointRoute {\n /** Marks this route as an endpoint rather than a page. Required. */\n type: 'endpoint';\n /**\n * Hono-style path pattern, e.g. `/api/health`, `/api/users/:id`.\n *\n * @see {@link https://hono.dev/docs/api/routing | Hono — routing}\n */\n path: string;\n /**\n * HTTP method to match, or a list of them. Defaults to `'all'` — every method.\n *\n * There is no `'head'`: Hono dispatches a `HEAD` as a `GET` and strips the body off the response, so a\n * `HEAD` is already answered by the `'get'` handler (and by `'all'`), and a route registered for `HEAD`\n * alone would never be reached.\n *\n * A list is how a two-method endpoint says so; `'all'` inside one is refused, since it is either the\n * whole thing or a mistake. A method the route does not name gets Hono's 404 rather than the handler.\n *\n * @example\n * ```ts\n * { type: 'endpoint', path: '/api/session', method: ['get', 'delete'], server: () => import('./session') }\n * ```\n */\n method?: HTTPMethod | readonly HTTPMethod[];\n /** Dynamic import of the {@link EndpointServerModule} exporting `handler`. */\n server: () => Promise<EndpointServerModule>;\n}\n\n/**\n * HTTP methods an {@link EndpointRoute} can match. `'all'` matches every method.\n *\n * No `'head'`, deliberately — see {@link EndpointRoute.method}. A `HEAD` reaches the `'get'` handler.\n */\nexport type HTTPMethod = 'get' | 'post' | 'put' | 'patch' | 'delete' | 'options' | 'all';\n\n/** Any entry in the `routes` array: a {@link PageRoute} or an {@link EndpointRoute}. */\nexport type Route = PageRoute | EndpointRoute;\n\n/**\n * Narrows a {@link Route} to a {@link PageRoute} — `type` is optional on page routes, so anything not\n * explicitly `'endpoint'` is one.\n *\n * @internal\n */\nexport function isPageRoute(route: Route): route is PageRoute {\n return route.type !== 'endpoint';\n}\n\n/**\n * A page the framework falls back to rather than routes to — `notFound` and `error` in\n * {@link RouteConfig}. Same contract as a {@link PageRoute} `component`, without a path of its own.\n */\nexport interface FallbackPage {\n /** Dynamic import of the page module; its default export is the {@link PageComponent}. */\n component: () => Promise<{ default: PageComponent }>;\n}\n\n/**\n * The error detail handed to the `error` page. Redacted in production — a generic\n * `'Internal Server Error'` and no `stack`; in dev, the real message and stack.\n */\nexport interface ErrorPageInfo {\n /** The thrown error's message in dev; `'Internal Server Error'` in production. */\n message: string;\n /**\n * The stack trace — **dev only**, and `undefined` in every build. Optional for that reason rather than\n * because some errors lack one, so a page that renders it should guard on it, not on a mode flag.\n */\n stack?: string;\n}\n\n/**\n * Props for the `error` page declared in {@link RouteConfig.error} — the usual {@link PageProps} plus\n * the redaction-aware {@link ErrorPageInfo}.\n *\n * In a build `error.message` is the generic `'Internal Server Error'` and `error.stack` is `undefined`, so\n * the page below guards on the stack rather than on a mode flag — there is no mode flag to guard on.\n *\n * @typeParam E - The app's Hono {@link Env}, forwarded to {@link PageProps.ctx}.\n *\n * @example\n * ```tsx\n * import type { ErrorPageProps } from '@rshono/core';\n *\n * export default function ServerError({ error }: ErrorPageProps) {\n * return (\n * <html>\n * <body>\n * <h1>Something went wrong</h1>\n * <p>{error.message}</p>\n * {error.stack && <pre>{error.stack}</pre>}\n * </body>\n * </html>\n * );\n * }\n * ```\n */\nexport type ErrorPageProps<E extends Env = Env> = PageProps<string, E> & {\n /** The error that failed the request, redacted in production — see {@link ErrorPageInfo}. */\n error: ErrorPageInfo;\n};\n\n/**\n * The object form accepted by {@link defineRoutes}: the route table plus the two\n * optional framework-owned pages.\n *\n * @typeParam TRoutes - Inferred tuple of route literals, which is what makes the\n * per-route `path` → props check possible.\n *\n * @see {@link https://www.rshono.com/docs/routing#notfound-and-error | Docs — notFound and error pages}\n */\nexport interface RouteConfig<TRoutes extends readonly Route[] = readonly Route[]> {\n /** Every page and endpoint in the app, matched in order. */\n routes: TRoutes;\n /** Page rendered with a 404 status for unmatched paths and for `notFound()` calls. */\n notFound?: FallbackPage;\n /**\n * Page rendered with a 500 status when a request throws — a page component, a page module that will not\n * load, an endpoint, a server action, or middleware. Receives {@link ErrorPageProps}.\n *\n * It is a *fresh* render, with its own flight payload, so it hydrates and behaves like any other page.\n * An app that declares none gets the framework's plain 500 document instead. If the `error` page itself\n * throws, that is reported too and the framework's document answers.\n */\n error?: FallbackPage;\n}\n\n/**\n * The same check for `staticPaths`, whose param sets have to fill the route's own path: a key that does not\n * is otherwise a build-time throw from `interpolatePath` rather than a type error.\n *\n * Keys only, not full assignability, because the declared field type is `Record<string, string>` and a\n * `staticPaths` annotated as returning exactly that has to stay accepted — an index signature carries no\n * key to check, so it passes. Skipped where the path has no params, because `staticPaths` is not called for\n * such a route at all and an error there would be about the wrong thing.\n */\ntype ValidateStaticPaths<R, P extends string> =\n ParamKeys<P> extends never\n ? R\n : R extends { staticPaths: () => infer Sets }\n ? Awaited<Sets> extends ReadonlyArray<infer Set>\n ? [keyof PathParams<P>] extends [keyof Set]\n ? R\n : R & { staticPaths: `every param set staticPaths returns needs the params of '${P}'` }\n : R\n : R;\n\n// `PageProps<P, any>`, not `PageProps<P>`: only the *path* is being checked, and pinning the Env would\n// fail every page that declares its own (`PageProps<'/x', MyEnv>`, to type `ctx.var`).\ntype ValidateRoute<R> = R extends {\n path: infer P extends string;\n component: () => Promise<{ default: PageComponent<infer CP> }>;\n}\n ? // eslint-disable-next-line @typescript-eslint/no-explicit-any -- the Env is deliberately unpinned; see above.\n [PageProps<P, any>] extends [CP]\n ? ValidateStaticPaths<R, P>\n : R & { component: `component props are not satisfied by PageProps<'${P}'>` }\n : R;\n\ntype ValidateRoutes<TRoutes extends readonly Route[]> = { [K in keyof TRoutes]: ValidateRoute<TRoutes[K]> };\n\n/**\n * Refuses a key that is not a {@link RouteConfig} field — a typo'd `notfound` is otherwise a fallback page\n * that never renders, and nothing at runtime looks for one.\n *\n * Excess-property checking did this while the object form was an overload of its own with a concrete\n * parameter type. It cannot once the parameter is generic and inferred from the argument, because the\n * inferred type *has* the extra key. The message here is the better one anyway: it lands on the field.\n */\ntype ValidateConfigKeys<T> =\n Exclude<keyof T, keyof RouteConfig> extends never\n ? T\n : T & Record<Exclude<keyof T, keyof RouteConfig>, 'not a defineRoutes field — the fields are routes, notFound and error'>;\n\n/** The check for whichever of the two accepted shapes was passed. */\ntype ValidateInput<T> = T extends readonly Route[]\n ? ValidateRoutes<T>\n : T extends { routes: infer R extends readonly Route[] }\n ? ValidateConfigKeys<T> & { routes: ValidateRoutes<R> }\n : T;\n\n/** The route tuple inside either shape, so the return type carries the literals through both. */\ntype RoutesOf<T> = T extends readonly Route[] ? T : T extends { routes: infer R extends readonly Route[] } ? R : readonly Route[];\n\n/**\n * Declares the app's route table. Export the result as `routes` from `src/routes.ts` — the one file\n * rshono requires. It only ever runs on the server, so importing server-only modules from it (inside\n * `staticPaths`, say) is safe.\n *\n * Takes a {@link RouteConfig} — the `routes` array plus the optional `notFound` and `error` pages — or a\n * bare {@link Route} array as shorthand for an app with neither.\n *\n * Beyond typing the config, every page is cross-checked against its own path: props not satisfied by\n * `PageProps<'<its path>'>` make the `component` field a type error, and a `staticPaths` whose param sets do\n * not fill the path makes that field one.\n *\n * **One signature over both shapes, deliberately.** The array form used to be a second overload, which meant\n * a mistake inside a bare array was reported as an overload-resolution failure whose *first* line was the\n * object form's complaint — \"Property 'routes' is missing\" — pointing at a change the author should not make.\n * The real message was on line 8. A single signature reports the argument once, at the field that is wrong.\n *\n * @param input - A {@link RouteConfig}, or the bare `routes` array.\n * @returns The config, unchanged and fully typed; an array is wrapped as `{ routes }`.\n *\n * @example\n * ```ts\n * // src/routes.ts\n * import { defineRoutes } from '@rshono/core';\n *\n * export const routes = defineRoutes({\n * routes: [\n * { path: '/', component: () => import('./components/home') },\n * { path: '/profile/:id', component: () => import('./components/profile') },\n * {\n * path: '/docs/:slug',\n * render: 'static',\n * component: () => import('./components/documentation'),\n * staticPaths: async () => [{ slug: 'getting-started' }, { slug: 'deployment' }],\n * },\n * { type: 'endpoint', path: '/api/health', server: () => import('./health') },\n * ],\n * notFound: { component: () => import('./components/404') },\n * error: { component: () => import('./components/500') },\n * });\n * ```\n *\n * @example\n * ```ts\n * // The shorthand, for an app with no notFound or error page.\n * export const routes = defineRoutes([{ path: '/', component: () => import('./components/home') }]);\n * ```\n *\n * @see {@link https://www.rshono.com/docs/routing | Docs — routing}\n */\nexport function defineRoutes<const T extends readonly Route[] | RouteConfig<readonly Route[]>>(input: T & ValidateInput<T>): RouteConfig<RoutesOf<T>>;\nexport function defineRoutes(input: readonly Route[] | RouteConfig): RouteConfig {\n return Array.isArray(input) ? { routes: input } : (input as RouteConfig);\n}\n"]}
@@ -532,7 +532,11 @@ function loadPayload(url, signal, afterCommit) {
532
532
  push(payload.redirect);
533
533
  return;
534
534
  }
535
- committed = setPayload(payload, afterCommit);
535
+ // The fetch crossed an await, so its payload update needs a new synchronous transition scope.
536
+ // Keep the commit promise outside the async Action; React tracks the scheduled update until commit.
537
+ React.startTransition(() => {
538
+ committed = setPayload(payload, afterCommit);
539
+ });
536
540
  };
537
541
  // `startTransition` runs the work but hands nothing back, so the promise carrying a failure is caught here
538
542
  // instead. Assigned synchronously: React invokes the callback before `startNav` returns.
@@ -713,7 +717,9 @@ async function main() {
713
717
  // its predecessor's scroll out of the queue along with its commit. Initialised with the reload's offset:
714
718
  // the first layout effect below applies it with the first payload, before the new tree is painted.
715
719
  const pendingScroll = React.useRef(restored ? () => scrollToPoint(restored) : null);
716
- React.useEffect(() => {
720
+ // Descendant passive effects can start a navigation before the root's passive effects run.
721
+ // Install the live payload setter and transition runner before any such navigation starts.
722
+ React.useLayoutEffect(() => {
717
723
  setPayload = (next, afterCommit) => new Promise((resolve) => {
718
724
  // A payload replaced before it ever painted still has a navigation waiting on it. React commits
719
725
  // only the newest, so the effect below never runs for the one it skipped: release it here.
@@ -741,7 +747,8 @@ async function main() {
741
747
  pendingCommit.current = null;
742
748
  commit?.();
743
749
  }, [payload]);
744
- React.useEffect(() => listenNavigation(), []);
750
+ // A descendant may navigate from its first passive effect. Intercept it before that effect runs.
751
+ React.useLayoutEffect(() => listenNavigation(), []);
745
752
  const router = React.useMemo(() => ({ push, replace, back, forward, refresh, pending }), [pending]);
746
753
  return _jsx(RouterContext.Provider, { value: router, children: payload.root });
747
754
  }
@@ -1 +1 @@
1
- {"version":3,"file":"entry.client.js","sourceRoot":"","sources":["../../src/runtime/entry.client.tsx"],"names":[],"mappings":"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","sourcesContent":["import React from 'react';\nimport { hydrateRoot } from 'react-dom/client';\nimport {\n createFromFetch,\n createFromReadableStream,\n createTemporaryReferenceSet,\n encodeReply,\n setServerCallback,\n} from 'react-server-dom-rspack/client.browser';\nimport { isControlDigest, parseRedirectDigest } from './control.js';\nimport type { DevMessage } from './dev-protocol.js';\nimport type { RscPayload } from './entry.rsc.js';\n// Dev-only: its one caller sits behind `import.meta.webpackHot`, which a production build compiles to\n// `false` — so this module is dropped there.\nimport { walkHotUpdates } from './hot-update.js';\nimport { RouterContext, type NavigationRouter } from './navigation.js';\nimport { createRscRequest } from './request.js';\n\nconst isDev = process.env.NODE_ENV === 'development';\n\ndeclare global {\n /** The array the payload `<script>` tags `flight-inject.ts` emits push their chunks into. */\n var __FLIGHT_DATA: Array<string | Uint8Array> | undefined;\n}\n\n/** The flight payload the document carried, read back out of `__FLIGHT_DATA` — see `flight-inject.ts`. */\nfunction readFlightPayload(): ReadableStream<Uint8Array> {\n const encoder = new TextEncoder();\n // Assigned synchronously by `start`, which `new ReadableStream` runs before it returns.\n let controller!: ReadableStreamDefaultController<Uint8Array>;\n const stream = new ReadableStream<Uint8Array>({\n start: (c) => void (controller = c),\n });\n const enqueue = (chunk: string | Uint8Array) => controller.enqueue(typeof chunk === 'string' ? encoder.encode(chunk) : chunk);\n\n // Payload scripts interleave with the document: the ones that already ran are in the array, the rest\n // arrive through `push`.\n const data = (self.__FLIGHT_DATA ??= []);\n for (const chunk of data) enqueue(chunk);\n data.push = enqueue as typeof data.push;\n\n // The last payload script lands before parsing finishes, so that is what closes the stream.\n if (document.readyState === 'loading') {\n document.addEventListener('DOMContentLoaded', () => controller.close(), { once: true });\n } else {\n controller.close();\n }\n return stream;\n}\n\n/** Created at module evaluation, not inside `main()`, so no chunk can be pushed before it is watching. */\nconst flightStream = readFlightPayload();\n\n/**\n * The part of the location a payload is rendered for — the document, without the fragment, which the server\n * never sees. Two URLs that differ only by `#hash` describe the same payload.\n */\nconst documentUrl = (): string => location.pathname + location.search;\n\n/**\n * The document URL the payload on screen was rendered for — see {@link documentUrl}. A fragment-only\n * traversal leaves it unchanged, which is how the `popstate` listener knows there is nothing to fetch.\n * Updated in the layout effect that commits a payload.\n */\nlet renderedUrl = documentUrl();\n\n/** Guarantees somewhere to attach the fatal overlay: the root container is `document`, so a teardown can take `<body>` with it. */\nfunction overlayHost(): HTMLElement {\n if (!document.documentElement) document.appendChild(document.createElement('html'));\n if (!document.body) document.documentElement.appendChild(document.createElement('body'));\n return document.body;\n}\n\n/**\n * Paints a full-viewport panel over whatever is on screen, and returns the box for the caller to fill.\n *\n * DOM calls rather than React (one caller runs because the renderer just failed), and `textContent` rather\n * than `innerHTML` (an error message is untrusted input). Queued on a macrotask: React's teardown runs after\n * the callback that reaches here returns, and would remove a node appended inline.\n */\nfunction paintOverlay(fill: (box: HTMLElement) => void): void {\n setTimeout(() => {\n const host = overlayHost();\n host.querySelector('[data-rshono-fatal]')?.remove();\n\n const box = document.createElement('div');\n box.setAttribute('data-rshono-fatal', '');\n box.setAttribute('role', 'alert');\n box.style.cssText =\n 'position:fixed;inset:0;z-index:2147483647;overflow:auto;padding:1.5rem;background:#18181b;color:#f4f4f5;' +\n 'font:14px/1.6 ui-monospace,SFMono-Regular,Menlo,monospace;text-align:left';\n\n fill(box);\n host.appendChild(box);\n }, 0);\n}\n\n/** The overlay's heading. */\nfunction overlayTitle(text: string): HTMLElement {\n const title = document.createElement('div');\n title.textContent = text;\n title.style.cssText = 'font-size:1.0625rem;font-weight:700;color:#f87171;margin:0 0 0.75rem';\n return title;\n}\n\n/**\n * Paints the reason for an uncaught render error over the blank page it leaves behind — the full stack in\n * dev, a generic notice and a reload button in production.\n */\nfunction showFatal(error: unknown, componentStack?: string | null): void {\n paintOverlay((box) => {\n box.appendChild(overlayTitle(isDev ? 'Unhandled error' : 'Something went wrong'));\n\n if (isDev) {\n const detail = document.createElement('pre');\n detail.style.cssText = 'margin:0;white-space:pre-wrap;word-break:break-word';\n detail.textContent =\n (error instanceof Error ? (error.stack ?? `${error.name}: ${error.message}`) : String(error)) +\n (componentStack ? `\\n\\nComponent stack:${componentStack}` : '');\n box.appendChild(detail);\n } else {\n const message = document.createElement('p');\n message.textContent = 'This page hit an unexpected error and can’t continue.';\n message.style.cssText = 'margin:0 0 1rem;color:#d4d4d8';\n box.appendChild(message);\n }\n\n const reload = document.createElement('button');\n reload.textContent = 'Reload page';\n reload.style.cssText =\n 'margin-top:1.25rem;padding:0.5rem 1rem;font:inherit;color:#18181b;background:#f4f4f5;border:0;border-radius:4px;cursor:pointer';\n reload.addEventListener('click', () => loadDocument());\n box.appendChild(reload);\n });\n}\n\n/**\n * The end of the line for a `notFound()` that arrived too late to be a 404 and did not survive a reload.\n *\n * No reload button, unlike {@link showFatal}: the reload has already been spent, and the second identical\n * response is what brought us here. \"Page not found\" is what the server was trying to say, so it is what the\n * visitor is told; the reason it could not say it properly is a message for whoever wrote the page, and dev is\n * where they are.\n */\nfunction showLateNotFound(): void {\n paintOverlay((box) => {\n box.appendChild(overlayTitle('Page not found'));\n\n const message = document.createElement('p');\n message.textContent = isDev\n ? 'notFound() was raised from a boundary that resolved after the page shell had been sent, so the response ' +\n 'could not be a 404 — and reloading rendered the same page again. Decide before the render starts ' +\n 'streaming: in Hono middleware, or in the page component body above the boundary.'\n : 'This page is not available.';\n message.style.cssText = 'margin:0;color:#d4d4d8';\n box.appendChild(message);\n });\n}\n/** What every flight response is typed as. The charset and any other parameters follow it. */\nconst FLIGHT_CONTENT_TYPE = 'text/x-component';\n\n/**\n * Fetches a payload, refusing a response that is not one.\n *\n * The status cannot be the gate: a payload legitimately arrives as a 404 from the `notFound` page and as a\n * 500 from an action that threw, and both carry a real payload the caller has to see. The content type is.\n *\n * What this catches is the response that is not a payload at all — a `bodyLimit()` 413, a proxy's error page,\n * a 502 mid-deploy. Handed to the flight parser those all surface as `Error: Connection closed.`, with the\n * status and the body nowhere in sight; here they become an error that says what arrived.\n */\nasync function payloadResponse(request: Request): Promise<Response> {\n const response = await fetch(request);\n const contentType = response.headers.get('content-type');\n if (contentType?.startsWith(FLIGHT_CONTENT_TYPE)) return response;\n // Read for the message: a plain-text refusal says what it refused only in its body, and HTTP/2 has no\n // `statusText` at all. Bounded, because this is an error path and the body is not ours to trust.\n const body = await response.text().then(\n (text) => text.trim().slice(0, 200),\n () => '',\n );\n const status = `${response.status}${response.statusText ? ` ${response.statusText}` : ''}`;\n throw new Error(`[rshono] the server answered ${status} (${contentType ?? 'no content type'}) instead of a payload${body ? `: ${body}` : ''}`);\n}\n\n/**\n * Asks a URL for its flight payload. Deliberately uncached — a payload can never be staler than the click\n * that wanted it, and the browser's own HTTP cache is what makes a repeat visit cheap.\n */\nfunction requestPayload(href: string, signal?: AbortSignal): Promise<RscPayload> {\n return createFromFetch<RscPayload>(payloadResponse(createRscRequest(new URL(href, location.href).href, undefined, signal)));\n}\n\n/**\n * Whether the browser hands us its navigations. Gated on `sourceElement` rather than on `navigation` itself:\n * Chrome shipped the event in 102 and that property only in 135, and without it a `data-native` link cannot\n * be told from any other — so the older window would soft-navigate the very links that asked not to be.\n *\n * Where this is false there is no interception at all and every navigation is a real browser load, which a\n * server-rendered app answers correctly on its own. Only the soft part is missing.\n *\n * Both globals are tested, and neither is touched before: this runs at module scope, where a ReferenceError\n * would take the whole client runtime down with it rather than degrading anything.\n */\nconst canSoftNavigate = typeof navigation !== 'undefined' && typeof NavigateEvent !== 'undefined' && 'sourceElement' in NavigateEvent.prototype;\n\n/**\n * The runtime owns a soft navigation's scroll, so the browser's own restoration has to be off: left on, a\n * traversal restores the destination's offset against the outgoing tree before the payload for that entry\n * has even been asked for, and the incoming tree overwrites it. `manual` only concerns the entries this\n * document creates — a navigation to another document creates its own entry `auto` — and it also turns the\n * browser's reload restoration off, which {@link readStoredScrollPositions} and the first layout effect put\n * back.\n *\n * Gated on the soft router: below the Navigation API floor every navigation is a real document load, which\n * a server-rendered app answers correctly and the browser restores correctly, and taking that over without\n * a router to repaint the entry would strand the visitor at the top.\n */\nif (canSoftNavigate) {\n try {\n history.scrollRestoration = 'manual';\n } catch {\n // A preference, not a requirement: where it cannot be set, the browser's restoration and the runtime's\n // own can race on a traversal, and the runtime's runs at commit, after.\n }\n}\n\n/** A scroll offset, in the coordinates `window.scrollTo` takes and `window.scrollX`/`window.scrollY` return. */\ntype ScrollPoint = { x: number; y: number };\n\n/**\n * Where each history entry of this document was left, keyed by its Navigation API key. In memory for the\n * document's life; {@link persistScrollPositions} also writes it to `sessionStorage` so a reload — which\n * the `manual` mode above stops the browser restoring — lands where the last document was left.\n */\nconst scrollPositions = new Map<string, ScrollPoint>();\n\n/** The `sessionStorage` key holding {@link scrollPositions}. */\nconst SCROLL_STORAGE_KEY = 'rshono:scroll';\n\n/** How many entries are kept in that snapshot; the oldest falls out first — `Map` iteration order. */\nconst SCROLL_STORAGE_LIMIT = 50;\n\n/** The key of the history entry being shown, or `undefined` where the soft router does not exist. */\nfunction currentEntryKey(): string | undefined {\n return canSoftNavigate ? navigation.currentEntry?.key : undefined;\n}\n\n/**\n * Records where the outgoing entry is being left. Read at `navigate` time — before the browser commits the\n * new entry — and at `pagehide`, so whatever the navigation turns out to be, the entry it leaves has a\n * position to come back to.\n */\nfunction rememberCurrentScroll(): void {\n const key = currentEntryKey();\n if (key) scrollPositions.set(key, { x: window.scrollX, y: window.scrollY });\n}\n\n/** The position `key` was left at, or `undefined` when this document never saw it. */\nfunction scrollPointFor(key: string | undefined): ScrollPoint | undefined {\n return key === undefined ? undefined : scrollPositions.get(key);\n}\n\n/**\n * Reads the last document's snapshot back into {@link scrollPositions}. Called once, on startup, before the\n * first payload commits: the in-memory map alone would lose every entry the moment the document is replaced.\n */\nfunction readStoredScrollPositions(): void {\n try {\n const raw = sessionStorage.getItem(SCROLL_STORAGE_KEY);\n if (!raw) return;\n for (const [key, point] of Object.entries(JSON.parse(raw) as Record<string, ScrollPoint>)) {\n if (Number.isFinite(point?.x) && Number.isFinite(point?.y)) scrollPositions.set(key, point);\n }\n } catch {\n // Blocked site data, or a snapshot written by a different version. Either way there is nothing to restore,\n // and the page is still correct without it.\n }\n}\n\n/** Writes {@link scrollPositions} out, oldest first, bounded — see {@link SCROLL_STORAGE_LIMIT}. */\nfunction persistScrollPositions(): void {\n try {\n while (scrollPositions.size > SCROLL_STORAGE_LIMIT) {\n const oldest = scrollPositions.keys().next().value;\n if (oldest === undefined) break;\n scrollPositions.delete(oldest);\n }\n sessionStorage.setItem(SCROLL_STORAGE_KEY, JSON.stringify(Object.fromEntries(scrollPositions)));\n } catch {\n // Blocked site data: the in-memory map still carries this document's navigations.\n }\n}\n\n/**\n * The snapshot starts with the document, not with hydration: the page is visible and clickable while the\n * initial payload streams, and a reload or a navigation away in that window would otherwise lose the offset\n * now that `manual` has stopped the browser restoring it. Nothing here depends on the router being mounted,\n * so it does not wait for {@link listenNavigation}.\n */\nif (canSoftNavigate) {\n window.addEventListener('pagehide', () => {\n rememberCurrentScroll();\n persistScrollPositions();\n });\n}\n\n/**\n * Drops a navigation's result promises. Both reject when a navigation is superseded or cancelled — routine\n * here, since a second click is meant to abandon the first — and unhandled they would be reported as faults.\n */\nfunction settle(result: NavigationResult): void {\n const ignore = () => {};\n void result.committed?.catch(ignore);\n void result.finished?.catch(ignore);\n}\n\n/**\n * The mark {@link loadDocument} puts on its navigations, so the `navigate` listener below recognizes them as\n * the runtime's own. A symbol because the identity has to survive the trip through the browser intact:\n * `NavigateEvent.info` hands the value back by reference, so only the navigation that was given it matches.\n */\nconst documentNavigation = Symbol('rshono:document-navigation');\n\n/**\n * Performs a navigation the router below must **not** intercept, and returns having asked for it.\n *\n * `listenNavigation` intercepts a `reload` on purpose — that is what `router.refresh()` is — and every caller\n * here is reaching for a *new document* precisely because the current one cannot be repaired: the React root\n * a soft load would render into is the thing that just failed, or is about to be torn down. Intercepted, the\n * escape hatch becomes a payload fetch that lands nowhere — which is how a late `notFound()` left the tab on\n * its Suspense fallback with no second document ever arriving, and how a late `redirect()` moved the address\n * bar to a page it then failed to render.\n *\n * The mark rides the navigation itself, through `info`, so the listener recognizes the event that owns it\n * instead of consuming a flag set in advance. There is no state to clear and none to leak: a navigation the\n * browser refuses cannot make the next one a full load. Below the Navigation API there is no interception to\n * opt out of, and `location.*` is already a document load.\n */\nfunction loadDocument(href?: string): void {\n if (!canSoftNavigate) {\n if (href === undefined) window.location.reload();\n else window.location.assign(href);\n return;\n }\n\n settle(href === undefined ? navigation.reload({ info: documentNavigation }) : navigation.navigate(href, { info: documentNavigation }));\n}\n\n// The imperative actions behind `useNavigation().router`. Each one only *asks*: the browser turns it into a\n// `navigate` event, which is where `listenNavigation` answers it — so a `router.push` and a link click reach\n// the same code by the same route, and inherit the same fetch, scroll and `pending` flag.\nfunction push(href: string): void {\n if (canSoftNavigate) settle(navigation.navigate(href, { history: 'push' }));\n else window.location.assign(href);\n}\n\nfunction replace(href: string): void {\n if (canSoftNavigate) settle(navigation.navigate(href, { history: 'replace' }));\n else window.location.replace(href);\n}\n\n// A traversal is the browser's to perform either way — `navigation` only hands it back as an interceptable\n// event first. Nothing to go back to is a rejection there and a no-op here; both amount to the same thing.\nfunction back(): void {\n if (canSoftNavigate) settle(navigation.back());\n else window.history.back();\n}\n\nfunction forward(): void {\n if (canSoftNavigate) settle(navigation.forward());\n else window.history.forward();\n}\n\n// A refresh keeps the URL, and is still a navigation: it arrives as `navigationType: 'reload'`, which is what\n// tells the listener to leave scroll and focus where the user left them.\nfunction refresh(): void {\n if (canSoftNavigate) settle(navigation.reload());\n else window.location.reload();\n}\n\n/** How long the recovery reload is given to replace this document before the panel is painted instead. */\nconst RELOAD_GRACE_MS = 2000;\n\n/** The `sessionStorage` key bounding the recovery reload for one URL. Spent here, released in {@link main}. */\nconst lateNotFoundKey = (): string => `rshono:late-not-found:${documentUrl()}`;\n\n/**\n * Spends the one reload a late `notFound()` gets, or paints if it has already been spent for this URL.\n *\n * `redirect()` is terminal on the client — there is somewhere to navigate to — and `notFound()` is not: the\n * response is already committed as a 200, so the only recovery left is asking for the page again and hoping\n * the signal comes early enough this time to be a real 404. That works where the lateness was incidental, a\n * boundary that happened to resolve after the shell on a slow request. Where it is structural — a page that\n * always signals from a late boundary — the reload gets a byte-identical response and reloads again, and the\n * tab spins until the visitor leaves. In production nothing is logged, because the warning that explains this\n * is `isDev`-only.\n *\n * So it is bounded: one reload per URL per tab, then {@link showLateNotFound}. `sessionStorage` because the\n * value has to outlive the document it is written in and must not outlive the tab, and keyed by URL so a\n * second page's late signal still gets its own attempt.\n */\nfunction reloadOnceForLateNotFound(): void {\n const key = lateNotFoundKey();\n let spent: boolean;\n try {\n spent = sessionStorage.getItem(key) !== null;\n if (!spent) sessionStorage.setItem(key, '1');\n } catch {\n // Storage can throw outright where site data is blocked, and a page that cannot count its reloads has\n // to pick a side. It picks the terminating one: a message on a page that might have recovered is a\n // worse outcome than a reload loop only by a lot less.\n spent = true;\n }\n if (spent) {\n showLateNotFound();\n return;\n }\n\n loadDocument();\n\n // The reload wins this race whenever it happens at all: the document goes away and takes the timer with\n // it. What this covers is a reload that does not happen — swallowed by an interceptor, refused by the\n // browser, held by a `beforeunload` — which used to leave the visitor on a Suspense fallback with nothing\n // coming and nothing said. The panel is the honest answer in that case too.\n setTimeout(() => {\n if (!document.querySelector('[data-rshono-fatal]')) showLateNotFound();\n }, RELOAD_GRACE_MS);\n}\n\n/**\n * Turns a control-signal digest — how `redirect()` / `notFound()` reach the browser — into a real\n * navigation. Returns false for anything else, so callers fall through to their own handling.\n *\n * `hard` forces a full document load, for signals that surfaced *through React*: it unmounts the root on\n * an uncaught error, leaving no live tree to soft-navigate with.\n */\nfunction handleControlDigest(error: unknown, { hard = false }: { hard?: boolean } = {}): boolean {\n const digest = (error as { digest?: unknown } | null)?.digest;\n if (!isControlDigest(digest)) return false;\n const redirect = parseRedirectDigest(digest);\n if (!redirect) {\n reloadOnceForLateNotFound();\n } else if (hard) {\n // The URL is resolved first: a malformed location then throws here, before any navigation is asked for.\n loadDocument(new URL(redirect.location, window.location.href).href);\n } else {\n push(redirect.location);\n }\n return true;\n}\n\n/**\n * Scrolls the document to its start.\n *\n * The options form rather than `scrollTo(0, 0)`: the two-argument call is `auto`, which follows a\n * `scroll-behavior` the app may have set on `html`, and a soft navigation that animates its own reset reads\n * as a glitch rather than a page change.\n */\nfunction scrollToTop(): void {\n window.scrollTo({ top: 0, left: 0, behavior: 'instant' });\n}\n\n/** Puts a saved offset back. Instant for the same reason {@link scrollToTop} passes it. */\nfunction scrollToPoint(point: ScrollPoint): void {\n window.scrollTo({ top: point.y, left: point.x, behavior: 'instant' });\n}\n\n/**\n * Scrolls to a fragment's target the way the browser's own fragment jump does.\n *\n * `scrollIntoView` is the algorithm that honours `scroll-padding-top` on the scrolling box and\n * `scroll-margin-top` on the target, which `window.scrollTo` does not. The lookup follows the browser's\n * \"find a potential indicated element\": the id first, then the name. A malformed percent-escape falls back\n * to the literal fragment, and a fragment nothing matches gets the top of the document — what a browser\n * gives a missing anchor on a real load.\n */\nfunction jumpToAnchor(hash: string): void {\n const raw = hash.startsWith('#') ? hash.slice(1) : hash;\n // No special case for `#top`: the browser only treats it as the top of the document when no element\n // matches, and the fallback below is that top.\n if (raw === '') {\n scrollToTop();\n return;\n }\n let id = raw;\n try {\n id = decodeURIComponent(raw);\n } catch {\n // Malformed escape — the literal fragment is the better guess at the id than nothing.\n }\n const target = document.getElementById(id) ?? document.getElementsByName(id)[0];\n if (target) target.scrollIntoView();\n else scrollToTop();\n}\n\n/**\n * Moves focus the way the browser's `focusReset: 'after-transition'` does: the first `autofocus` element,\n * else the document body. A traversal is no longer intercepted, so the browser performs no focus reset for\n * it; without this, Back would leave focus on the link that was clicked on the page being left, and the next\n * Tab would resume there. `preventScroll` because the traversal's own offset has just been restored.\n */\nfunction resetFocus(): void {\n const autofocus = document.querySelector<HTMLElement>('[autofocus]');\n if (autofocus) autofocus.focus({ preventScroll: true });\n else document.body.focus({ preventScroll: true });\n}\n\n/**\n * Puts a payload on screen, resolving once React has committed it. Replaced by `BrowserRoot`'s own on mount;\n * the default covers the window before hydration, where `setServerCallback` is already registered but there\n * is no root to update — a reload is the honest answer, and nothing after it needs to run.\n *\n * `afterCommit`, when given, runs in the same layout effect that releases the commit: after the new tree is\n * in the DOM and before the browser paints, which is the only moment a `#hash` target exists and the\n * pre-scroll position has not been shown.\n */\nlet setPayload: (payload: RscPayload, afterCommit?: () => void) => Promise<void> = () => {\n window.location.reload();\n return new Promise<void>(() => {});\n};\n\n/** Runs work inside the nav transition so `useNavigation().pending` stays true across the round-trip. */\nlet startNav: (run: () => void | Promise<void>) => void = (run) => {\n void run();\n};\n\n/**\n * The navigation whose payload is allowed to settle the screen. React runs async work concurrently, so two\n * navigations are two live fetches with no ordering between them; without this a slow first response landing\n * after a fast second one repaints the page the user already left. The Navigation API aborts an intercepted\n * navigation when a newer one starts, but a traversal has no `event.signal` to watch — `popstate` arrives\n * after the browser has already committed it — so ordering is the runtime's own for those.\n */\nlet currentNavigation = 0;\n\n/** The in-flight navigation's fetch, so a newer one can stop paying for it. */\nlet navigationFetch: AbortController | null = null;\n\n/**\n * Fetches the payload for `url` and puts it on screen.\n *\n * Resolves once React has **committed** it rather than when the fetch lands: `afterCommit` runs at that\n * point, and a `#hash` target does not exist until the new tree does. Rejects only on a genuine failure —\n * being superseded is not one, and resolves quietly, because the navigation that replaced this one owns the\n * screen from then on.\n */\nfunction loadPayload(url: string, signal?: AbortSignal, afterCommit?: () => void): Promise<void> {\n // This navigation's place in the queue, and its own abort switch: a fetch is abandoned by whichever comes\n // first, the browser superseding it (an intercepted navigation carries `event.signal`) or a newer runtime\n // fetch starting (a traversal, an action, a dev refresh).\n const navigation = ++currentNavigation;\n navigationFetch?.abort();\n const controller = (navigationFetch = new AbortController());\n const abort = signal ? AbortSignal.any([signal, controller.signal]) : controller.signal;\n\n // Deliberately not awaited inside the transition: the scope ends once the payload is handed to React, and\n // React holds `pending` until the update it scheduled commits. Awaiting the commit *inside* the scope would\n // work too, but only because React happens not to gate a commit on its async scope settling — an internal\n // this has no reason to depend on across the whole `^19.1.0` peer range.\n let committed: Promise<void> | undefined;\n\n const run = async () => {\n const payload = await requestPayload(url, abort);\n // Checked again after the await because the fetch may already have resolved by then, and applying it\n // would repaint a page the user has left.\n if (abort.aborted || navigation !== currentNavigation) return;\n if (payload.redirect) {\n push(payload.redirect);\n return;\n }\n committed = setPayload(payload, afterCommit);\n };\n\n // `startTransition` runs the work but hands nothing back, so the promise carrying a failure is caught here\n // instead. Assigned synchronously: React invokes the callback before `startNav` returns.\n let work!: Promise<void>;\n startNav(() => (work = run()));\n\n return work.then(\n // Undefined whenever nothing was applied — an abort, or a redirect — and there is then nothing to wait for.\n () => committed,\n (error: unknown) => {\n // Checked before the error is read: an abort is this navigation being replaced, and the one that\n // replaced it owns the outcome.\n if (abort.aborted || navigation !== currentNavigation || handleControlDigest(error)) return;\n throw error;\n },\n );\n}\n\n/**\n * Whether a destination names a file rather than a page. `public/`, `/_static` and an endpoint route that\n * serves a document (`/llms.txt`, `/sitemap.xml`) answer an RSC fetch with the file itself, not a flight\n * payload — so intercepting one buys nothing: the payload never arrives, and the only recovery left is the\n * document load the browser would have made directly. Handing it that navigation up front also gives the\n * entry the file loads into the browser's own history, so Back is an ordinary cross-document traversal. An\n * intercepted entry is same-document by construction, and traversing one with nothing to repaint it changes\n * the URL and nothing else — which is what a Back press out of an opened file was doing.\n *\n * A dot in the last path segment rather than a list of extensions: a list is never complete, and every miss\n * is the failed round trip above. A page route whose last segment carries a dot (`/release-1.0`) therefore\n * costs a document load — the direction to err in, and what a `data-native` link already asks for by hand.\n */\nfunction namesAFile(href: string): boolean {\n const lastSegment = new URL(href).pathname.split('/').pop() ?? '';\n return lastSegment.includes('.');\n}\n\n/**\n * Navigations the browser can hand over but shouldn't:\n *\n * - a fragment jump, which is same-document already and needs no payload — the browser's own jump is the one\n * that honours `scroll-padding-top`, and re-rendering would pull the target out from under it;\n * - a download, which is not a navigation of this page at all;\n * - a `POST` form, which is a submission and the server's to answer (a `GET` form carries its fields in the\n * URL, has no `formData`, and soft-navigates like any other link);\n * - a link marked `data-native`, the documented opt-out;\n * - a destination that names a file — see {@link namesAFile}.\n */\nfunction leaveToBrowser(event: NavigateEvent): boolean {\n return (\n event.hashChange ||\n event.downloadRequest !== null ||\n event.formData !== null ||\n event.sourceElement?.hasAttribute('data-native') === true ||\n namesAFile(event.destination.url)\n );\n}\n\n/**\n * The whole router, in one listener.\n *\n * Every navigation the page can make arrives as a `navigate` event — a link click, a `GET` form, a\n * `history.pushState`, the back button, `navigation.reload()` — already filtered by the browser: it does not\n * fire for a middle-click, a modified click or a new tab, and reports `canIntercept: false` for anything\n * cross-origin, or for a traversal that leaves the app. Those need no handling here; they are left alone, and\n * the browser performs them as it always would.\n */\nfunction listenNavigation(): () => void {\n if (!canSoftNavigate) return () => {};\n\n const onNavigate = (event: NavigateEvent) => {\n // A document navigation the runtime asked for itself, marked through `info`. Checked before the scroll\n // snapshot: the document is going away, so where its entry was left does not matter, and an unrelated\n // later navigation can never be mistaken for this one.\n if (event.info === documentNavigation) return;\n\n // Whatever the browser is about to do with this navigation, the entry it is leaving is about to lose the\n // offset it was at, and nothing else in this document will put it back. Saved before the branches below\n // return, so a fragment the browser performs itself is covered too.\n rememberCurrentScroll();\n\n if (!event.canIntercept || leaveToBrowser(event)) return;\n\n // A traversal is repainted by the `popstate` listener below, not intercepted. `intercept`ing one is what\n // makes WebKit stall the rendered viewport for about three seconds on a back swipe\n // (bugs.webkit.org/319414): the view gesture's snapshot is only removed once the navigation finishes, and\n // React's root attaches the wheel listener the bug also needs. Letting the traversal through means the\n // browser commits the entry straight away, and the runtime puts the payload on screen when it arrives.\n if (event.navigationType === 'traverse') return;\n\n // A replace or a refresh stays where it is, so neither should move. A push starts at the top of the\n // page, or at its fragment — and that scroll is the runtime's own now: WebKit performs no\n // `after-transition` reset at all for an intercepted push (bugs.webkit.org/304593). Chromium skips it\n // too, and a fragment jump rides the same code path. Passing `manual` here makes the browser hand the\n // handler over without scrolling; the `afterCommit` callback reaches the target once the new tree is on\n // screen. Focus stays the browser's, reset after the transition.\n const inPlace = event.navigationType === 'replace' || event.navigationType === 'reload';\n let afterCommit: (() => void) | undefined;\n if (event.navigationType === 'push') {\n const { hash } = new URL(event.destination.url);\n afterCommit = hash === '' ? scrollToTop : () => jumpToAnchor(hash);\n }\n\n event.intercept({\n scroll: 'manual',\n focusReset: inPlace ? 'manual' : 'after-transition',\n // The URL commits before the handler runs, so a failure leaves the address bar describing a page the\n // document is not showing. A real load is the only way back to agreement.\n handler: () => loadPayload(event.destination.url, event.signal, afterCommit).catch(() => loadDocument()),\n });\n };\n\n /**\n * Repaints a traversal the listener above deliberately left to the browser, and moves the viewport back\n * where the entry was left. `popstate` fires after the browser has committed the entry, so the destination\n * is `navigation.currentEntry` and its saved offset is in {@link scrollPositions}.\n */\n const onPopState = () => {\n const stored = scrollPointFor(currentEntryKey());\n const hash = location.hash;\n const apply = () => {\n if (stored) scrollToPoint(stored);\n else if (hash !== '') jumpToAnchor(hash);\n else scrollToTop();\n };\n\n // A fragment-only traversal never changed the payload: the address bar is back at an anchor of the page\n // already on screen, so there is nothing to fetch and nothing to wait for. The browser's own restoration\n // is off, so the offset comes from what `onNavigate` saved when the anchor was followed; no focus reset,\n // which is what leaving those navigations to the browser has always meant.\n if (documentUrl() === renderedUrl) {\n apply();\n return;\n }\n\n void loadPayload(location.href, undefined, () => {\n apply();\n // The browser performs this for an intercepted navigation; a traversal is no longer intercepted, so\n // without it Back would leave focus on the link that was clicked on the page being left.\n resetFocus();\n }).catch(() => loadDocument());\n };\n\n navigation.addEventListener('navigate', onNavigate);\n window.addEventListener('popstate', onPopState);\n return () => {\n navigation.removeEventListener('navigate', onNavigate);\n window.removeEventListener('popstate', onPopState);\n };\n}\n\nasync function main() {\n // The assertion is load-bearing under the compiler that builds this: TypeScript 7 declares `nonce` on\n // HTMLElement, 6 declares it on Element. ESLint runs the older lib — where the narrowing is redundant —\n // so it reports an assertion that `tsc` requires. Believe `typecheck`, not the rule.\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion\n const cspMeta = document.querySelector('meta[property=\"csp-nonce\"]') as HTMLMetaElement | null;\n if (cspMeta?.nonce) __webpack_nonce__ = cspMeta.nonce;\n\n const initialPayload = await createFromReadableStream<RscPayload>(flightStream);\n\n // The recovery reload landed: this document *is* the `notFound` page, so the signal that could only be a\n // digest on the `RSC: 1` request became a real 404 on the document request. The one-reload bound was spent\n // on a recovery that worked and has to be released — otherwise the *next* soft navigation to this URL sees a\n // spent key and paints {@link showLateNotFound} over a page the app can still render.\n //\n // This is the discriminator the bound was missing. A structurally late `notFound()` commits its 200 before\n // it signals, so its reloaded document is the page itself and carries no `notFound`: the key survives and\n // that loop stays bounded at one reload, which is the whole reason the bound exists.\n if (initialPayload.notFound) {\n try {\n sessionStorage.removeItem(lateNotFoundKey());\n } catch {\n // Blocked site data. `reloadOnceForLateNotFound` already treats that as the terminating case.\n }\n }\n\n // Everything the last document saved, read before any payload commits: the in-memory map alone would not\n // survive the reload that `history.scrollRestoration = 'manual'` just stopped the browser restoring. The\n // entry's key is stable across a reload, and the offset is applied by `BrowserRoot`'s first layout effect,\n // before the first paint of the new tree.\n if (canSoftNavigate) readStoredScrollPositions();\n const restored = scrollPointFor(currentEntryKey());\n\n function BrowserRoot() {\n const [payload, setPayloadState] = React.useState(initialPayload);\n const [pending, startTransition] = React.useTransition();\n // The resolver the payload on screen still owes — see {@link loadPayload}.\n const pendingCommit = React.useRef<(() => void) | null>(null);\n // The scroll the payload about to commit owes, set with it so a payload that supersedes another takes\n // its predecessor's scroll out of the queue along with its commit. Initialised with the reload's offset:\n // the first layout effect below applies it with the first payload, before the new tree is painted.\n const pendingScroll = React.useRef<(() => void) | null>(restored ? () => scrollToPoint(restored) : null);\n\n React.useEffect(() => {\n setPayload = (next, afterCommit) =>\n new Promise<void>((resolve) => {\n // A payload replaced before it ever painted still has a navigation waiting on it. React commits\n // only the newest, so the effect below never runs for the one it skipped: release it here.\n pendingCommit.current?.();\n pendingCommit.current = resolve;\n // Replaced rather than kept: a server action's payload carries no `afterCommit`, and the\n // navigation it superseded must not scroll the page the action is about to replace it with.\n pendingScroll.current = afterCommit ?? null;\n setPayloadState(next);\n });\n startNav = (run) => startTransition(run);\n }, [startTransition]);\n\n /**\n * Performs the pending scroll and releases the navigation waiting on this payload. A layout effect, so\n * the new tree is in the DOM and the pre-scroll position is never painted.\n */\n React.useLayoutEffect(() => {\n const scroll = pendingScroll.current;\n pendingScroll.current = null;\n scroll?.();\n // What the payload that just committed was rendered for — see {@link renderedUrl}. A redirect never\n // reaches here, and an action or a dev refresh keeps the URL it was fetched for.\n renderedUrl = documentUrl();\n const commit = pendingCommit.current;\n pendingCommit.current = null;\n commit?.();\n }, [payload]);\n\n React.useEffect(() => listenNavigation(), []);\n\n const router = React.useMemo<NavigationRouter>(() => ({ push, replace, back, forward, refresh, pending }), [pending]);\n\n return <RouterContext.Provider value={router}>{payload.root}</RouterContext.Provider>;\n }\n\n setServerCallback(async (id, args) => {\n const temporaryReferences = createTemporaryReferenceSet();\n // The document the action is being called from. Every action response carries a fresh payload for that\n // page, so if a navigation has moved on by the time it arrives the payload describes a page the user has\n // left — the return value is still theirs, but painting it is not. Compared without the fragment, which\n // the server never saw.\n const calledFrom = documentUrl();\n const request = createRscRequest(window.location.href, {\n id,\n body: await encodeReply(args, { temporaryReferences }),\n });\n let payload: RscPayload;\n try {\n payload = await createFromFetch<RscPayload>(payloadResponse(request), { temporaryReferences });\n } catch (error) {\n if (handleControlDigest(error)) return undefined;\n throw error;\n }\n if (payload.redirect) {\n push(payload.redirect);\n return undefined;\n }\n if (documentUrl() === calledFrom) React.startTransition(() => void setPayload(payload));\n if (payload.notFound) return undefined;\n const result = payload.returnValue;\n if (!result) {\n // A payload that is not this action's own reply: the server rendered a page in its place. An action\n // that had already run has its result carried across (see `actionResults` in entry.rsc.tsx), and the\n // ways a *caller* can get a request wrong are refused ahead of any render — an unknown id or an\n // undecodable body is a `text/plain` 400, which `payloadResponse` turns into an error of its own\n // before this.\n //\n // What is left is the server failing before the action ran, which is answered with the `error` page —\n // a flight payload, so it arrives here rather than at `payloadResponse`, with no `returnValue` in it.\n // A module the deployment no longer holds is the reachable case: `loadServerAction` throws, the\n // framework reports it and 500s, and this is what the caller has to go on. Hence the message: the\n // failure is on the server and its log is where the error is. Below that it is still the defensive\n // floor for a payload shaped by another deployment or replaced by a proxy — reading `.ok` off it used\n // to hand the caller `Cannot read properties of undefined`.\n throw new Error(\n '[rshono] the server action produced no result — the request failed around it and the server answered with a page instead. Its log has the error.',\n );\n }\n if (!result.ok) throw result.error;\n return result.value;\n });\n\n // A `redirect()` / `notFound()` from a component below the page root reaches us through React: it rides the\n // flight payload as an error, and boundaries re-throw it so it lands here rather than in a fallback.\n //\n // Installing these hooks opts out of React's own defaults, so everything that isn't a control signal has to\n // be put back by hand — `reportError` rather than a bare log, so error-reporting tools still see it.\n hydrateRoot(document, <BrowserRoot />, {\n formState: initialPayload.formState,\n onCaughtError: (error, errorInfo) => {\n if (handleControlDigest(error, { hard: true })) return;\n // A boundary handled it and the tree is intact, so no overlay over the app's own fallback.\n console.error(error, errorInfo.componentStack ?? '');\n },\n onUncaughtError: (error, errorInfo) => {\n if (handleControlDigest(error, { hard: true })) return;\n // Nothing caught it, so React tears the root down — and the root is `document`.\n globalThis.reportError(error);\n showFatal(error, errorInfo.componentStack);\n },\n });\n\n if (import.meta.webpackHot) {\n initDevRefresh();\n }\n}\n\n/**\n * Dev-only refresh client, listening to the CLI's SSE endpoint:\n *\n * client-built → hot-apply the waiting updates; anything the page can't be patched up to reloads.\n * rsc-update → server component code changed: re-fetch the flight payload, state preserved.\n * hello → sent on (re)connect with the latest build hash; a mismatch means a missed event.\n */\nfunction initDevRefresh() {\n const hot = import.meta.webpackHot!;\n let connectedOnce = false;\n /** The newest build the dev server has announced — what {@link applyClientUpdate} walks towards. */\n let targetHash: string | undefined;\n\n function reload(reason: string, error?: unknown): void {\n console.warn(`[rshono] ${reason} — reloading`, ...(error === undefined ? [] : [error]));\n loadDocument();\n }\n\n async function applyClientUpdate(): Promise<void> {\n const giveUp = await walkHotUpdates(\n hot,\n () => __webpack_hash__,\n () => targetHash,\n );\n if (giveUp) reload(giveUp.reason, giveUp.error);\n }\n\n async function handle(message: DevMessage): Promise<void> {\n switch (message.type) {\n case 'hello':\n targetHash = message.hash ?? targetHash;\n if (connectedOnce) {\n await applyClientUpdate();\n await loadPayload(window.location.href).catch(() => loadDocument());\n }\n connectedOnce = true;\n break;\n case 'client-built':\n targetHash = message.hash;\n await applyClientUpdate();\n break;\n case 'rsc-update':\n console.log('[rshono] server components updated');\n await loadPayload(window.location.href).catch(() => loadDocument());\n break;\n }\n }\n\n const source = new EventSource('/_rshono/hmr');\n // Chained rather than handled as they arrive: `hot.check` may only run from `idle`, and a burst of saves\n // puts several frames on the wire inside the time one takes. Queueing drops nothing, because `targetHash`\n // is shared — whichever handler runs next walks to the newest build.\n let queue: Promise<void> = Promise.resolve();\n source.onmessage = (event: MessageEvent<string>) => {\n const message = JSON.parse(event.data) as DevMessage;\n queue = queue.then(() => handle(message)).catch((error) => reload('the dev client failed', error));\n };\n}\n\n// A bootstrap failure — a truncated initial payload, most likely — would otherwise be an unhandled\n// rejection: nothing hydrates, nothing is reported, and the page just sits there.\nmain().catch((error) => {\n console.error('[rshono] the client runtime failed to start:', error);\n showFatal(error);\n});\n"]}
1
+ {"version":3,"file":"entry.client.js","sourceRoot":"","sources":["../../src/runtime/entry.client.tsx"],"names":[],"mappings":";AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EACL,eAAe,EACf,wBAAwB,EACxB,2BAA2B,EAC3B,WAAW,EACX,iBAAiB,GAClB,MAAM,wCAAwC,CAAC;AAChD,OAAO,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAGpE,sGAAsG;AACtG,6CAA6C;AAC7C,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,EAAE,aAAa,EAAyB,MAAM,iBAAiB,CAAC;AACvE,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAEhD,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,aAAa,CAAC;AAOrD,0GAA0G;AAC1G,SAAS,iBAAiB;IACxB,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC;IAClC,wFAAwF;IACxF,IAAI,UAAwD,CAAC;IAC7D,MAAM,MAAM,GAAG,IAAI,cAAc,CAAa;QAC5C,KAAK,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,UAAU,GAAG,CAAC,CAAC;KACpC,CAAC,CAAC;IACH,MAAM,OAAO,GAAG,CAAC,KAA0B,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;IAE9H,qGAAqG;IACrG,yBAAyB;IACzB,MAAM,IAAI,GAAG,CAAC,IAAI,CAAC,aAAa,KAAK,EAAE,CAAC,CAAC;IACzC,KAAK,MAAM,KAAK,IAAI,IAAI;QAAE,OAAO,CAAC,KAAK,CAAC,CAAC;IACzC,IAAI,CAAC,IAAI,GAAG,OAA2B,CAAC;IAExC,4FAA4F;IAC5F,IAAI,QAAQ,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;QACtC,QAAQ,CAAC,gBAAgB,CAAC,kBAAkB,EAAE,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IAC1F,CAAC;SAAM,CAAC;QACN,UAAU,CAAC,KAAK,EAAE,CAAC;IACrB,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,0GAA0G;AAC1G,MAAM,YAAY,GAAG,iBAAiB,EAAE,CAAC;AAEzC;;;GAGG;AACH,MAAM,WAAW,GAAG,GAAW,EAAE,CAAC,QAAQ,CAAC,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC;AAEtE;;;;GAIG;AACH,IAAI,WAAW,GAAG,WAAW,EAAE,CAAC;AAEhC,mIAAmI;AACnI,SAAS,WAAW;IAClB,IAAI,CAAC,QAAQ,CAAC,eAAe;QAAE,QAAQ,CAAC,WAAW,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC;IACpF,IAAI,CAAC,QAAQ,CAAC,IAAI;QAAE,QAAQ,CAAC,eAAe,CAAC,WAAW,CAAC,QAAQ,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC;IACzF,OAAO,QAAQ,CAAC,IAAI,CAAC;AACvB,CAAC;AAED;;;;;;GAMG;AACH,SAAS,YAAY,CAAC,IAAgC;IACpD,UAAU,CAAC,GAAG,EAAE;QACd,MAAM,IAAI,GAAG,WAAW,EAAE,CAAC;QAC3B,IAAI,CAAC,aAAa,CAAC,qBAAqB,CAAC,EAAE,MAAM,EAAE,CAAC;QAEpD,MAAM,GAAG,GAAG,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;QAC1C,GAAG,CAAC,YAAY,CAAC,mBAAmB,EAAE,EAAE,CAAC,CAAC;QAC1C,GAAG,CAAC,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAClC,GAAG,CAAC,KAAK,CAAC,OAAO;YACf,0GAA0G;gBAC1G,2EAA2E,CAAC;QAE9E,IAAI,CAAC,GAAG,CAAC,CAAC;QACV,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IACxB,CAAC,EAAE,CAAC,CAAC,CAAC;AACR,CAAC;AAED,6BAA6B;AAC7B,SAAS,YAAY,CAAC,IAAY;IAChC,MAAM,KAAK,GAAG,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;IAC5C,KAAK,CAAC,WAAW,GAAG,IAAI,CAAC;IACzB,KAAK,CAAC,KAAK,CAAC,OAAO,GAAG,sEAAsE,CAAC;IAC7F,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;GAGG;AACH,SAAS,SAAS,CAAC,KAAc,EAAE,cAA8B;IAC/D,YAAY,CAAC,CAAC,GAAG,EAAE,EAAE;QACnB,GAAG,CAAC,WAAW,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC;QAElF,IAAI,KAAK,EAAE,CAAC;YACV,MAAM,MAAM,GAAG,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;YAC7C,MAAM,CAAC,KAAK,CAAC,OAAO,GAAG,qDAAqD,CAAC;YAC7E,MAAM,CAAC,WAAW;gBAChB,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,IAAI,GAAG,KAAK,CAAC,IAAI,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;oBAC7F,CAAC,cAAc,CAAC,CAAC,CAAC,uBAAuB,cAAc,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YAClE,GAAG,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;QAC1B,CAAC;aAAM,CAAC;YACN,MAAM,OAAO,GAAG,QAAQ,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC;YAC5C,OAAO,CAAC,WAAW,GAAG,uDAAuD,CAAC;YAC9E,OAAO,CAAC,KAAK,CAAC,OAAO,GAAG,+BAA+B,CAAC;YACxD,GAAG,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;QAC3B,CAAC;QAED,MAAM,MAAM,GAAG,QAAQ,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;QAChD,MAAM,CAAC,WAAW,GAAG,aAAa,CAAC;QACnC,MAAM,CAAC,KAAK,CAAC,OAAO;YAClB,gIAAgI,CAAC;QACnI,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,YAAY,EAAE,CAAC,CAAC;QACvD,GAAG,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;IAC1B,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,gBAAgB;IACvB,YAAY,CAAC,CAAC,GAAG,EAAE,EAAE;QACnB,GAAG,CAAC,WAAW,CAAC,YAAY,CAAC,gBAAgB,CAAC,CAAC,CAAC;QAEhD,MAAM,OAAO,GAAG,QAAQ,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC;QAC5C,OAAO,CAAC,WAAW,GAAG,KAAK;YACzB,CAAC,CAAC,0GAA0G;gBAC1G,mGAAmG;gBACnG,kFAAkF;YACpF,CAAC,CAAC,6BAA6B,CAAC;QAClC,OAAO,CAAC,KAAK,CAAC,OAAO,GAAG,wBAAwB,CAAC;QACjD,GAAG,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;IAC3B,CAAC,CAAC,CAAC;AACL,CAAC;AACD,8FAA8F;AAC9F,MAAM,mBAAmB,GAAG,kBAAkB,CAAC;AAE/C;;;;;;;;;GASG;AACH,KAAK,UAAU,eAAe,CAAC,OAAgB;IAC7C,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,OAAO,CAAC,CAAC;IACtC,MAAM,WAAW,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IACzD,IAAI,WAAW,EAAE,UAAU,CAAC,mBAAmB,CAAC;QAAE,OAAO,QAAQ,CAAC;IAClE,sGAAsG;IACtG,iGAAiG;IACjG,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,IAAI,CACrC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EACnC,GAAG,EAAE,CAAC,EAAE,CACT,CAAC;IACF,MAAM,MAAM,GAAG,GAAG,QAAQ,CAAC,MAAM,GAAG,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;IAC3F,MAAM,IAAI,KAAK,CAAC,gCAAgC,MAAM,KAAK,WAAW,IAAI,iBAAiB,yBAAyB,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AACjJ,CAAC;AAED;;;GAGG;AACH,SAAS,cAAc,CAAC,IAAY,EAAE,MAAoB;IACxD,OAAO,eAAe,CAAa,eAAe,CAAC,gBAAgB,CAAC,IAAI,GAAG,CAAC,IAAI,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC;AAC9H,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,eAAe,GAAG,OAAO,UAAU,KAAK,WAAW,IAAI,OAAO,aAAa,KAAK,WAAW,IAAI,eAAe,IAAI,aAAa,CAAC,SAAS,CAAC;AAEhJ;;;;;;;;;;;GAWG;AACH,IAAI,eAAe,EAAE,CAAC;IACpB,IAAI,CAAC;QACH,OAAO,CAAC,iBAAiB,GAAG,QAAQ,CAAC;IACvC,CAAC;IAAC,MAAM,CAAC;QACP,uGAAuG;QACvG,wEAAwE;IAC1E,CAAC;AACH,CAAC;AAKD;;;;GAIG;AACH,MAAM,eAAe,GAAG,IAAI,GAAG,EAAuB,CAAC;AAEvD,gEAAgE;AAChE,MAAM,kBAAkB,GAAG,eAAe,CAAC;AAE3C,sGAAsG;AACtG,MAAM,oBAAoB,GAAG,EAAE,CAAC;AAEhC,qGAAqG;AACrG,SAAS,eAAe;IACtB,OAAO,eAAe,CAAC,CAAC,CAAC,UAAU,CAAC,YAAY,EAAE,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC;AACpE,CAAC;AAED;;;;GAIG;AACH,SAAS,qBAAqB;IAC5B,MAAM,GAAG,GAAG,eAAe,EAAE,CAAC;IAC9B,IAAI,GAAG;QAAE,eAAe,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,CAAC,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC;AAC9E,CAAC;AAED,sFAAsF;AACtF,SAAS,cAAc,CAAC,GAAuB;IAC7C,OAAO,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,eAAe,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AAClE,CAAC;AAED;;;GAGG;AACH,SAAS,yBAAyB;IAChC,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,cAAc,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAAC;QACvD,IAAI,CAAC,GAAG;YAAE,OAAO;QACjB,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAgC,CAAC,EAAE,CAAC;YAC1F,IAAI,MAAM,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC;gBAAE,eAAe,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QAC9F,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,2GAA2G;QAC3G,4CAA4C;IAC9C,CAAC;AACH,CAAC;AAED,oGAAoG;AACpG,SAAS,sBAAsB;IAC7B,IAAI,CAAC;QACH,OAAO,eAAe,CAAC,IAAI,GAAG,oBAAoB,EAAE,CAAC;YACnD,MAAM,MAAM,GAAG,eAAe,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC;YACnD,IAAI,MAAM,KAAK,SAAS;gBAAE,MAAM;YAChC,eAAe,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QACjC,CAAC;QACD,cAAc,CAAC,OAAO,CAAC,kBAAkB,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,WAAW,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;IAClG,CAAC;IAAC,MAAM,CAAC;QACP,kFAAkF;IACpF,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,IAAI,eAAe,EAAE,CAAC;IACpB,MAAM,CAAC,gBAAgB,CAAC,UAAU,EAAE,GAAG,EAAE;QACvC,qBAAqB,EAAE,CAAC;QACxB,sBAAsB,EAAE,CAAC;IAC3B,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;GAGG;AACH,SAAS,MAAM,CAAC,MAAwB;IACtC,MAAM,MAAM,GAAG,GAAG,EAAE,GAAE,CAAC,CAAC;IACxB,KAAK,MAAM,CAAC,SAAS,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IACrC,KAAK,MAAM,CAAC,QAAQ,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;AACtC,CAAC;AAED;;;;GAIG;AACH,MAAM,kBAAkB,GAAG,MAAM,CAAC,4BAA4B,CAAC,CAAC;AAEhE;;;;;;;;;;;;;;GAcG;AACH,SAAS,YAAY,CAAC,IAAa;IACjC,IAAI,CAAC,eAAe,EAAE,CAAC;QACrB,IAAI,IAAI,KAAK,SAAS;YAAE,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC;;YAC5C,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAClC,OAAO;IACT,CAAC;IAED,MAAM,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,kBAAkB,EAAE,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,kBAAkB,EAAE,CAAC,CAAC,CAAC;AACzI,CAAC;AAED,4GAA4G;AAC5G,6GAA6G;AAC7G,0FAA0F;AAC1F,SAAS,IAAI,CAAC,IAAY;IACxB,IAAI,eAAe;QAAE,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAI,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC;;QACvE,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;AACpC,CAAC;AAED,SAAS,OAAO,CAAC,IAAY;IAC3B,IAAI,eAAe;QAAE,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAI,EAAE,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC;;QAC1E,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;AACrC,CAAC;AAED,2GAA2G;AAC3G,2GAA2G;AAC3G,SAAS,IAAI;IACX,IAAI,eAAe;QAAE,MAAM,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC,CAAC;;QAC1C,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;AAC7B,CAAC;AAED,SAAS,OAAO;IACd,IAAI,eAAe;QAAE,MAAM,CAAC,UAAU,CAAC,OAAO,EAAE,CAAC,CAAC;;QAC7C,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;AAChC,CAAC;AAED,8GAA8G;AAC9G,yEAAyE;AACzE,SAAS,OAAO;IACd,IAAI,eAAe;QAAE,MAAM,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC,CAAC;;QAC5C,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC;AAChC,CAAC;AAED,0GAA0G;AAC1G,MAAM,eAAe,GAAG,IAAI,CAAC;AAE7B,+GAA+G;AAC/G,MAAM,eAAe,GAAG,GAAW,EAAE,CAAC,yBAAyB,WAAW,EAAE,EAAE,CAAC;AAE/E;;;;;;;;;;;;;;GAcG;AACH,SAAS,yBAAyB;IAChC,MAAM,GAAG,GAAG,eAAe,EAAE,CAAC;IAC9B,IAAI,KAAc,CAAC;IACnB,IAAI,CAAC;QACH,KAAK,GAAG,cAAc,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,IAAI,CAAC;QAC7C,IAAI,CAAC,KAAK;YAAE,cAAc,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IAC/C,CAAC;IAAC,MAAM,CAAC;QACP,sGAAsG;QACtG,mGAAmG;QACnG,uDAAuD;QACvD,KAAK,GAAG,IAAI,CAAC;IACf,CAAC;IACD,IAAI,KAAK,EAAE,CAAC;QACV,gBAAgB,EAAE,CAAC;QACnB,OAAO;IACT,CAAC;IAED,YAAY,EAAE,CAAC;IAEf,wGAAwG;IACxG,sGAAsG;IACtG,0GAA0G;IAC1G,4EAA4E;IAC5E,UAAU,CAAC,GAAG,EAAE;QACd,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,qBAAqB,CAAC;YAAE,gBAAgB,EAAE,CAAC;IACzE,CAAC,EAAE,eAAe,CAAC,CAAC;AACtB,CAAC;AAED;;;;;;GAMG;AACH,SAAS,mBAAmB,CAAC,KAAc,EAAE,EAAE,IAAI,GAAG,KAAK,EAAE,GAAuB,EAAE;IACpF,MAAM,MAAM,GAAI,KAAqC,EAAE,MAAM,CAAC;IAC9D,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC;QAAE,OAAO,KAAK,CAAC;IAC3C,MAAM,QAAQ,GAAG,mBAAmB,CAAC,MAAM,CAAC,CAAC;IAC7C,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,yBAAyB,EAAE,CAAC;IAC9B,CAAC;SAAM,IAAI,IAAI,EAAE,CAAC;QAChB,wGAAwG;QACxG,YAAY,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC;IACtE,CAAC;SAAM,CAAC;QACN,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAC1B,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;;GAMG;AACH,SAAS,WAAW;IAClB,MAAM,CAAC,QAAQ,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC,CAAC;AAC5D,CAAC;AAED,2FAA2F;AAC3F,SAAS,aAAa,CAAC,KAAkB;IACvC,MAAM,CAAC,QAAQ,CAAC,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC,CAAC;AACxE,CAAC;AAED;;;;;;;;GAQG;AACH,SAAS,YAAY,CAAC,IAAY;IAChC,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IACxD,oGAAoG;IACpG,+CAA+C;IAC/C,IAAI,GAAG,KAAK,EAAE,EAAE,CAAC;QACf,WAAW,EAAE,CAAC;QACd,OAAO;IACT,CAAC;IACD,IAAI,EAAE,GAAG,GAAG,CAAC;IACb,IAAI,CAAC;QACH,EAAE,GAAG,kBAAkB,CAAC,GAAG,CAAC,CAAC;IAC/B,CAAC;IAAC,MAAM,CAAC;QACP,sFAAsF;IACxF,CAAC;IACD,MAAM,MAAM,GAAG,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC,IAAI,QAAQ,CAAC,iBAAiB,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IAChF,IAAI,MAAM;QAAE,MAAM,CAAC,cAAc,EAAE,CAAC;;QAC/B,WAAW,EAAE,CAAC;AACrB,CAAC;AAED;;;;;GAKG;AACH,SAAS,UAAU;IACjB,MAAM,SAAS,GAAG,QAAQ,CAAC,aAAa,CAAc,aAAa,CAAC,CAAC;IACrE,IAAI,SAAS;QAAE,SAAS,CAAC,KAAK,CAAC,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;;QACnD,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;AACpD,CAAC;AAED;;;;;;;;GAQG;AACH,IAAI,UAAU,GAAqE,GAAG,EAAE;IACtF,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC;IACzB,OAAO,IAAI,OAAO,CAAO,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;AACrC,CAAC,CAAC;AAEF,yGAAyG;AACzG,IAAI,QAAQ,GAA8C,CAAC,GAAG,EAAE,EAAE;IAChE,KAAK,GAAG,EAAE,CAAC;AACb,CAAC,CAAC;AAEF;;;;;;GAMG;AACH,IAAI,iBAAiB,GAAG,CAAC,CAAC;AAE1B,+EAA+E;AAC/E,IAAI,eAAe,GAA2B,IAAI,CAAC;AAEnD;;;;;;;GAOG;AACH,SAAS,WAAW,CAAC,GAAW,EAAE,MAAoB,EAAE,WAAwB;IAC9E,0GAA0G;IAC1G,0GAA0G;IAC1G,0DAA0D;IAC1D,MAAM,UAAU,GAAG,EAAE,iBAAiB,CAAC;IACvC,eAAe,EAAE,KAAK,EAAE,CAAC;IACzB,MAAM,UAAU,GAAG,CAAC,eAAe,GAAG,IAAI,eAAe,EAAE,CAAC,CAAC;IAC7D,MAAM,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC;IAExF,0GAA0G;IAC1G,4GAA4G;IAC5G,0GAA0G;IAC1G,yEAAyE;IACzE,IAAI,SAAoC,CAAC;IAEzC,MAAM,GAAG,GAAG,KAAK,IAAI,EAAE;QACrB,MAAM,OAAO,GAAG,MAAM,cAAc,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QACjD,qGAAqG;QACrG,0CAA0C;QAC1C,IAAI,KAAK,CAAC,OAAO,IAAI,UAAU,KAAK,iBAAiB;YAAE,OAAO;QAC9D,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;YACrB,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;YACvB,OAAO;QACT,CAAC;QACD,8FAA8F;QAC9F,oGAAoG;QACpG,KAAK,CAAC,eAAe,CAAC,GAAG,EAAE;YACzB,SAAS,GAAG,UAAU,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;QAC/C,CAAC,CAAC,CAAC;IACL,CAAC,CAAC;IAEF,2GAA2G;IAC3G,yFAAyF;IACzF,IAAI,IAAoB,CAAC;IACzB,QAAQ,CAAC,GAAG,EAAE,CAAC,CAAC,IAAI,GAAG,GAAG,EAAE,CAAC,CAAC,CAAC;IAE/B,OAAO,IAAI,CAAC,IAAI;IACd,4GAA4G;IAC5G,GAAG,EAAE,CAAC,SAAS,EACf,CAAC,KAAc,EAAE,EAAE;QACjB,iGAAiG;QACjG,gCAAgC;QAChC,IAAI,KAAK,CAAC,OAAO,IAAI,UAAU,KAAK,iBAAiB,IAAI,mBAAmB,CAAC,KAAK,CAAC;YAAE,OAAO;QAC5F,MAAM,KAAK,CAAC;IACd,CAAC,CACF,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,SAAS,UAAU,CAAC,IAAY;IAC9B,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC;IAClE,OAAO,WAAW,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;AACnC,CAAC;AAED;;;;;;;;;;GAUG;AACH,SAAS,cAAc,CAAC,KAAoB;IAC1C,OAAO,CACL,KAAK,CAAC,UAAU;QAChB,KAAK,CAAC,eAAe,KAAK,IAAI;QAC9B,KAAK,CAAC,QAAQ,KAAK,IAAI;QACvB,KAAK,CAAC,aAAa,EAAE,YAAY,CAAC,aAAa,CAAC,KAAK,IAAI;QACzD,UAAU,CAAC,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC,CAClC,CAAC;AACJ,CAAC;AAED;;;;;;;;GAQG;AACH,SAAS,gBAAgB;IACvB,IAAI,CAAC,eAAe;QAAE,OAAO,GAAG,EAAE,GAAE,CAAC,CAAC;IAEtC,MAAM,UAAU,GAAG,CAAC,KAAoB,EAAE,EAAE;QAC1C,uGAAuG;QACvG,sGAAsG;QACtG,uDAAuD;QACvD,IAAI,KAAK,CAAC,IAAI,KAAK,kBAAkB;YAAE,OAAO;QAE9C,yGAAyG;QACzG,wGAAwG;QACxG,oEAAoE;QACpE,qBAAqB,EAAE,CAAC;QAExB,IAAI,CAAC,KAAK,CAAC,YAAY,IAAI,cAAc,CAAC,KAAK,CAAC;YAAE,OAAO;QAEzD,yGAAyG;QACzG,mFAAmF;QACnF,0GAA0G;QAC1G,uGAAuG;QACvG,uGAAuG;QACvG,IAAI,KAAK,CAAC,cAAc,KAAK,UAAU;YAAE,OAAO;QAEhD,oGAAoG;QACpG,0FAA0F;QAC1F,sGAAsG;QACtG,sGAAsG;QACtG,wGAAwG;QACxG,iEAAiE;QACjE,MAAM,OAAO,GAAG,KAAK,CAAC,cAAc,KAAK,SAAS,IAAI,KAAK,CAAC,cAAc,KAAK,QAAQ,CAAC;QACxF,IAAI,WAAqC,CAAC;QAC1C,IAAI,KAAK,CAAC,cAAc,KAAK,MAAM,EAAE,CAAC;YACpC,MAAM,EAAE,IAAI,EAAE,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;YAChD,WAAW,GAAG,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;QACrE,CAAC;QAED,KAAK,CAAC,SAAS,CAAC;YACd,MAAM,EAAE,QAAQ;YAChB,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,kBAAkB;YACnD,qGAAqG;YACrG,0EAA0E;YAC1E,OAAO,EAAE,GAAG,EAAE,CAAC,WAAW,CAAC,KAAK,CAAC,WAAW,CAAC,GAAG,EAAE,KAAK,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,YAAY,EAAE,CAAC;SACzG,CAAC,CAAC;IACL,CAAC,CAAC;IAEF;;;;OAIG;IACH,MAAM,UAAU,GAAG,GAAG,EAAE;QACtB,MAAM,MAAM,GAAG,cAAc,CAAC,eAAe,EAAE,CAAC,CAAC;QACjD,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC;QAC3B,MAAM,KAAK,GAAG,GAAG,EAAE;YACjB,IAAI,MAAM;gBAAE,aAAa,CAAC,MAAM,CAAC,CAAC;iBAC7B,IAAI,IAAI,KAAK,EAAE;gBAAE,YAAY,CAAC,IAAI,CAAC,CAAC;;gBACpC,WAAW,EAAE,CAAC;QACrB,CAAC,CAAC;QAEF,wGAAwG;QACxG,yGAAyG;QACzG,yGAAyG;QACzG,2EAA2E;QAC3E,IAAI,WAAW,EAAE,KAAK,WAAW,EAAE,CAAC;YAClC,KAAK,EAAE,CAAC;YACR,OAAO;QACT,CAAC;QAED,KAAK,WAAW,CAAC,QAAQ,CAAC,IAAI,EAAE,SAAS,EAAE,GAAG,EAAE;YAC9C,KAAK,EAAE,CAAC;YACR,oGAAoG;YACpG,yFAAyF;YACzF,UAAU,EAAE,CAAC;QACf,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,YAAY,EAAE,CAAC,CAAC;IACjC,CAAC,CAAC;IAEF,UAAU,CAAC,gBAAgB,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;IACpD,MAAM,CAAC,gBAAgB,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;IAChD,OAAO,GAAG,EAAE;QACV,UAAU,CAAC,mBAAmB,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;QACvD,MAAM,CAAC,mBAAmB,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;IACrD,CAAC,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,IAAI;IACjB,sGAAsG;IACtG,wGAAwG;IACxG,qFAAqF;IACrF,4EAA4E;IAC5E,MAAM,OAAO,GAAG,QAAQ,CAAC,aAAa,CAAC,4BAA4B,CAA2B,CAAC;IAC/F,IAAI,OAAO,EAAE,KAAK;QAAE,iBAAiB,GAAG,OAAO,CAAC,KAAK,CAAC;IAEtD,MAAM,cAAc,GAAG,MAAM,wBAAwB,CAAa,YAAY,CAAC,CAAC;IAEhF,yGAAyG;IACzG,2GAA2G;IAC3G,6GAA6G;IAC7G,sFAAsF;IACtF,EAAE;IACF,2GAA2G;IAC3G,0GAA0G;IAC1G,qFAAqF;IACrF,IAAI,cAAc,CAAC,QAAQ,EAAE,CAAC;QAC5B,IAAI,CAAC;YACH,cAAc,CAAC,UAAU,CAAC,eAAe,EAAE,CAAC,CAAC;QAC/C,CAAC;QAAC,MAAM,CAAC;YACP,8FAA8F;QAChG,CAAC;IACH,CAAC;IAED,yGAAyG;IACzG,yGAAyG;IACzG,2GAA2G;IAC3G,0CAA0C;IAC1C,IAAI,eAAe;QAAE,yBAAyB,EAAE,CAAC;IACjD,MAAM,QAAQ,GAAG,cAAc,CAAC,eAAe,EAAE,CAAC,CAAC;IAEnD,SAAS,WAAW;QAClB,MAAM,CAAC,OAAO,EAAE,eAAe,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC;QAClE,MAAM,CAAC,OAAO,EAAE,eAAe,CAAC,GAAG,KAAK,CAAC,aAAa,EAAE,CAAC;QACzD,2EAA2E;QAC3E,MAAM,aAAa,GAAG,KAAK,CAAC,MAAM,CAAsB,IAAI,CAAC,CAAC;QAC9D,sGAAsG;QACtG,yGAAyG;QACzG,mGAAmG;QACnG,MAAM,aAAa,GAAG,KAAK,CAAC,MAAM,CAAsB,QAAQ,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QAEzG,2FAA2F;QAC3F,2FAA2F;QAC3F,KAAK,CAAC,eAAe,CAAC,GAAG,EAAE;YACzB,UAAU,GAAG,CAAC,IAAI,EAAE,WAAW,EAAE,EAAE,CACjC,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;gBAC5B,gGAAgG;gBAChG,2FAA2F;gBAC3F,aAAa,CAAC,OAAO,EAAE,EAAE,CAAC;gBAC1B,aAAa,CAAC,OAAO,GAAG,OAAO,CAAC;gBAChC,yFAAyF;gBACzF,4FAA4F;gBAC5F,aAAa,CAAC,OAAO,GAAG,WAAW,IAAI,IAAI,CAAC;gBAC5C,eAAe,CAAC,IAAI,CAAC,CAAC;YACxB,CAAC,CAAC,CAAC;YACL,QAAQ,GAAG,CAAC,GAAG,EAAE,EAAE,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC;QAC3C,CAAC,EAAE,CAAC,eAAe,CAAC,CAAC,CAAC;QAEtB;;;WAGG;QACH,KAAK,CAAC,eAAe,CAAC,GAAG,EAAE;YACzB,MAAM,MAAM,GAAG,aAAa,CAAC,OAAO,CAAC;YACrC,aAAa,CAAC,OAAO,GAAG,IAAI,CAAC;YAC7B,MAAM,EAAE,EAAE,CAAC;YACX,oGAAoG;YACpG,iFAAiF;YACjF,WAAW,GAAG,WAAW,EAAE,CAAC;YAC5B,MAAM,MAAM,GAAG,aAAa,CAAC,OAAO,CAAC;YACrC,aAAa,CAAC,OAAO,GAAG,IAAI,CAAC;YAC7B,MAAM,EAAE,EAAE,CAAC;QACb,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;QAEd,iGAAiG;QACjG,KAAK,CAAC,eAAe,CAAC,GAAG,EAAE,CAAC,gBAAgB,EAAE,EAAE,EAAE,CAAC,CAAC;QAEpD,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO,CAAmB,GAAG,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;QAEtH,OAAO,KAAC,aAAa,CAAC,QAAQ,IAAC,KAAK,EAAE,MAAM,YAAG,OAAO,CAAC,IAAI,GAA0B,CAAC;IACxF,CAAC;IAED,iBAAiB,CAAC,KAAK,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE;QACnC,MAAM,mBAAmB,GAAG,2BAA2B,EAAE,CAAC;QAC1D,uGAAuG;QACvG,yGAAyG;QACzG,wGAAwG;QACxG,wBAAwB;QACxB,MAAM,UAAU,GAAG,WAAW,EAAE,CAAC;QACjC,MAAM,OAAO,GAAG,gBAAgB,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE;YACrD,EAAE;YACF,IAAI,EAAE,MAAM,WAAW,CAAC,IAAI,EAAE,EAAE,mBAAmB,EAAE,CAAC;SACvD,CAAC,CAAC;QACH,IAAI,OAAmB,CAAC;QACxB,IAAI,CAAC;YACH,OAAO,GAAG,MAAM,eAAe,CAAa,eAAe,CAAC,OAAO,CAAC,EAAE,EAAE,mBAAmB,EAAE,CAAC,CAAC;QACjG,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,mBAAmB,CAAC,KAAK,CAAC;gBAAE,OAAO,SAAS,CAAC;YACjD,MAAM,KAAK,CAAC;QACd,CAAC;QACD,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;YACrB,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;YACvB,OAAO,SAAS,CAAC;QACnB,CAAC;QACD,IAAI,WAAW,EAAE,KAAK,UAAU;YAAE,KAAK,CAAC,eAAe,CAAC,GAAG,EAAE,CAAC,KAAK,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC;QACxF,IAAI,OAAO,CAAC,QAAQ;YAAE,OAAO,SAAS,CAAC;QACvC,MAAM,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;QACnC,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,oGAAoG;YACpG,qGAAqG;YACrG,gGAAgG;YAChG,iGAAiG;YACjG,eAAe;YACf,EAAE;YACF,sGAAsG;YACtG,sGAAsG;YACtG,gGAAgG;YAChG,kGAAkG;YAClG,mGAAmG;YACnG,sGAAsG;YACtG,4DAA4D;YAC5D,MAAM,IAAI,KAAK,CACb,kJAAkJ,CACnJ,CAAC;QACJ,CAAC;QACD,IAAI,CAAC,MAAM,CAAC,EAAE;YAAE,MAAM,MAAM,CAAC,KAAK,CAAC;QACnC,OAAO,MAAM,CAAC,KAAK,CAAC;IACtB,CAAC,CAAC,CAAC;IAEH,4GAA4G;IAC5G,qGAAqG;IACrG,EAAE;IACF,4GAA4G;IAC5G,qGAAqG;IACrG,WAAW,CAAC,QAAQ,EAAE,KAAC,WAAW,KAAG,EAAE;QACrC,SAAS,EAAE,cAAc,CAAC,SAAS;QACnC,aAAa,EAAE,CAAC,KAAK,EAAE,SAAS,EAAE,EAAE;YAClC,IAAI,mBAAmB,CAAC,KAAK,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;gBAAE,OAAO;YACvD,2FAA2F;YAC3F,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,SAAS,CAAC,cAAc,IAAI,EAAE,CAAC,CAAC;QACvD,CAAC;QACD,eAAe,EAAE,CAAC,KAAK,EAAE,SAAS,EAAE,EAAE;YACpC,IAAI,mBAAmB,CAAC,KAAK,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;gBAAE,OAAO;YACvD,gFAAgF;YAChF,UAAU,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;YAC9B,SAAS,CAAC,KAAK,EAAE,SAAS,CAAC,cAAc,CAAC,CAAC;QAC7C,CAAC;KACF,CAAC,CAAC;IAEH,IAAI,OAAO,IAAI,CAAC,UAAU,EAAE,CAAC;QAC3B,cAAc,EAAE,CAAC;IACnB,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACH,SAAS,cAAc;IACrB,MAAM,GAAG,GAAG,OAAO,IAAI,CAAC,UAAW,CAAC;IACpC,IAAI,aAAa,GAAG,KAAK,CAAC;IAC1B,oGAAoG;IACpG,IAAI,UAA8B,CAAC;IAEnC,SAAS,MAAM,CAAC,MAAc,EAAE,KAAe;QAC7C,OAAO,CAAC,IAAI,CAAC,YAAY,MAAM,cAAc,EAAE,GAAG,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QACxF,YAAY,EAAE,CAAC;IACjB,CAAC;IAED,KAAK,UAAU,iBAAiB;QAC9B,MAAM,MAAM,GAAG,MAAM,cAAc,CACjC,GAAG,EACH,GAAG,EAAE,CAAC,gBAAgB,EACtB,GAAG,EAAE,CAAC,UAAU,CACjB,CAAC;QACF,IAAI,MAAM;YAAE,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;IAClD,CAAC;IAED,KAAK,UAAU,MAAM,CAAC,OAAmB;QACvC,QAAQ,OAAO,CAAC,IAAI,EAAE,CAAC;YACrB,KAAK,OAAO;gBACV,UAAU,GAAG,OAAO,CAAC,IAAI,IAAI,UAAU,CAAC;gBACxC,IAAI,aAAa,EAAE,CAAC;oBAClB,MAAM,iBAAiB,EAAE,CAAC;oBAC1B,MAAM,WAAW,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,YAAY,EAAE,CAAC,CAAC;gBACtE,CAAC;gBACD,aAAa,GAAG,IAAI,CAAC;gBACrB,MAAM;YACR,KAAK,cAAc;gBACjB,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;gBAC1B,MAAM,iBAAiB,EAAE,CAAC;gBAC1B,MAAM;YACR,KAAK,YAAY;gBACf,OAAO,CAAC,GAAG,CAAC,oCAAoC,CAAC,CAAC;gBAClD,MAAM,WAAW,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,YAAY,EAAE,CAAC,CAAC;gBACpE,MAAM;QACV,CAAC;IACH,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,WAAW,CAAC,cAAc,CAAC,CAAC;IAC/C,yGAAyG;IACzG,0GAA0G;IAC1G,qEAAqE;IACrE,IAAI,KAAK,GAAkB,OAAO,CAAC,OAAO,EAAE,CAAC;IAC7C,MAAM,CAAC,SAAS,GAAG,CAAC,KAA2B,EAAE,EAAE;QACjD,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAe,CAAC;QACrD,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,MAAM,CAAC,uBAAuB,EAAE,KAAK,CAAC,CAAC,CAAC;IACrG,CAAC,CAAC;AACJ,CAAC;AAED,mGAAmG;AACnG,kFAAkF;AAClF,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IACrB,OAAO,CAAC,KAAK,CAAC,8CAA8C,EAAE,KAAK,CAAC,CAAC;IACrE,SAAS,CAAC,KAAK,CAAC,CAAC;AACnB,CAAC,CAAC,CAAC","sourcesContent":["import React from 'react';\nimport { hydrateRoot } from 'react-dom/client';\nimport {\n createFromFetch,\n createFromReadableStream,\n createTemporaryReferenceSet,\n encodeReply,\n setServerCallback,\n} from 'react-server-dom-rspack/client.browser';\nimport { isControlDigest, parseRedirectDigest } from './control.js';\nimport type { DevMessage } from './dev-protocol.js';\nimport type { RscPayload } from './entry.rsc.js';\n// Dev-only: its one caller sits behind `import.meta.webpackHot`, which a production build compiles to\n// `false` — so this module is dropped there.\nimport { walkHotUpdates } from './hot-update.js';\nimport { RouterContext, type NavigationRouter } from './navigation.js';\nimport { createRscRequest } from './request.js';\n\nconst isDev = process.env.NODE_ENV === 'development';\n\ndeclare global {\n /** The array the payload `<script>` tags `flight-inject.ts` emits push their chunks into. */\n var __FLIGHT_DATA: Array<string | Uint8Array> | undefined;\n}\n\n/** The flight payload the document carried, read back out of `__FLIGHT_DATA` — see `flight-inject.ts`. */\nfunction readFlightPayload(): ReadableStream<Uint8Array> {\n const encoder = new TextEncoder();\n // Assigned synchronously by `start`, which `new ReadableStream` runs before it returns.\n let controller!: ReadableStreamDefaultController<Uint8Array>;\n const stream = new ReadableStream<Uint8Array>({\n start: (c) => void (controller = c),\n });\n const enqueue = (chunk: string | Uint8Array) => controller.enqueue(typeof chunk === 'string' ? encoder.encode(chunk) : chunk);\n\n // Payload scripts interleave with the document: the ones that already ran are in the array, the rest\n // arrive through `push`.\n const data = (self.__FLIGHT_DATA ??= []);\n for (const chunk of data) enqueue(chunk);\n data.push = enqueue as typeof data.push;\n\n // The last payload script lands before parsing finishes, so that is what closes the stream.\n if (document.readyState === 'loading') {\n document.addEventListener('DOMContentLoaded', () => controller.close(), { once: true });\n } else {\n controller.close();\n }\n return stream;\n}\n\n/** Created at module evaluation, not inside `main()`, so no chunk can be pushed before it is watching. */\nconst flightStream = readFlightPayload();\n\n/**\n * The part of the location a payload is rendered for — the document, without the fragment, which the server\n * never sees. Two URLs that differ only by `#hash` describe the same payload.\n */\nconst documentUrl = (): string => location.pathname + location.search;\n\n/**\n * The document URL the payload on screen was rendered for — see {@link documentUrl}. A fragment-only\n * traversal leaves it unchanged, which is how the `popstate` listener knows there is nothing to fetch.\n * Updated in the layout effect that commits a payload.\n */\nlet renderedUrl = documentUrl();\n\n/** Guarantees somewhere to attach the fatal overlay: the root container is `document`, so a teardown can take `<body>` with it. */\nfunction overlayHost(): HTMLElement {\n if (!document.documentElement) document.appendChild(document.createElement('html'));\n if (!document.body) document.documentElement.appendChild(document.createElement('body'));\n return document.body;\n}\n\n/**\n * Paints a full-viewport panel over whatever is on screen, and returns the box for the caller to fill.\n *\n * DOM calls rather than React (one caller runs because the renderer just failed), and `textContent` rather\n * than `innerHTML` (an error message is untrusted input). Queued on a macrotask: React's teardown runs after\n * the callback that reaches here returns, and would remove a node appended inline.\n */\nfunction paintOverlay(fill: (box: HTMLElement) => void): void {\n setTimeout(() => {\n const host = overlayHost();\n host.querySelector('[data-rshono-fatal]')?.remove();\n\n const box = document.createElement('div');\n box.setAttribute('data-rshono-fatal', '');\n box.setAttribute('role', 'alert');\n box.style.cssText =\n 'position:fixed;inset:0;z-index:2147483647;overflow:auto;padding:1.5rem;background:#18181b;color:#f4f4f5;' +\n 'font:14px/1.6 ui-monospace,SFMono-Regular,Menlo,monospace;text-align:left';\n\n fill(box);\n host.appendChild(box);\n }, 0);\n}\n\n/** The overlay's heading. */\nfunction overlayTitle(text: string): HTMLElement {\n const title = document.createElement('div');\n title.textContent = text;\n title.style.cssText = 'font-size:1.0625rem;font-weight:700;color:#f87171;margin:0 0 0.75rem';\n return title;\n}\n\n/**\n * Paints the reason for an uncaught render error over the blank page it leaves behind — the full stack in\n * dev, a generic notice and a reload button in production.\n */\nfunction showFatal(error: unknown, componentStack?: string | null): void {\n paintOverlay((box) => {\n box.appendChild(overlayTitle(isDev ? 'Unhandled error' : 'Something went wrong'));\n\n if (isDev) {\n const detail = document.createElement('pre');\n detail.style.cssText = 'margin:0;white-space:pre-wrap;word-break:break-word';\n detail.textContent =\n (error instanceof Error ? (error.stack ?? `${error.name}: ${error.message}`) : String(error)) +\n (componentStack ? `\\n\\nComponent stack:${componentStack}` : '');\n box.appendChild(detail);\n } else {\n const message = document.createElement('p');\n message.textContent = 'This page hit an unexpected error and can’t continue.';\n message.style.cssText = 'margin:0 0 1rem;color:#d4d4d8';\n box.appendChild(message);\n }\n\n const reload = document.createElement('button');\n reload.textContent = 'Reload page';\n reload.style.cssText =\n 'margin-top:1.25rem;padding:0.5rem 1rem;font:inherit;color:#18181b;background:#f4f4f5;border:0;border-radius:4px;cursor:pointer';\n reload.addEventListener('click', () => loadDocument());\n box.appendChild(reload);\n });\n}\n\n/**\n * The end of the line for a `notFound()` that arrived too late to be a 404 and did not survive a reload.\n *\n * No reload button, unlike {@link showFatal}: the reload has already been spent, and the second identical\n * response is what brought us here. \"Page not found\" is what the server was trying to say, so it is what the\n * visitor is told; the reason it could not say it properly is a message for whoever wrote the page, and dev is\n * where they are.\n */\nfunction showLateNotFound(): void {\n paintOverlay((box) => {\n box.appendChild(overlayTitle('Page not found'));\n\n const message = document.createElement('p');\n message.textContent = isDev\n ? 'notFound() was raised from a boundary that resolved after the page shell had been sent, so the response ' +\n 'could not be a 404 — and reloading rendered the same page again. Decide before the render starts ' +\n 'streaming: in Hono middleware, or in the page component body above the boundary.'\n : 'This page is not available.';\n message.style.cssText = 'margin:0;color:#d4d4d8';\n box.appendChild(message);\n });\n}\n/** What every flight response is typed as. The charset and any other parameters follow it. */\nconst FLIGHT_CONTENT_TYPE = 'text/x-component';\n\n/**\n * Fetches a payload, refusing a response that is not one.\n *\n * The status cannot be the gate: a payload legitimately arrives as a 404 from the `notFound` page and as a\n * 500 from an action that threw, and both carry a real payload the caller has to see. The content type is.\n *\n * What this catches is the response that is not a payload at all — a `bodyLimit()` 413, a proxy's error page,\n * a 502 mid-deploy. Handed to the flight parser those all surface as `Error: Connection closed.`, with the\n * status and the body nowhere in sight; here they become an error that says what arrived.\n */\nasync function payloadResponse(request: Request): Promise<Response> {\n const response = await fetch(request);\n const contentType = response.headers.get('content-type');\n if (contentType?.startsWith(FLIGHT_CONTENT_TYPE)) return response;\n // Read for the message: a plain-text refusal says what it refused only in its body, and HTTP/2 has no\n // `statusText` at all. Bounded, because this is an error path and the body is not ours to trust.\n const body = await response.text().then(\n (text) => text.trim().slice(0, 200),\n () => '',\n );\n const status = `${response.status}${response.statusText ? ` ${response.statusText}` : ''}`;\n throw new Error(`[rshono] the server answered ${status} (${contentType ?? 'no content type'}) instead of a payload${body ? `: ${body}` : ''}`);\n}\n\n/**\n * Asks a URL for its flight payload. Deliberately uncached — a payload can never be staler than the click\n * that wanted it, and the browser's own HTTP cache is what makes a repeat visit cheap.\n */\nfunction requestPayload(href: string, signal?: AbortSignal): Promise<RscPayload> {\n return createFromFetch<RscPayload>(payloadResponse(createRscRequest(new URL(href, location.href).href, undefined, signal)));\n}\n\n/**\n * Whether the browser hands us its navigations. Gated on `sourceElement` rather than on `navigation` itself:\n * Chrome shipped the event in 102 and that property only in 135, and without it a `data-native` link cannot\n * be told from any other — so the older window would soft-navigate the very links that asked not to be.\n *\n * Where this is false there is no interception at all and every navigation is a real browser load, which a\n * server-rendered app answers correctly on its own. Only the soft part is missing.\n *\n * Both globals are tested, and neither is touched before: this runs at module scope, where a ReferenceError\n * would take the whole client runtime down with it rather than degrading anything.\n */\nconst canSoftNavigate = typeof navigation !== 'undefined' && typeof NavigateEvent !== 'undefined' && 'sourceElement' in NavigateEvent.prototype;\n\n/**\n * The runtime owns a soft navigation's scroll, so the browser's own restoration has to be off: left on, a\n * traversal restores the destination's offset against the outgoing tree before the payload for that entry\n * has even been asked for, and the incoming tree overwrites it. `manual` only concerns the entries this\n * document creates — a navigation to another document creates its own entry `auto` — and it also turns the\n * browser's reload restoration off, which {@link readStoredScrollPositions} and the first layout effect put\n * back.\n *\n * Gated on the soft router: below the Navigation API floor every navigation is a real document load, which\n * a server-rendered app answers correctly and the browser restores correctly, and taking that over without\n * a router to repaint the entry would strand the visitor at the top.\n */\nif (canSoftNavigate) {\n try {\n history.scrollRestoration = 'manual';\n } catch {\n // A preference, not a requirement: where it cannot be set, the browser's restoration and the runtime's\n // own can race on a traversal, and the runtime's runs at commit, after.\n }\n}\n\n/** A scroll offset, in the coordinates `window.scrollTo` takes and `window.scrollX`/`window.scrollY` return. */\ntype ScrollPoint = { x: number; y: number };\n\n/**\n * Where each history entry of this document was left, keyed by its Navigation API key. In memory for the\n * document's life; {@link persistScrollPositions} also writes it to `sessionStorage` so a reload — which\n * the `manual` mode above stops the browser restoring — lands where the last document was left.\n */\nconst scrollPositions = new Map<string, ScrollPoint>();\n\n/** The `sessionStorage` key holding {@link scrollPositions}. */\nconst SCROLL_STORAGE_KEY = 'rshono:scroll';\n\n/** How many entries are kept in that snapshot; the oldest falls out first — `Map` iteration order. */\nconst SCROLL_STORAGE_LIMIT = 50;\n\n/** The key of the history entry being shown, or `undefined` where the soft router does not exist. */\nfunction currentEntryKey(): string | undefined {\n return canSoftNavigate ? navigation.currentEntry?.key : undefined;\n}\n\n/**\n * Records where the outgoing entry is being left. Read at `navigate` time — before the browser commits the\n * new entry — and at `pagehide`, so whatever the navigation turns out to be, the entry it leaves has a\n * position to come back to.\n */\nfunction rememberCurrentScroll(): void {\n const key = currentEntryKey();\n if (key) scrollPositions.set(key, { x: window.scrollX, y: window.scrollY });\n}\n\n/** The position `key` was left at, or `undefined` when this document never saw it. */\nfunction scrollPointFor(key: string | undefined): ScrollPoint | undefined {\n return key === undefined ? undefined : scrollPositions.get(key);\n}\n\n/**\n * Reads the last document's snapshot back into {@link scrollPositions}. Called once, on startup, before the\n * first payload commits: the in-memory map alone would lose every entry the moment the document is replaced.\n */\nfunction readStoredScrollPositions(): void {\n try {\n const raw = sessionStorage.getItem(SCROLL_STORAGE_KEY);\n if (!raw) return;\n for (const [key, point] of Object.entries(JSON.parse(raw) as Record<string, ScrollPoint>)) {\n if (Number.isFinite(point?.x) && Number.isFinite(point?.y)) scrollPositions.set(key, point);\n }\n } catch {\n // Blocked site data, or a snapshot written by a different version. Either way there is nothing to restore,\n // and the page is still correct without it.\n }\n}\n\n/** Writes {@link scrollPositions} out, oldest first, bounded — see {@link SCROLL_STORAGE_LIMIT}. */\nfunction persistScrollPositions(): void {\n try {\n while (scrollPositions.size > SCROLL_STORAGE_LIMIT) {\n const oldest = scrollPositions.keys().next().value;\n if (oldest === undefined) break;\n scrollPositions.delete(oldest);\n }\n sessionStorage.setItem(SCROLL_STORAGE_KEY, JSON.stringify(Object.fromEntries(scrollPositions)));\n } catch {\n // Blocked site data: the in-memory map still carries this document's navigations.\n }\n}\n\n/**\n * The snapshot starts with the document, not with hydration: the page is visible and clickable while the\n * initial payload streams, and a reload or a navigation away in that window would otherwise lose the offset\n * now that `manual` has stopped the browser restoring it. Nothing here depends on the router being mounted,\n * so it does not wait for {@link listenNavigation}.\n */\nif (canSoftNavigate) {\n window.addEventListener('pagehide', () => {\n rememberCurrentScroll();\n persistScrollPositions();\n });\n}\n\n/**\n * Drops a navigation's result promises. Both reject when a navigation is superseded or cancelled — routine\n * here, since a second click is meant to abandon the first — and unhandled they would be reported as faults.\n */\nfunction settle(result: NavigationResult): void {\n const ignore = () => {};\n void result.committed?.catch(ignore);\n void result.finished?.catch(ignore);\n}\n\n/**\n * The mark {@link loadDocument} puts on its navigations, so the `navigate` listener below recognizes them as\n * the runtime's own. A symbol because the identity has to survive the trip through the browser intact:\n * `NavigateEvent.info` hands the value back by reference, so only the navigation that was given it matches.\n */\nconst documentNavigation = Symbol('rshono:document-navigation');\n\n/**\n * Performs a navigation the router below must **not** intercept, and returns having asked for it.\n *\n * `listenNavigation` intercepts a `reload` on purpose — that is what `router.refresh()` is — and every caller\n * here is reaching for a *new document* precisely because the current one cannot be repaired: the React root\n * a soft load would render into is the thing that just failed, or is about to be torn down. Intercepted, the\n * escape hatch becomes a payload fetch that lands nowhere — which is how a late `notFound()` left the tab on\n * its Suspense fallback with no second document ever arriving, and how a late `redirect()` moved the address\n * bar to a page it then failed to render.\n *\n * The mark rides the navigation itself, through `info`, so the listener recognizes the event that owns it\n * instead of consuming a flag set in advance. There is no state to clear and none to leak: a navigation the\n * browser refuses cannot make the next one a full load. Below the Navigation API there is no interception to\n * opt out of, and `location.*` is already a document load.\n */\nfunction loadDocument(href?: string): void {\n if (!canSoftNavigate) {\n if (href === undefined) window.location.reload();\n else window.location.assign(href);\n return;\n }\n\n settle(href === undefined ? navigation.reload({ info: documentNavigation }) : navigation.navigate(href, { info: documentNavigation }));\n}\n\n// The imperative actions behind `useNavigation().router`. Each one only *asks*: the browser turns it into a\n// `navigate` event, which is where `listenNavigation` answers it — so a `router.push` and a link click reach\n// the same code by the same route, and inherit the same fetch, scroll and `pending` flag.\nfunction push(href: string): void {\n if (canSoftNavigate) settle(navigation.navigate(href, { history: 'push' }));\n else window.location.assign(href);\n}\n\nfunction replace(href: string): void {\n if (canSoftNavigate) settle(navigation.navigate(href, { history: 'replace' }));\n else window.location.replace(href);\n}\n\n// A traversal is the browser's to perform either way — `navigation` only hands it back as an interceptable\n// event first. Nothing to go back to is a rejection there and a no-op here; both amount to the same thing.\nfunction back(): void {\n if (canSoftNavigate) settle(navigation.back());\n else window.history.back();\n}\n\nfunction forward(): void {\n if (canSoftNavigate) settle(navigation.forward());\n else window.history.forward();\n}\n\n// A refresh keeps the URL, and is still a navigation: it arrives as `navigationType: 'reload'`, which is what\n// tells the listener to leave scroll and focus where the user left them.\nfunction refresh(): void {\n if (canSoftNavigate) settle(navigation.reload());\n else window.location.reload();\n}\n\n/** How long the recovery reload is given to replace this document before the panel is painted instead. */\nconst RELOAD_GRACE_MS = 2000;\n\n/** The `sessionStorage` key bounding the recovery reload for one URL. Spent here, released in {@link main}. */\nconst lateNotFoundKey = (): string => `rshono:late-not-found:${documentUrl()}`;\n\n/**\n * Spends the one reload a late `notFound()` gets, or paints if it has already been spent for this URL.\n *\n * `redirect()` is terminal on the client — there is somewhere to navigate to — and `notFound()` is not: the\n * response is already committed as a 200, so the only recovery left is asking for the page again and hoping\n * the signal comes early enough this time to be a real 404. That works where the lateness was incidental, a\n * boundary that happened to resolve after the shell on a slow request. Where it is structural — a page that\n * always signals from a late boundary — the reload gets a byte-identical response and reloads again, and the\n * tab spins until the visitor leaves. In production nothing is logged, because the warning that explains this\n * is `isDev`-only.\n *\n * So it is bounded: one reload per URL per tab, then {@link showLateNotFound}. `sessionStorage` because the\n * value has to outlive the document it is written in and must not outlive the tab, and keyed by URL so a\n * second page's late signal still gets its own attempt.\n */\nfunction reloadOnceForLateNotFound(): void {\n const key = lateNotFoundKey();\n let spent: boolean;\n try {\n spent = sessionStorage.getItem(key) !== null;\n if (!spent) sessionStorage.setItem(key, '1');\n } catch {\n // Storage can throw outright where site data is blocked, and a page that cannot count its reloads has\n // to pick a side. It picks the terminating one: a message on a page that might have recovered is a\n // worse outcome than a reload loop only by a lot less.\n spent = true;\n }\n if (spent) {\n showLateNotFound();\n return;\n }\n\n loadDocument();\n\n // The reload wins this race whenever it happens at all: the document goes away and takes the timer with\n // it. What this covers is a reload that does not happen — swallowed by an interceptor, refused by the\n // browser, held by a `beforeunload` — which used to leave the visitor on a Suspense fallback with nothing\n // coming and nothing said. The panel is the honest answer in that case too.\n setTimeout(() => {\n if (!document.querySelector('[data-rshono-fatal]')) showLateNotFound();\n }, RELOAD_GRACE_MS);\n}\n\n/**\n * Turns a control-signal digest — how `redirect()` / `notFound()` reach the browser — into a real\n * navigation. Returns false for anything else, so callers fall through to their own handling.\n *\n * `hard` forces a full document load, for signals that surfaced *through React*: it unmounts the root on\n * an uncaught error, leaving no live tree to soft-navigate with.\n */\nfunction handleControlDigest(error: unknown, { hard = false }: { hard?: boolean } = {}): boolean {\n const digest = (error as { digest?: unknown } | null)?.digest;\n if (!isControlDigest(digest)) return false;\n const redirect = parseRedirectDigest(digest);\n if (!redirect) {\n reloadOnceForLateNotFound();\n } else if (hard) {\n // The URL is resolved first: a malformed location then throws here, before any navigation is asked for.\n loadDocument(new URL(redirect.location, window.location.href).href);\n } else {\n push(redirect.location);\n }\n return true;\n}\n\n/**\n * Scrolls the document to its start.\n *\n * The options form rather than `scrollTo(0, 0)`: the two-argument call is `auto`, which follows a\n * `scroll-behavior` the app may have set on `html`, and a soft navigation that animates its own reset reads\n * as a glitch rather than a page change.\n */\nfunction scrollToTop(): void {\n window.scrollTo({ top: 0, left: 0, behavior: 'instant' });\n}\n\n/** Puts a saved offset back. Instant for the same reason {@link scrollToTop} passes it. */\nfunction scrollToPoint(point: ScrollPoint): void {\n window.scrollTo({ top: point.y, left: point.x, behavior: 'instant' });\n}\n\n/**\n * Scrolls to a fragment's target the way the browser's own fragment jump does.\n *\n * `scrollIntoView` is the algorithm that honours `scroll-padding-top` on the scrolling box and\n * `scroll-margin-top` on the target, which `window.scrollTo` does not. The lookup follows the browser's\n * \"find a potential indicated element\": the id first, then the name. A malformed percent-escape falls back\n * to the literal fragment, and a fragment nothing matches gets the top of the document — what a browser\n * gives a missing anchor on a real load.\n */\nfunction jumpToAnchor(hash: string): void {\n const raw = hash.startsWith('#') ? hash.slice(1) : hash;\n // No special case for `#top`: the browser only treats it as the top of the document when no element\n // matches, and the fallback below is that top.\n if (raw === '') {\n scrollToTop();\n return;\n }\n let id = raw;\n try {\n id = decodeURIComponent(raw);\n } catch {\n // Malformed escape — the literal fragment is the better guess at the id than nothing.\n }\n const target = document.getElementById(id) ?? document.getElementsByName(id)[0];\n if (target) target.scrollIntoView();\n else scrollToTop();\n}\n\n/**\n * Moves focus the way the browser's `focusReset: 'after-transition'` does: the first `autofocus` element,\n * else the document body. A traversal is no longer intercepted, so the browser performs no focus reset for\n * it; without this, Back would leave focus on the link that was clicked on the page being left, and the next\n * Tab would resume there. `preventScroll` because the traversal's own offset has just been restored.\n */\nfunction resetFocus(): void {\n const autofocus = document.querySelector<HTMLElement>('[autofocus]');\n if (autofocus) autofocus.focus({ preventScroll: true });\n else document.body.focus({ preventScroll: true });\n}\n\n/**\n * Puts a payload on screen, resolving once React has committed it. Replaced by `BrowserRoot`'s own on mount;\n * the default covers the window before hydration, where `setServerCallback` is already registered but there\n * is no root to update — a reload is the honest answer, and nothing after it needs to run.\n *\n * `afterCommit`, when given, runs in the same layout effect that releases the commit: after the new tree is\n * in the DOM and before the browser paints, which is the only moment a `#hash` target exists and the\n * pre-scroll position has not been shown.\n */\nlet setPayload: (payload: RscPayload, afterCommit?: () => void) => Promise<void> = () => {\n window.location.reload();\n return new Promise<void>(() => {});\n};\n\n/** Runs work inside the nav transition so `useNavigation().pending` stays true across the round-trip. */\nlet startNav: (run: () => void | Promise<void>) => void = (run) => {\n void run();\n};\n\n/**\n * The navigation whose payload is allowed to settle the screen. React runs async work concurrently, so two\n * navigations are two live fetches with no ordering between them; without this a slow first response landing\n * after a fast second one repaints the page the user already left. The Navigation API aborts an intercepted\n * navigation when a newer one starts, but a traversal has no `event.signal` to watch — `popstate` arrives\n * after the browser has already committed it — so ordering is the runtime's own for those.\n */\nlet currentNavigation = 0;\n\n/** The in-flight navigation's fetch, so a newer one can stop paying for it. */\nlet navigationFetch: AbortController | null = null;\n\n/**\n * Fetches the payload for `url` and puts it on screen.\n *\n * Resolves once React has **committed** it rather than when the fetch lands: `afterCommit` runs at that\n * point, and a `#hash` target does not exist until the new tree does. Rejects only on a genuine failure —\n * being superseded is not one, and resolves quietly, because the navigation that replaced this one owns the\n * screen from then on.\n */\nfunction loadPayload(url: string, signal?: AbortSignal, afterCommit?: () => void): Promise<void> {\n // This navigation's place in the queue, and its own abort switch: a fetch is abandoned by whichever comes\n // first, the browser superseding it (an intercepted navigation carries `event.signal`) or a newer runtime\n // fetch starting (a traversal, an action, a dev refresh).\n const navigation = ++currentNavigation;\n navigationFetch?.abort();\n const controller = (navigationFetch = new AbortController());\n const abort = signal ? AbortSignal.any([signal, controller.signal]) : controller.signal;\n\n // Deliberately not awaited inside the transition: the scope ends once the payload is handed to React, and\n // React holds `pending` until the update it scheduled commits. Awaiting the commit *inside* the scope would\n // work too, but only because React happens not to gate a commit on its async scope settling — an internal\n // this has no reason to depend on across the whole `^19.1.0` peer range.\n let committed: Promise<void> | undefined;\n\n const run = async () => {\n const payload = await requestPayload(url, abort);\n // Checked again after the await because the fetch may already have resolved by then, and applying it\n // would repaint a page the user has left.\n if (abort.aborted || navigation !== currentNavigation) return;\n if (payload.redirect) {\n push(payload.redirect);\n return;\n }\n // The fetch crossed an await, so its payload update needs a new synchronous transition scope.\n // Keep the commit promise outside the async Action; React tracks the scheduled update until commit.\n React.startTransition(() => {\n committed = setPayload(payload, afterCommit);\n });\n };\n\n // `startTransition` runs the work but hands nothing back, so the promise carrying a failure is caught here\n // instead. Assigned synchronously: React invokes the callback before `startNav` returns.\n let work!: Promise<void>;\n startNav(() => (work = run()));\n\n return work.then(\n // Undefined whenever nothing was applied — an abort, or a redirect — and there is then nothing to wait for.\n () => committed,\n (error: unknown) => {\n // Checked before the error is read: an abort is this navigation being replaced, and the one that\n // replaced it owns the outcome.\n if (abort.aborted || navigation !== currentNavigation || handleControlDigest(error)) return;\n throw error;\n },\n );\n}\n\n/**\n * Whether a destination names a file rather than a page. `public/`, `/_static` and an endpoint route that\n * serves a document (`/llms.txt`, `/sitemap.xml`) answer an RSC fetch with the file itself, not a flight\n * payload — so intercepting one buys nothing: the payload never arrives, and the only recovery left is the\n * document load the browser would have made directly. Handing it that navigation up front also gives the\n * entry the file loads into the browser's own history, so Back is an ordinary cross-document traversal. An\n * intercepted entry is same-document by construction, and traversing one with nothing to repaint it changes\n * the URL and nothing else — which is what a Back press out of an opened file was doing.\n *\n * A dot in the last path segment rather than a list of extensions: a list is never complete, and every miss\n * is the failed round trip above. A page route whose last segment carries a dot (`/release-1.0`) therefore\n * costs a document load — the direction to err in, and what a `data-native` link already asks for by hand.\n */\nfunction namesAFile(href: string): boolean {\n const lastSegment = new URL(href).pathname.split('/').pop() ?? '';\n return lastSegment.includes('.');\n}\n\n/**\n * Navigations the browser can hand over but shouldn't:\n *\n * - a fragment jump, which is same-document already and needs no payload — the browser's own jump is the one\n * that honours `scroll-padding-top`, and re-rendering would pull the target out from under it;\n * - a download, which is not a navigation of this page at all;\n * - a `POST` form, which is a submission and the server's to answer (a `GET` form carries its fields in the\n * URL, has no `formData`, and soft-navigates like any other link);\n * - a link marked `data-native`, the documented opt-out;\n * - a destination that names a file — see {@link namesAFile}.\n */\nfunction leaveToBrowser(event: NavigateEvent): boolean {\n return (\n event.hashChange ||\n event.downloadRequest !== null ||\n event.formData !== null ||\n event.sourceElement?.hasAttribute('data-native') === true ||\n namesAFile(event.destination.url)\n );\n}\n\n/**\n * The whole router, in one listener.\n *\n * Every navigation the page can make arrives as a `navigate` event — a link click, a `GET` form, a\n * `history.pushState`, the back button, `navigation.reload()` — already filtered by the browser: it does not\n * fire for a middle-click, a modified click or a new tab, and reports `canIntercept: false` for anything\n * cross-origin, or for a traversal that leaves the app. Those need no handling here; they are left alone, and\n * the browser performs them as it always would.\n */\nfunction listenNavigation(): () => void {\n if (!canSoftNavigate) return () => {};\n\n const onNavigate = (event: NavigateEvent) => {\n // A document navigation the runtime asked for itself, marked through `info`. Checked before the scroll\n // snapshot: the document is going away, so where its entry was left does not matter, and an unrelated\n // later navigation can never be mistaken for this one.\n if (event.info === documentNavigation) return;\n\n // Whatever the browser is about to do with this navigation, the entry it is leaving is about to lose the\n // offset it was at, and nothing else in this document will put it back. Saved before the branches below\n // return, so a fragment the browser performs itself is covered too.\n rememberCurrentScroll();\n\n if (!event.canIntercept || leaveToBrowser(event)) return;\n\n // A traversal is repainted by the `popstate` listener below, not intercepted. `intercept`ing one is what\n // makes WebKit stall the rendered viewport for about three seconds on a back swipe\n // (bugs.webkit.org/319414): the view gesture's snapshot is only removed once the navigation finishes, and\n // React's root attaches the wheel listener the bug also needs. Letting the traversal through means the\n // browser commits the entry straight away, and the runtime puts the payload on screen when it arrives.\n if (event.navigationType === 'traverse') return;\n\n // A replace or a refresh stays where it is, so neither should move. A push starts at the top of the\n // page, or at its fragment — and that scroll is the runtime's own now: WebKit performs no\n // `after-transition` reset at all for an intercepted push (bugs.webkit.org/304593). Chromium skips it\n // too, and a fragment jump rides the same code path. Passing `manual` here makes the browser hand the\n // handler over without scrolling; the `afterCommit` callback reaches the target once the new tree is on\n // screen. Focus stays the browser's, reset after the transition.\n const inPlace = event.navigationType === 'replace' || event.navigationType === 'reload';\n let afterCommit: (() => void) | undefined;\n if (event.navigationType === 'push') {\n const { hash } = new URL(event.destination.url);\n afterCommit = hash === '' ? scrollToTop : () => jumpToAnchor(hash);\n }\n\n event.intercept({\n scroll: 'manual',\n focusReset: inPlace ? 'manual' : 'after-transition',\n // The URL commits before the handler runs, so a failure leaves the address bar describing a page the\n // document is not showing. A real load is the only way back to agreement.\n handler: () => loadPayload(event.destination.url, event.signal, afterCommit).catch(() => loadDocument()),\n });\n };\n\n /**\n * Repaints a traversal the listener above deliberately left to the browser, and moves the viewport back\n * where the entry was left. `popstate` fires after the browser has committed the entry, so the destination\n * is `navigation.currentEntry` and its saved offset is in {@link scrollPositions}.\n */\n const onPopState = () => {\n const stored = scrollPointFor(currentEntryKey());\n const hash = location.hash;\n const apply = () => {\n if (stored) scrollToPoint(stored);\n else if (hash !== '') jumpToAnchor(hash);\n else scrollToTop();\n };\n\n // A fragment-only traversal never changed the payload: the address bar is back at an anchor of the page\n // already on screen, so there is nothing to fetch and nothing to wait for. The browser's own restoration\n // is off, so the offset comes from what `onNavigate` saved when the anchor was followed; no focus reset,\n // which is what leaving those navigations to the browser has always meant.\n if (documentUrl() === renderedUrl) {\n apply();\n return;\n }\n\n void loadPayload(location.href, undefined, () => {\n apply();\n // The browser performs this for an intercepted navigation; a traversal is no longer intercepted, so\n // without it Back would leave focus on the link that was clicked on the page being left.\n resetFocus();\n }).catch(() => loadDocument());\n };\n\n navigation.addEventListener('navigate', onNavigate);\n window.addEventListener('popstate', onPopState);\n return () => {\n navigation.removeEventListener('navigate', onNavigate);\n window.removeEventListener('popstate', onPopState);\n };\n}\n\nasync function main() {\n // The assertion is load-bearing under the compiler that builds this: TypeScript 7 declares `nonce` on\n // HTMLElement, 6 declares it on Element. ESLint runs the older lib — where the narrowing is redundant —\n // so it reports an assertion that `tsc` requires. Believe `typecheck`, not the rule.\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion\n const cspMeta = document.querySelector('meta[property=\"csp-nonce\"]') as HTMLMetaElement | null;\n if (cspMeta?.nonce) __webpack_nonce__ = cspMeta.nonce;\n\n const initialPayload = await createFromReadableStream<RscPayload>(flightStream);\n\n // The recovery reload landed: this document *is* the `notFound` page, so the signal that could only be a\n // digest on the `RSC: 1` request became a real 404 on the document request. The one-reload bound was spent\n // on a recovery that worked and has to be released — otherwise the *next* soft navigation to this URL sees a\n // spent key and paints {@link showLateNotFound} over a page the app can still render.\n //\n // This is the discriminator the bound was missing. A structurally late `notFound()` commits its 200 before\n // it signals, so its reloaded document is the page itself and carries no `notFound`: the key survives and\n // that loop stays bounded at one reload, which is the whole reason the bound exists.\n if (initialPayload.notFound) {\n try {\n sessionStorage.removeItem(lateNotFoundKey());\n } catch {\n // Blocked site data. `reloadOnceForLateNotFound` already treats that as the terminating case.\n }\n }\n\n // Everything the last document saved, read before any payload commits: the in-memory map alone would not\n // survive the reload that `history.scrollRestoration = 'manual'` just stopped the browser restoring. The\n // entry's key is stable across a reload, and the offset is applied by `BrowserRoot`'s first layout effect,\n // before the first paint of the new tree.\n if (canSoftNavigate) readStoredScrollPositions();\n const restored = scrollPointFor(currentEntryKey());\n\n function BrowserRoot() {\n const [payload, setPayloadState] = React.useState(initialPayload);\n const [pending, startTransition] = React.useTransition();\n // The resolver the payload on screen still owes — see {@link loadPayload}.\n const pendingCommit = React.useRef<(() => void) | null>(null);\n // The scroll the payload about to commit owes, set with it so a payload that supersedes another takes\n // its predecessor's scroll out of the queue along with its commit. Initialised with the reload's offset:\n // the first layout effect below applies it with the first payload, before the new tree is painted.\n const pendingScroll = React.useRef<(() => void) | null>(restored ? () => scrollToPoint(restored) : null);\n\n // Descendant passive effects can start a navigation before the root's passive effects run.\n // Install the live payload setter and transition runner before any such navigation starts.\n React.useLayoutEffect(() => {\n setPayload = (next, afterCommit) =>\n new Promise<void>((resolve) => {\n // A payload replaced before it ever painted still has a navigation waiting on it. React commits\n // only the newest, so the effect below never runs for the one it skipped: release it here.\n pendingCommit.current?.();\n pendingCommit.current = resolve;\n // Replaced rather than kept: a server action's payload carries no `afterCommit`, and the\n // navigation it superseded must not scroll the page the action is about to replace it with.\n pendingScroll.current = afterCommit ?? null;\n setPayloadState(next);\n });\n startNav = (run) => startTransition(run);\n }, [startTransition]);\n\n /**\n * Performs the pending scroll and releases the navigation waiting on this payload. A layout effect, so\n * the new tree is in the DOM and the pre-scroll position is never painted.\n */\n React.useLayoutEffect(() => {\n const scroll = pendingScroll.current;\n pendingScroll.current = null;\n scroll?.();\n // What the payload that just committed was rendered for — see {@link renderedUrl}. A redirect never\n // reaches here, and an action or a dev refresh keeps the URL it was fetched for.\n renderedUrl = documentUrl();\n const commit = pendingCommit.current;\n pendingCommit.current = null;\n commit?.();\n }, [payload]);\n\n // A descendant may navigate from its first passive effect. Intercept it before that effect runs.\n React.useLayoutEffect(() => listenNavigation(), []);\n\n const router = React.useMemo<NavigationRouter>(() => ({ push, replace, back, forward, refresh, pending }), [pending]);\n\n return <RouterContext.Provider value={router}>{payload.root}</RouterContext.Provider>;\n }\n\n setServerCallback(async (id, args) => {\n const temporaryReferences = createTemporaryReferenceSet();\n // The document the action is being called from. Every action response carries a fresh payload for that\n // page, so if a navigation has moved on by the time it arrives the payload describes a page the user has\n // left — the return value is still theirs, but painting it is not. Compared without the fragment, which\n // the server never saw.\n const calledFrom = documentUrl();\n const request = createRscRequest(window.location.href, {\n id,\n body: await encodeReply(args, { temporaryReferences }),\n });\n let payload: RscPayload;\n try {\n payload = await createFromFetch<RscPayload>(payloadResponse(request), { temporaryReferences });\n } catch (error) {\n if (handleControlDigest(error)) return undefined;\n throw error;\n }\n if (payload.redirect) {\n push(payload.redirect);\n return undefined;\n }\n if (documentUrl() === calledFrom) React.startTransition(() => void setPayload(payload));\n if (payload.notFound) return undefined;\n const result = payload.returnValue;\n if (!result) {\n // A payload that is not this action's own reply: the server rendered a page in its place. An action\n // that had already run has its result carried across (see `actionResults` in entry.rsc.tsx), and the\n // ways a *caller* can get a request wrong are refused ahead of any render — an unknown id or an\n // undecodable body is a `text/plain` 400, which `payloadResponse` turns into an error of its own\n // before this.\n //\n // What is left is the server failing before the action ran, which is answered with the `error` page —\n // a flight payload, so it arrives here rather than at `payloadResponse`, with no `returnValue` in it.\n // A module the deployment no longer holds is the reachable case: `loadServerAction` throws, the\n // framework reports it and 500s, and this is what the caller has to go on. Hence the message: the\n // failure is on the server and its log is where the error is. Below that it is still the defensive\n // floor for a payload shaped by another deployment or replaced by a proxy — reading `.ok` off it used\n // to hand the caller `Cannot read properties of undefined`.\n throw new Error(\n '[rshono] the server action produced no result — the request failed around it and the server answered with a page instead. Its log has the error.',\n );\n }\n if (!result.ok) throw result.error;\n return result.value;\n });\n\n // A `redirect()` / `notFound()` from a component below the page root reaches us through React: it rides the\n // flight payload as an error, and boundaries re-throw it so it lands here rather than in a fallback.\n //\n // Installing these hooks opts out of React's own defaults, so everything that isn't a control signal has to\n // be put back by hand — `reportError` rather than a bare log, so error-reporting tools still see it.\n hydrateRoot(document, <BrowserRoot />, {\n formState: initialPayload.formState,\n onCaughtError: (error, errorInfo) => {\n if (handleControlDigest(error, { hard: true })) return;\n // A boundary handled it and the tree is intact, so no overlay over the app's own fallback.\n console.error(error, errorInfo.componentStack ?? '');\n },\n onUncaughtError: (error, errorInfo) => {\n if (handleControlDigest(error, { hard: true })) return;\n // Nothing caught it, so React tears the root down — and the root is `document`.\n globalThis.reportError(error);\n showFatal(error, errorInfo.componentStack);\n },\n });\n\n if (import.meta.webpackHot) {\n initDevRefresh();\n }\n}\n\n/**\n * Dev-only refresh client, listening to the CLI's SSE endpoint:\n *\n * client-built → hot-apply the waiting updates; anything the page can't be patched up to reloads.\n * rsc-update → server component code changed: re-fetch the flight payload, state preserved.\n * hello → sent on (re)connect with the latest build hash; a mismatch means a missed event.\n */\nfunction initDevRefresh() {\n const hot = import.meta.webpackHot!;\n let connectedOnce = false;\n /** The newest build the dev server has announced — what {@link applyClientUpdate} walks towards. */\n let targetHash: string | undefined;\n\n function reload(reason: string, error?: unknown): void {\n console.warn(`[rshono] ${reason} — reloading`, ...(error === undefined ? [] : [error]));\n loadDocument();\n }\n\n async function applyClientUpdate(): Promise<void> {\n const giveUp = await walkHotUpdates(\n hot,\n () => __webpack_hash__,\n () => targetHash,\n );\n if (giveUp) reload(giveUp.reason, giveUp.error);\n }\n\n async function handle(message: DevMessage): Promise<void> {\n switch (message.type) {\n case 'hello':\n targetHash = message.hash ?? targetHash;\n if (connectedOnce) {\n await applyClientUpdate();\n await loadPayload(window.location.href).catch(() => loadDocument());\n }\n connectedOnce = true;\n break;\n case 'client-built':\n targetHash = message.hash;\n await applyClientUpdate();\n break;\n case 'rsc-update':\n console.log('[rshono] server components updated');\n await loadPayload(window.location.href).catch(() => loadDocument());\n break;\n }\n }\n\n const source = new EventSource('/_rshono/hmr');\n // Chained rather than handled as they arrive: `hot.check` may only run from `idle`, and a burst of saves\n // puts several frames on the wire inside the time one takes. Queueing drops nothing, because `targetHash`\n // is shared — whichever handler runs next walks to the newest build.\n let queue: Promise<void> = Promise.resolve();\n source.onmessage = (event: MessageEvent<string>) => {\n const message = JSON.parse(event.data) as DevMessage;\n queue = queue.then(() => handle(message)).catch((error) => reload('the dev client failed', error));\n };\n}\n\n// A bootstrap failure — a truncated initial payload, most likely — would otherwise be an unhandled\n// rejection: nothing hydrates, nothing is reported, and the page just sits there.\nmain().catch((error) => {\n console.error('[rshono] the client runtime failed to start:', error);\n showFatal(error);\n});\n"]}
@@ -39,6 +39,12 @@ export interface NavigationState {
39
39
  /**
40
40
  * The full current {@link URL}. A fresh instance per navigation, so mutating it affects nothing else
41
41
  * — it is not written back to the address bar.
42
+ *
43
+ * The path, query and origin travel in the page payload, but the fragment cannot: a browser leaves `#…`
44
+ * out of the request line, so the server renders every page without one. `url.hash` is therefore read
45
+ * from the browser after hydration and follows `hashchange` — an in-page link, Back/Forward between
46
+ * anchors of one document, or opening the document at one. Nothing else about the URL is affected; see
47
+ * {@link useNavigation} for the `render: 'static'` case.
42
48
  */
43
49
  url: URL;
44
50
  /** Matched route params for the current page, e.g. `{ id: '42' }` for `/profile/:id`. */
@@ -71,11 +77,16 @@ export declare function RouterProvider({ href, params, children }: {
71
77
  * during SSR — no hydration flicker — and update on every navigation. `router` holds the imperative
72
78
  * actions plus a `pending` flag, `true` while a soft navigation is in flight.
73
79
  *
80
+ * The fragment is the exception the payload cannot cover: a browser never sends `#…` to the server, so
81
+ * `url.hash` is read from the address bar after hydration and kept in sync on `hashchange` — an in-page
82
+ * link, Back/Forward between anchors, or opening the document at `#section` — with no request either way.
83
+ * Everything before the `#` remains what the payload carried.
84
+ *
74
85
  * **On a `render: 'static'` route `url` is frozen at build time**, origin included and query empty. The
75
86
  * payload is one prerendered set of bytes and this reads the `href` in it, so it is the page's own
76
- * `PageProps.url` — the same value, not a live one. A page whose output depends on the query wants
77
- * `render: 'dynamic'`; a component that only needs it after hydration can read `location.search` in an
78
- * effect.
87
+ * `PageProps.url` — the same value, not a live one, `url.hash` aside. A page whose output depends on the
88
+ * query wants `render: 'dynamic'`; a component that only needs it after hydration can read
89
+ * `location.search` in an effect.
79
90
  *
80
91
  * Hooks can't run in a server component; read the same data there from `getRequestContext()`.
81
92
  *
@@ -1,6 +1,6 @@
1
1
  'use client';
2
2
  import { jsx as _jsx } from "react/jsx-runtime";
3
- import { createContext, useContext, useMemo } from 'react';
3
+ import { createContext, useContext, useMemo, useSyncExternalStore } from 'react';
4
4
  const noop = () => { };
5
5
  const defaultRouter = { push: noop, replace: noop, back: noop, forward: noop, refresh: noop, pending: false };
6
6
  /**
@@ -10,6 +10,27 @@ const defaultRouter = { push: noop, replace: noop, back: noop, forward: noop, re
10
10
  */
11
11
  export const RouterContext = createContext(defaultRouter);
12
12
  const NavigationContext = createContext(null);
13
+ /**
14
+ * The browser's fragment navigation: the one part of the address a payload can never carry, and the one part
15
+ * that can move without a page data request. `hashchange` is every way it moves within a document — an
16
+ * in-page link, Back/Forward between anchors of one page, opening the document at `#section` covered by the
17
+ * post-hydration check `useSyncExternalStore` makes for a changed snapshot. A cross-page `#anchor` commits a
18
+ * payload instead; the re-render that follows reads the fragment then.
19
+ */
20
+ function subscribeToHash(onStoreChange) {
21
+ window.addEventListener('hashchange', onStoreChange);
22
+ return () => window.removeEventListener('hashchange', onStoreChange);
23
+ }
24
+ /** The live fragment, `#…` included, or `''`. */
25
+ const readHash = () => window.location.hash;
26
+ /**
27
+ * What the fragment reads as while the server snapshot is in use — server render and hydration. The server
28
+ * never saw one, so the payload's URL has none; answering with the live fragment here would render markup
29
+ * the server did not and fail hydration. The empty string is exactly what the payload carries, and the
30
+ * post-hydration re-render that `useSyncExternalStore` performs for a changed snapshot is where the
31
+ * browser's own arrives.
32
+ */
33
+ const readServerHash = () => '';
13
34
  /**
14
35
  * Publishes the per-render location and params for {@link useNavigation} to read. The RSC entry wraps
15
36
  * every page in one.
@@ -18,7 +39,14 @@ const NavigationContext = createContext(null);
18
39
  */
19
40
  export function RouterProvider({ href, params, children }) {
20
41
  const router = useContext(RouterContext);
21
- const value = useMemo(() => ({ url: new URL(href), params, router }), [href, params, router]);
42
+ // `href` is the payload's URL — see `subscribeToHash` — so the browser's fragment is applied on top of it.
43
+ // This is the only client-side part of `url`; path, query and origin stay exactly what the payload said.
44
+ const hash = useSyncExternalStore(subscribeToHash, readHash, readServerHash);
45
+ const value = useMemo(() => {
46
+ const url = new URL(href);
47
+ url.hash = hash;
48
+ return { url, params, router };
49
+ }, [href, hash, params, router]);
22
50
  return _jsx(NavigationContext.Provider, { value: value, children: children });
23
51
  }
24
52
  /**
@@ -29,11 +57,16 @@ export function RouterProvider({ href, params, children }) {
29
57
  * during SSR — no hydration flicker — and update on every navigation. `router` holds the imperative
30
58
  * actions plus a `pending` flag, `true` while a soft navigation is in flight.
31
59
  *
60
+ * The fragment is the exception the payload cannot cover: a browser never sends `#…` to the server, so
61
+ * `url.hash` is read from the address bar after hydration and kept in sync on `hashchange` — an in-page
62
+ * link, Back/Forward between anchors, or opening the document at `#section` — with no request either way.
63
+ * Everything before the `#` remains what the payload carried.
64
+ *
32
65
  * **On a `render: 'static'` route `url` is frozen at build time**, origin included and query empty. The
33
66
  * payload is one prerendered set of bytes and this reads the `href` in it, so it is the page's own
34
- * `PageProps.url` — the same value, not a live one. A page whose output depends on the query wants
35
- * `render: 'dynamic'`; a component that only needs it after hydration can read `location.search` in an
36
- * effect.
67
+ * `PageProps.url` — the same value, not a live one, `url.hash` aside. A page whose output depends on the
68
+ * query wants `render: 'dynamic'`; a component that only needs it after hydration can read
69
+ * `location.search` in an effect.
37
70
  *
38
71
  * Hooks can't run in a server component; read the same data there from `getRequestContext()`.
39
72
  *
@@ -1 +1 @@
1
- {"version":3,"file":"navigation.js","sourceRoot":"","sources":["../../src/runtime/navigation.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,OAAO,EAAkB,MAAM,OAAO,CAAC;AAmD3E,MAAM,IAAI,GAAG,GAAG,EAAE,GAAE,CAAC,CAAC;AAEtB,MAAM,aAAa,GAAqB,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;AAEhI;;;;GAIG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,aAAa,CAAmB,aAAa,CAAC,CAAC;AAE5E,MAAM,iBAAiB,GAAG,aAAa,CAAyB,IAAI,CAAC,CAAC;AAEtE;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAyE;IAC9H,MAAM,MAAM,GAAG,UAAU,CAAC,aAAa,CAAC,CAAC;IACzC,MAAM,KAAK,GAAG,OAAO,CAAkB,GAAG,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,IAAI,GAAG,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAE/G,OAAO,KAAC,iBAAiB,CAAC,QAAQ,IAAC,KAAK,EAAE,KAAK,YAAG,QAAQ,GAA8B,CAAC;AAC3F,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,MAAM,UAAU,aAAa;IAC3B,MAAM,KAAK,GAAG,UAAU,CAAC,iBAAiB,CAAC,CAAC;IAC5C,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CACb,mKAAmK,CACpK,CAAC;IACJ,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC","sourcesContent":["'use client';\n\nimport { createContext, useContext, useMemo, type ReactNode } from 'react';\n\n/**\n * Imperative navigation actions, reached as `useNavigation().router`.\n *\n * Every action is a **soft** navigation: the page's flight payload is fetched and applied in place, so\n * client component state outside the changed subtree survives. Off-site hrefs — and a traversal that leaves\n * the app — fall back to a full load.\n *\n * Soft navigation is the browser's\n * {@link https://developer.mozilla.org/en-US/docs/Web/API/Navigation_API | Navigation API}; where that is\n * missing, every action below is still correct and simply performs a real browser load.\n *\n * @example\n * ```tsx\n * const { router } = useNavigation();\n * router.push('/dashboard'); // navigate, new history entry\n * router.replace('/login'); // navigate, no new entry\n * router.back(); // one entry back, as the browser's button does\n * router.forward(); // one entry forward\n * router.refresh(); // re-run this route's server components\n * ```\n */\nexport interface NavigationRouter {\n /** Navigates to `href` and pushes a new history entry. */\n push(href: string): void;\n /** Navigates to `href`, replacing the current history entry instead of adding one. */\n replace(href: string): void;\n /** Steps one entry back in the browser's session history. Nothing to go back to is a no-op. */\n back(): void;\n /** Steps one entry forward in the browser's session history. A no-op on the newest entry. */\n forward(): void;\n /** Re-fetches the current route from the server, re-running its server components. */\n refresh(): void;\n /** `true` while a soft navigation is in flight — use it to disable controls or show a spinner. */\n pending: boolean;\n}\n\n/** The current location plus the {@link NavigationRouter}, as returned by {@link useNavigation}. */\nexport interface NavigationState {\n /**\n * The full current {@link URL}. A fresh instance per navigation, so mutating it affects nothing else\n * — it is not written back to the address bar.\n */\n url: URL;\n /** Matched route params for the current page, e.g. `{ id: '42' }` for `/profile/:id`. */\n params: Record<string, string>;\n /** Imperative navigation actions and the `pending` flag. */\n router: NavigationRouter;\n}\n\nconst noop = () => {};\n\nconst defaultRouter: NavigationRouter = { push: noop, replace: noop, back: noop, forward: noop, refresh: noop, pending: false };\n\n/**\n * Carries the live {@link NavigationRouter} from the hydration runtime down to {@link RouterProvider}.\n *\n * @internal\n */\nexport const RouterContext = createContext<NavigationRouter>(defaultRouter);\n\nconst NavigationContext = createContext<NavigationState | null>(null);\n\n/**\n * Publishes the per-render location and params for {@link useNavigation} to read. The RSC entry wraps\n * every page in one.\n *\n * @internal\n */\nexport function RouterProvider({ href, params, children }: { href: string; params: Record<string, string>; children: ReactNode }) {\n const router = useContext(RouterContext);\n const value = useMemo<NavigationState>(() => ({ url: new URL(href), params, router }), [href, params, router]);\n\n return <NavigationContext.Provider value={value}>{children}</NavigationContext.Provider>;\n}\n\n/**\n * Reactive access to the current URL and programmatic navigation, in one hook. Call it from a\n * `'use client'` component.\n *\n * `url` and `params` are computed on the server and travel in the flight payload, so they are correct\n * during SSR — no hydration flicker — and update on every navigation. `router` holds the imperative\n * actions plus a `pending` flag, `true` while a soft navigation is in flight.\n *\n * **On a `render: 'static'` route `url` is frozen at build time**, origin included and query empty. The\n * payload is one prerendered set of bytes and this reads the `href` in it, so it is the page's own\n * `PageProps.url` — the same value, not a live one. A page whose output depends on the query wants\n * `render: 'dynamic'`; a component that only needs it after hydration can read `location.search` in an\n * effect.\n *\n * Hooks can't run in a server component; read the same data there from `getRequestContext()`.\n *\n * @example\n * ```tsx\n * 'use client';\n * import { useNavigation } from '@rshono/core/client';\n *\n * export function NextPage() {\n * const { url, router } = useNavigation();\n * const page = Number(url.searchParams.get('page') ?? '1');\n * return (\n * <button disabled={router.pending} onClick={() => router.push(`${url.pathname}?page=${page + 1}`)}>\n * Next {router.pending ? '…' : ''}\n * </button>\n * );\n * }\n * ```\n *\n * @returns The current {@link NavigationState}: `url` and `params`, plus `router`\n * ({@link NavigationRouter}) with `push` / `replace` / `back` / `forward` / `refresh` / `pending`.\n * @throws If called outside a page's React tree, where there is no navigation\n * context to read.\n *\n * @see {@link https://www.rshono.com/docs/api#rshonocoreclient | Docs — `@rshono/core/client`}\n * @see {@link https://www.rshono.com/docs/pages#client-components | Docs — client components}\n */\nexport function useNavigation(): NavigationState {\n const value = useContext(NavigationContext);\n if (!value) {\n throw new Error(\n \"[rshono] useNavigation() must be called inside a 'use client' component rendered by a page. In a server component, read the URL from getRequestContext() instead.\",\n );\n }\n return value;\n}\n"]}
1
+ {"version":3,"file":"navigation.js","sourceRoot":"","sources":["../../src/runtime/navigation.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,OAAO,EAAE,oBAAoB,EAAkB,MAAM,OAAO,CAAC;AAyDjG,MAAM,IAAI,GAAG,GAAG,EAAE,GAAE,CAAC,CAAC;AAEtB,MAAM,aAAa,GAAqB,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;AAEhI;;;;GAIG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,aAAa,CAAmB,aAAa,CAAC,CAAC;AAE5E,MAAM,iBAAiB,GAAG,aAAa,CAAyB,IAAI,CAAC,CAAC;AAEtE;;;;;;GAMG;AACH,SAAS,eAAe,CAAC,aAAyB;IAChD,MAAM,CAAC,gBAAgB,CAAC,YAAY,EAAE,aAAa,CAAC,CAAC;IACrD,OAAO,GAAG,EAAE,CAAC,MAAM,CAAC,mBAAmB,CAAC,YAAY,EAAE,aAAa,CAAC,CAAC;AACvE,CAAC;AAED,iDAAiD;AACjD,MAAM,QAAQ,GAAG,GAAW,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC;AAEpD;;;;;;GAMG;AACH,MAAM,cAAc,GAAG,GAAW,EAAE,CAAC,EAAE,CAAC;AAExC;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAyE;IAC9H,MAAM,MAAM,GAAG,UAAU,CAAC,aAAa,CAAC,CAAC;IACzC,2GAA2G;IAC3G,yGAAyG;IACzG,MAAM,IAAI,GAAG,oBAAoB,CAAC,eAAe,EAAE,QAAQ,EAAE,cAAc,CAAC,CAAC;IAC7E,MAAM,KAAK,GAAG,OAAO,CAAkB,GAAG,EAAE;QAC1C,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,CAAC;QAC1B,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC;QAChB,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;IACjC,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAEjC,OAAO,KAAC,iBAAiB,CAAC,QAAQ,IAAC,KAAK,EAAE,KAAK,YAAG,QAAQ,GAA8B,CAAC;AAC3F,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AACH,MAAM,UAAU,aAAa;IAC3B,MAAM,KAAK,GAAG,UAAU,CAAC,iBAAiB,CAAC,CAAC;IAC5C,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CACb,mKAAmK,CACpK,CAAC;IACJ,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC","sourcesContent":["'use client';\n\nimport { createContext, useContext, useMemo, useSyncExternalStore, type ReactNode } from 'react';\n\n/**\n * Imperative navigation actions, reached as `useNavigation().router`.\n *\n * Every action is a **soft** navigation: the page's flight payload is fetched and applied in place, so\n * client component state outside the changed subtree survives. Off-site hrefs — and a traversal that leaves\n * the app — fall back to a full load.\n *\n * Soft navigation is the browser's\n * {@link https://developer.mozilla.org/en-US/docs/Web/API/Navigation_API | Navigation API}; where that is\n * missing, every action below is still correct and simply performs a real browser load.\n *\n * @example\n * ```tsx\n * const { router } = useNavigation();\n * router.push('/dashboard'); // navigate, new history entry\n * router.replace('/login'); // navigate, no new entry\n * router.back(); // one entry back, as the browser's button does\n * router.forward(); // one entry forward\n * router.refresh(); // re-run this route's server components\n * ```\n */\nexport interface NavigationRouter {\n /** Navigates to `href` and pushes a new history entry. */\n push(href: string): void;\n /** Navigates to `href`, replacing the current history entry instead of adding one. */\n replace(href: string): void;\n /** Steps one entry back in the browser's session history. Nothing to go back to is a no-op. */\n back(): void;\n /** Steps one entry forward in the browser's session history. A no-op on the newest entry. */\n forward(): void;\n /** Re-fetches the current route from the server, re-running its server components. */\n refresh(): void;\n /** `true` while a soft navigation is in flight — use it to disable controls or show a spinner. */\n pending: boolean;\n}\n\n/** The current location plus the {@link NavigationRouter}, as returned by {@link useNavigation}. */\nexport interface NavigationState {\n /**\n * The full current {@link URL}. A fresh instance per navigation, so mutating it affects nothing else\n * — it is not written back to the address bar.\n *\n * The path, query and origin travel in the page payload, but the fragment cannot: a browser leaves `#…`\n * out of the request line, so the server renders every page without one. `url.hash` is therefore read\n * from the browser after hydration and follows `hashchange` — an in-page link, Back/Forward between\n * anchors of one document, or opening the document at one. Nothing else about the URL is affected; see\n * {@link useNavigation} for the `render: 'static'` case.\n */\n url: URL;\n /** Matched route params for the current page, e.g. `{ id: '42' }` for `/profile/:id`. */\n params: Record<string, string>;\n /** Imperative navigation actions and the `pending` flag. */\n router: NavigationRouter;\n}\n\nconst noop = () => {};\n\nconst defaultRouter: NavigationRouter = { push: noop, replace: noop, back: noop, forward: noop, refresh: noop, pending: false };\n\n/**\n * Carries the live {@link NavigationRouter} from the hydration runtime down to {@link RouterProvider}.\n *\n * @internal\n */\nexport const RouterContext = createContext<NavigationRouter>(defaultRouter);\n\nconst NavigationContext = createContext<NavigationState | null>(null);\n\n/**\n * The browser's fragment navigation: the one part of the address a payload can never carry, and the one part\n * that can move without a page data request. `hashchange` is every way it moves within a document — an\n * in-page link, Back/Forward between anchors of one page, opening the document at `#section` covered by the\n * post-hydration check `useSyncExternalStore` makes for a changed snapshot. A cross-page `#anchor` commits a\n * payload instead; the re-render that follows reads the fragment then.\n */\nfunction subscribeToHash(onStoreChange: () => void): () => void {\n window.addEventListener('hashchange', onStoreChange);\n return () => window.removeEventListener('hashchange', onStoreChange);\n}\n\n/** The live fragment, `#…` included, or `''`. */\nconst readHash = (): string => window.location.hash;\n\n/**\n * What the fragment reads as while the server snapshot is in use — server render and hydration. The server\n * never saw one, so the payload's URL has none; answering with the live fragment here would render markup\n * the server did not and fail hydration. The empty string is exactly what the payload carries, and the\n * post-hydration re-render that `useSyncExternalStore` performs for a changed snapshot is where the\n * browser's own arrives.\n */\nconst readServerHash = (): string => '';\n\n/**\n * Publishes the per-render location and params for {@link useNavigation} to read. The RSC entry wraps\n * every page in one.\n *\n * @internal\n */\nexport function RouterProvider({ href, params, children }: { href: string; params: Record<string, string>; children: ReactNode }) {\n const router = useContext(RouterContext);\n // `href` is the payload's URL — see `subscribeToHash` — so the browser's fragment is applied on top of it.\n // This is the only client-side part of `url`; path, query and origin stay exactly what the payload said.\n const hash = useSyncExternalStore(subscribeToHash, readHash, readServerHash);\n const value = useMemo<NavigationState>(() => {\n const url = new URL(href);\n url.hash = hash;\n return { url, params, router };\n }, [href, hash, params, router]);\n\n return <NavigationContext.Provider value={value}>{children}</NavigationContext.Provider>;\n}\n\n/**\n * Reactive access to the current URL and programmatic navigation, in one hook. Call it from a\n * `'use client'` component.\n *\n * `url` and `params` are computed on the server and travel in the flight payload, so they are correct\n * during SSR — no hydration flicker — and update on every navigation. `router` holds the imperative\n * actions plus a `pending` flag, `true` while a soft navigation is in flight.\n *\n * The fragment is the exception the payload cannot cover: a browser never sends `#…` to the server, so\n * `url.hash` is read from the address bar after hydration and kept in sync on `hashchange` — an in-page\n * link, Back/Forward between anchors, or opening the document at `#section` — with no request either way.\n * Everything before the `#` remains what the payload carried.\n *\n * **On a `render: 'static'` route `url` is frozen at build time**, origin included and query empty. The\n * payload is one prerendered set of bytes and this reads the `href` in it, so it is the page's own\n * `PageProps.url` — the same value, not a live one, `url.hash` aside. A page whose output depends on the\n * query wants `render: 'dynamic'`; a component that only needs it after hydration can read\n * `location.search` in an effect.\n *\n * Hooks can't run in a server component; read the same data there from `getRequestContext()`.\n *\n * @example\n * ```tsx\n * 'use client';\n * import { useNavigation } from '@rshono/core/client';\n *\n * export function NextPage() {\n * const { url, router } = useNavigation();\n * const page = Number(url.searchParams.get('page') ?? '1');\n * return (\n * <button disabled={router.pending} onClick={() => router.push(`${url.pathname}?page=${page + 1}`)}>\n * Next {router.pending ? '…' : ''}\n * </button>\n * );\n * }\n * ```\n *\n * @returns The current {@link NavigationState}: `url` and `params`, plus `router`\n * ({@link NavigationRouter}) with `push` / `replace` / `back` / `forward` / `refresh` / `pending`.\n * @throws If called outside a page's React tree, where there is no navigation\n * context to read.\n *\n * @see {@link https://www.rshono.com/docs/api#rshonocoreclient | Docs — `@rshono/core/client`}\n * @see {@link https://www.rshono.com/docs/pages#client-components | Docs — client components}\n */\nexport function useNavigation(): NavigationState {\n const value = useContext(NavigationContext);\n if (!value) {\n throw new Error(\n \"[rshono] useNavigation() must be called inside a 'use client' component rendered by a page. In a server component, read the URL from getRequestContext() instead.\",\n );\n }\n return value;\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rshono/core",
3
- "version": "1.0.0-rc.23",
3
+ "version": "1.0.0-rc.25",
4
4
  "description": "Minimalist web framework — Hono + Rspack + React Server Components",
5
5
  "author": "Lasse <lasse@lassetange.com> (https://www.lassetange.com)",
6
6
  "license": "MIT",
@@ -51,7 +51,7 @@
51
51
  "access": "public"
52
52
  },
53
53
  "dependencies": {
54
- "@hono/node-server": "^2.1.1",
54
+ "@hono/node-server": "^2.1.3",
55
55
  "@rspack/core": "2.2.7",
56
56
  "@rspack/plugin-react-refresh": "2.0.2",
57
57
  "react-refresh": "0.18.0",
@@ -59,10 +59,10 @@
59
59
  },
60
60
  "devDependencies": {
61
61
  "@playwright/test": "^1.63.0",
62
- "@types/node": "^26.5.1",
62
+ "@types/node": "^26.6.4",
63
63
  "@types/react": "^19.2.18",
64
64
  "@types/react-dom": "^19.2.5",
65
- "hono": "^4.13.7",
65
+ "hono": "^4.13.10",
66
66
  "react": "19.2.8",
67
67
  "react-dom": "19.2.8",
68
68
  "typescript": "^7.0.2"