@rsc-kit/core 0.30.38 → 0.30.39
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/dist/flash.d.ts +18 -0
- package/dist/flash.js +29 -0
- package/dist/flash.js.map +1 -0
- package/dist/flashCookie.d.ts +17 -0
- package/dist/flashCookie.js +36 -0
- package/dist/flashCookie.js.map +1 -0
- package/dist/js/ActivityRouter.js +3 -3
- package/dist/js/ActivityRouter.js.map +1 -1
- package/dist/js/Changes.js +1 -1
- package/dist/js/Changes.js.map +1 -1
- package/dist/js/DefaultRouteError.d.ts +1 -1
- package/dist/js/DefaultRouteError.js.map +1 -1
- package/dist/js/Form.d.ts +2 -2
- package/dist/js/Form.js +5 -5
- package/dist/js/Form.js.map +1 -1
- package/dist/js/Link.js +2 -2
- package/dist/js/Link.js.map +1 -1
- package/dist/js/RedirectBoundary.js +2 -2
- package/dist/js/RedirectBoundary.js.map +1 -1
- package/dist/js/SegmentBoundary.js +5 -5
- package/dist/js/SegmentBoundary.js.map +1 -1
- package/dist/js/SlotBoundary.js +3 -3
- package/dist/js/SlotBoundary.js.map +1 -1
- package/dist/js/changesStore.js +1 -1
- package/dist/js/changesStore.js.map +1 -1
- package/dist/js/createViteRscApp.js +14 -14
- package/dist/js/createViteRscApp.js.map +1 -1
- package/dist/js/navigate.d.ts +1 -1
- package/dist/js/navigate.js +8 -8
- package/dist/js/navigate.js.map +1 -1
- package/dist/js/nuqs.js +2 -2
- package/dist/js/nuqs.js.map +1 -1
- package/dist/js/pagePayload.js +2 -2
- package/dist/js/pagePayload.js.map +1 -1
- package/dist/js/refreshOn.js +3 -3
- package/dist/js/refreshOn.js.map +1 -1
- package/dist/js/section.d.ts +4 -4
- package/dist/js/section.js +2 -2
- package/dist/js/section.js.map +1 -1
- package/dist/js/useAppUpdate.js +1 -1
- package/dist/js/useAppUpdate.js.map +1 -1
- package/dist/js/useFlash.d.ts +16 -0
- package/dist/js/useFlash.js +56 -0
- package/dist/js/useFlash.js.map +1 -0
- package/dist/js/useOnline.js +1 -1
- package/dist/js/useOnline.js.map +1 -1
- package/dist/js/usePathname.js +1 -1
- package/dist/js/usePathname.js.map +1 -1
- package/dist/testing.d.ts +9 -0
- package/dist/testing.js +14 -2
- package/dist/testing.js.map +1 -1
- package/dist/vite.js +1 -0
- package/dist/vite.js.map +1 -1
- package/package.json +9 -1
package/dist/js/Link.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
-
import { LinkStatusContext } from "./useLinkStatus";
|
|
4
|
-
import { prefetchWhenVisible } from "./viewportPrefetch";
|
|
3
|
+
import { LinkStatusContext } from "./useLinkStatus.js";
|
|
4
|
+
import { prefetchWhenVisible } from "./viewportPrefetch.js";
|
|
5
5
|
import { withSearch } from "../routes.js";
|
|
6
6
|
import { useCallback, useEffect, useRef, useState, } from "react";
|
|
7
7
|
function isExternalUrl(url) {
|
package/dist/js/Link.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Link.js","sourceRoot":"","sources":["../../src/js/Link.tsx"],"names":[],"mappings":"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","sourcesContent":["\"use client\";\n\nimport { LinkStatusContext } from \"./useLinkStatus\";\nimport { prefetchWhenVisible } from \"./viewportPrefetch\";\nimport { type Route, type SearchProp, withSearch } from \"../routes.js\";\nimport {\n type AnchorHTMLAttributes,\n type MouseEvent,\n type Ref,\n useCallback,\n useEffect,\n useRef,\n useState,\n} from \"react\";\n\ntype PrefetchStrategy = \"hover\" | \"mount\" | \"click\" | \"none\" | boolean;\n\ninterface LinkBaseProps<H extends Route> extends Omit<\n AnchorHTMLAttributes<HTMLAnchorElement>,\n \"href\"\n> {\n /**\n * Where this goes. Typed to the routes the build found, so a link to a page\n * that does not exist stops compiling; `path as Route` when it is computed.\n */\n href: H;\n /**\n * The underlying anchor.\n *\n * Spread onto it like any other prop — React 19 passes ref through a\n * function component without forwardRef — but declared here because it is\n * not part of AnchorHTMLAttributes. A link that cannot be focused is a link\n * a dialog cannot move focus to when it opens.\n */\n ref?: Ref<HTMLAnchorElement>;\n prefetch?: PrefetchStrategy;\n cacheFor?: number;\n replace?: boolean;\n preserveScroll?: boolean;\n}\n\n/**\n * `search` is typed to the page's own `searchParams` schema when it exports\n * one — the same schema the page parses with, so a key it never reads or a\n * number written as text does not compile, and a key it requires is required\n * here. With no schema, any scalars. See SearchFor in routes.ts.\n */\ntype LinkProps<H extends Route> = LinkBaseProps<H> & SearchProp<H>;\n\nfunction isExternalUrl(url: string): boolean {\n try {\n return (\n new URL(url, window.location.origin).origin !== window.location.origin\n );\n } catch {\n return false;\n }\n}\n\nfunction shouldInterceptClick(e: MouseEvent<HTMLAnchorElement>): boolean {\n return (\n !e.defaultPrevented &&\n e.button === 0 &&\n !e.metaKey &&\n !e.ctrlKey &&\n !e.shiftKey &&\n !e.altKey\n );\n}\n\n/**\n * How long a pointer has to settle on a link before it prefetches.\n *\n * A pointer crossing a nav bar enters every link on the way, and each one used\n * to fire a request immediately — enough to fill the browser's per-origin\n * connection limit with pages the user never meant to visit. Waiting is close\n * to free: the prefetch only has to beat the click, and a click that follows a\n * hover this short would not have had its payload back anyway.\n */\nconst HOVER_PREFETCH_DELAY_MS = 100;\n\nexport default function Link<H extends Route>({\n href: path,\n search,\n prefetch: prefetchProp = \"hover\",\n cacheFor,\n replace = false,\n preserveScroll = false,\n children,\n onClick,\n onMouseEnter,\n onMouseLeave,\n onMouseDown,\n ref: callerRef,\n ...rest\n}: LinkProps<H>) {\n // The string the anchor and the router both use: the path, with the typed\n // search params serialised onto it.\n const href = (search ? withSearch(path, search as object) : path) as Route;\n const [pending, setPending] = useState(false);\n const hoverTimer = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n const prefetchStrategy =\n prefetchProp === true\n ? \"hover\"\n : prefetchProp === false\n ? \"none\"\n : prefetchProp;\n\n // `intent` is a hover that settled or a touch: the payload is decoded as\n // it lands, so the chunks the page names are loading before the click. A\n // link that only came into view fetches the bytes and stops there.\n const doPrefetch = useCallback(\n (intent = false) => {\n if (isExternalUrl(href)) return;\n const fn = (window as any).__rsc_prefetch;\n fn?.(href, cacheFor, intent);\n },\n [href, cacheFor],\n );\n\n // Only useEffect needed: prefetch on mount strategy\n useEffect(() => {\n if (prefetchStrategy === \"mount\") {\n doPrefetch();\n }\n }, [prefetchStrategy, doPrefetch]);\n\n // The link prefetches as it comes into view - the bytes, so a click finds\n // them however quick it is. See viewportPrefetch.\n const anchor = useRef<HTMLAnchorElement | null>(null);\n\n useEffect(() => {\n if (prefetchStrategy !== \"hover\") return;\n\n return prefetchWhenVisible(anchor.current, () => doPrefetch());\n }, [prefetchStrategy, doPrefetch]);\n\n const handleClick = useCallback(\n (e: MouseEvent<HTMLAnchorElement>) => {\n onClick?.(e);\n\n if (e.defaultPrevented) return;\n\n const target = (e.currentTarget as HTMLAnchorElement).target;\n if (target && target !== \"_self\") return;\n if (!shouldInterceptClick(e) || isExternalUrl(href)) return;\n\n // Hash-only links (#section) — let the browser scroll natively\n if (href.startsWith(\"#\")) return;\n\n e.preventDefault();\n setPending(true);\n\n // A hover that had not yet prefetched: the click is the navigation, and\n // a prefetch of the page being left for, firing after it, is a request\n // for nothing - seen as a stray 204 for a guarded link after landing\n // on the login page.\n if (hoverTimer.current !== null) {\n clearTimeout(hoverTimer.current);\n hoverTimer.current = null;\n }\n\n // navigate() returns a Promise — clear pending when it resolves or rejects\n const nav = (window as any).__rsc_navigate;\n const promise = nav?.(href, { replace, preserveScroll });\n promise?.then(\n () => setPending(false),\n () => setPending(false),\n );\n },\n [href, replace, preserveScroll, onClick],\n );\n\n const handleMouseEnter = useCallback(\n (e: MouseEvent<HTMLAnchorElement>) => {\n onMouseEnter?.(e);\n\n if (prefetchStrategy !== \"hover\" && prefetchStrategy !== \"click\") return;\n\n if (hoverTimer.current !== null) clearTimeout(hoverTimer.current);\n\n hoverTimer.current = setTimeout(() => {\n hoverTimer.current = null;\n doPrefetch(true);\n }, HOVER_PREFETCH_DELAY_MS);\n },\n [prefetchStrategy, doPrefetch, onMouseEnter],\n );\n\n const handleMouseLeave = useCallback(\n (e: MouseEvent<HTMLAnchorElement>) => {\n onMouseLeave?.(e);\n\n // Never fired: the pointer passed over on its way somewhere else.\n if (hoverTimer.current !== null) {\n clearTimeout(hoverTimer.current);\n hoverTimer.current = null;\n }\n\n // Already in flight: give the connection back to whatever the pointer is\n // heading for. A prefetch that has landed is kept — see cancelPrefetch.\n if (isExternalUrl(href)) return;\n (window as any).__rsc_cancel_prefetch?.(href);\n },\n [href, onMouseLeave],\n );\n\n // Touch gets no delay. There is no hovering to disambiguate — a touch is\n // already the start of a tap — and touchstart leads the click by little\n // enough that spending any of it waiting would waste the head start.\n //\n // And it decodes: the viewport prefetch that came before it, if one did,\n // fetched the bytes and left the chunks for the tap. This is the tap.\n const handleTouchStart = useCallback(() => {\n if (prefetchStrategy === \"hover\" || prefetchStrategy === \"click\") {\n doPrefetch(true);\n }\n }, [prefetchStrategy, doPrefetch]);\n\n // A press is a click 60-100 ms from landing, and a quick one comes before\n // the hover has settled. Whatever the hover did not, this does; whatever\n // it did, this finds done.\n const handleMouseDown = useCallback(\n (e: MouseEvent<HTMLAnchorElement>) => {\n onMouseDown?.(e);\n\n if (e.button !== 0) return;\n if (prefetchStrategy === \"hover\" || prefetchStrategy === \"click\") doPrefetch(true);\n },\n [prefetchStrategy, doPrefetch, onMouseDown],\n );\n\n // A link unmounted mid-hover (navigating away) must not prefetch afterwards.\n useEffect(\n () => () => {\n if (hoverTimer.current !== null) clearTimeout(hoverTimer.current);\n },\n [],\n );\n\n return (\n <LinkStatusContext.Provider value={{ pending }}>\n <a\n // The caller's ref still fills: a dialog moving focus to its link\n // needs the element as much as the observer above does.\n ref={(node) => {\n anchor.current = node;\n\n if (typeof callerRef === \"function\") callerRef(node);\n else if (callerRef) (callerRef as { current: HTMLAnchorElement | null }).current = node;\n }}\n href={href}\n // The mark the bootstrap script's click listener looks for: a tap\n // on this before the router exists is held for it. See earlyClicks.\n data-rsc=\"\"\n onClick={handleClick}\n onMouseEnter={handleMouseEnter}\n onMouseLeave={handleMouseLeave}\n onTouchStart={handleTouchStart}\n onMouseDown={handleMouseDown}\n data-pending={pending ? \"\" : undefined}\n {...rest}\n >\n {children}\n </a>\n </LinkStatusContext.Provider>\n );\n}\n"]}
|
|
1
|
+
{"version":3,"file":"Link.js","sourceRoot":"","sources":["../../src/js/Link.tsx"],"names":[],"mappings":"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","sourcesContent":["\"use client\";\n\nimport { LinkStatusContext } from \"./useLinkStatus.js\";\nimport { prefetchWhenVisible } from \"./viewportPrefetch.js\";\nimport { type Route, type SearchProp, withSearch } from \"../routes.js\";\nimport {\n type AnchorHTMLAttributes,\n type MouseEvent,\n type Ref,\n useCallback,\n useEffect,\n useRef,\n useState,\n} from \"react\";\n\ntype PrefetchStrategy = \"hover\" | \"mount\" | \"click\" | \"none\" | boolean;\n\ninterface LinkBaseProps<H extends Route> extends Omit<\n AnchorHTMLAttributes<HTMLAnchorElement>,\n \"href\"\n> {\n /**\n * Where this goes. Typed to the routes the build found, so a link to a page\n * that does not exist stops compiling; `path as Route` when it is computed.\n */\n href: H;\n /**\n * The underlying anchor.\n *\n * Spread onto it like any other prop — React 19 passes ref through a\n * function component without forwardRef — but declared here because it is\n * not part of AnchorHTMLAttributes. A link that cannot be focused is a link\n * a dialog cannot move focus to when it opens.\n */\n ref?: Ref<HTMLAnchorElement>;\n prefetch?: PrefetchStrategy;\n cacheFor?: number;\n replace?: boolean;\n preserveScroll?: boolean;\n}\n\n/**\n * `search` is typed to the page's own `searchParams` schema when it exports\n * one — the same schema the page parses with, so a key it never reads or a\n * number written as text does not compile, and a key it requires is required\n * here. With no schema, any scalars. See SearchFor in routes.ts.\n */\ntype LinkProps<H extends Route> = LinkBaseProps<H> & SearchProp<H>;\n\nfunction isExternalUrl(url: string): boolean {\n try {\n return (\n new URL(url, window.location.origin).origin !== window.location.origin\n );\n } catch {\n return false;\n }\n}\n\nfunction shouldInterceptClick(e: MouseEvent<HTMLAnchorElement>): boolean {\n return (\n !e.defaultPrevented &&\n e.button === 0 &&\n !e.metaKey &&\n !e.ctrlKey &&\n !e.shiftKey &&\n !e.altKey\n );\n}\n\n/**\n * How long a pointer has to settle on a link before it prefetches.\n *\n * A pointer crossing a nav bar enters every link on the way, and each one used\n * to fire a request immediately — enough to fill the browser's per-origin\n * connection limit with pages the user never meant to visit. Waiting is close\n * to free: the prefetch only has to beat the click, and a click that follows a\n * hover this short would not have had its payload back anyway.\n */\nconst HOVER_PREFETCH_DELAY_MS = 100;\n\nexport default function Link<H extends Route>({\n href: path,\n search,\n prefetch: prefetchProp = \"hover\",\n cacheFor,\n replace = false,\n preserveScroll = false,\n children,\n onClick,\n onMouseEnter,\n onMouseLeave,\n onMouseDown,\n ref: callerRef,\n ...rest\n}: LinkProps<H>) {\n // The string the anchor and the router both use: the path, with the typed\n // search params serialised onto it.\n const href = (search ? withSearch(path, search as object) : path) as Route;\n const [pending, setPending] = useState(false);\n const hoverTimer = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n const prefetchStrategy =\n prefetchProp === true\n ? \"hover\"\n : prefetchProp === false\n ? \"none\"\n : prefetchProp;\n\n // `intent` is a hover that settled or a touch: the payload is decoded as\n // it lands, so the chunks the page names are loading before the click. A\n // link that only came into view fetches the bytes and stops there.\n const doPrefetch = useCallback(\n (intent = false) => {\n if (isExternalUrl(href)) return;\n const fn = (window as any).__rsc_prefetch;\n fn?.(href, cacheFor, intent);\n },\n [href, cacheFor],\n );\n\n // Only useEffect needed: prefetch on mount strategy\n useEffect(() => {\n if (prefetchStrategy === \"mount\") {\n doPrefetch();\n }\n }, [prefetchStrategy, doPrefetch]);\n\n // The link prefetches as it comes into view - the bytes, so a click finds\n // them however quick it is. See viewportPrefetch.\n const anchor = useRef<HTMLAnchorElement | null>(null);\n\n useEffect(() => {\n if (prefetchStrategy !== \"hover\") return;\n\n return prefetchWhenVisible(anchor.current, () => doPrefetch());\n }, [prefetchStrategy, doPrefetch]);\n\n const handleClick = useCallback(\n (e: MouseEvent<HTMLAnchorElement>) => {\n onClick?.(e);\n\n if (e.defaultPrevented) return;\n\n const target = (e.currentTarget as HTMLAnchorElement).target;\n if (target && target !== \"_self\") return;\n if (!shouldInterceptClick(e) || isExternalUrl(href)) return;\n\n // Hash-only links (#section) — let the browser scroll natively\n if (href.startsWith(\"#\")) return;\n\n e.preventDefault();\n setPending(true);\n\n // A hover that had not yet prefetched: the click is the navigation, and\n // a prefetch of the page being left for, firing after it, is a request\n // for nothing - seen as a stray 204 for a guarded link after landing\n // on the login page.\n if (hoverTimer.current !== null) {\n clearTimeout(hoverTimer.current);\n hoverTimer.current = null;\n }\n\n // navigate() returns a Promise — clear pending when it resolves or rejects\n const nav = (window as any).__rsc_navigate;\n const promise = nav?.(href, { replace, preserveScroll });\n promise?.then(\n () => setPending(false),\n () => setPending(false),\n );\n },\n [href, replace, preserveScroll, onClick],\n );\n\n const handleMouseEnter = useCallback(\n (e: MouseEvent<HTMLAnchorElement>) => {\n onMouseEnter?.(e);\n\n if (prefetchStrategy !== \"hover\" && prefetchStrategy !== \"click\") return;\n\n if (hoverTimer.current !== null) clearTimeout(hoverTimer.current);\n\n hoverTimer.current = setTimeout(() => {\n hoverTimer.current = null;\n doPrefetch(true);\n }, HOVER_PREFETCH_DELAY_MS);\n },\n [prefetchStrategy, doPrefetch, onMouseEnter],\n );\n\n const handleMouseLeave = useCallback(\n (e: MouseEvent<HTMLAnchorElement>) => {\n onMouseLeave?.(e);\n\n // Never fired: the pointer passed over on its way somewhere else.\n if (hoverTimer.current !== null) {\n clearTimeout(hoverTimer.current);\n hoverTimer.current = null;\n }\n\n // Already in flight: give the connection back to whatever the pointer is\n // heading for. A prefetch that has landed is kept — see cancelPrefetch.\n if (isExternalUrl(href)) return;\n (window as any).__rsc_cancel_prefetch?.(href);\n },\n [href, onMouseLeave],\n );\n\n // Touch gets no delay. There is no hovering to disambiguate — a touch is\n // already the start of a tap — and touchstart leads the click by little\n // enough that spending any of it waiting would waste the head start.\n //\n // And it decodes: the viewport prefetch that came before it, if one did,\n // fetched the bytes and left the chunks for the tap. This is the tap.\n const handleTouchStart = useCallback(() => {\n if (prefetchStrategy === \"hover\" || prefetchStrategy === \"click\") {\n doPrefetch(true);\n }\n }, [prefetchStrategy, doPrefetch]);\n\n // A press is a click 60-100 ms from landing, and a quick one comes before\n // the hover has settled. Whatever the hover did not, this does; whatever\n // it did, this finds done.\n const handleMouseDown = useCallback(\n (e: MouseEvent<HTMLAnchorElement>) => {\n onMouseDown?.(e);\n\n if (e.button !== 0) return;\n if (prefetchStrategy === \"hover\" || prefetchStrategy === \"click\") doPrefetch(true);\n },\n [prefetchStrategy, doPrefetch, onMouseDown],\n );\n\n // A link unmounted mid-hover (navigating away) must not prefetch afterwards.\n useEffect(\n () => () => {\n if (hoverTimer.current !== null) clearTimeout(hoverTimer.current);\n },\n [],\n );\n\n return (\n <LinkStatusContext.Provider value={{ pending }}>\n <a\n // The caller's ref still fills: a dialog moving focus to its link\n // needs the element as much as the observer above does.\n ref={(node) => {\n anchor.current = node;\n\n if (typeof callerRef === \"function\") callerRef(node);\n else if (callerRef) (callerRef as { current: HTMLAnchorElement | null }).current = node;\n }}\n href={href}\n // The mark the bootstrap script's click listener looks for: a tap\n // on this before the router exists is held for it. See earlyClicks.\n data-rsc=\"\"\n onClick={handleClick}\n onMouseEnter={handleMouseEnter}\n onMouseLeave={handleMouseLeave}\n onTouchStart={handleTouchStart}\n onMouseDown={handleMouseDown}\n data-pending={pending ? \"\" : undefined}\n {...rest}\n >\n {children}\n </a>\n </LinkStatusContext.Provider>\n );\n}\n"]}
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
import { Component, createElement } from "react";
|
|
3
3
|
import { parseRedirectDigest } from "../redirectDigest.js";
|
|
4
4
|
import { isNotFoundDigest } from "../notFound.js";
|
|
5
|
-
import { visit } from "./router";
|
|
6
|
-
import { DefaultRouteError } from "./DefaultRouteError";
|
|
5
|
+
import { visit } from "./router.js";
|
|
6
|
+
import { DefaultRouteError } from "./DefaultRouteError.js";
|
|
7
7
|
export class RedirectBoundary extends Component {
|
|
8
8
|
state = {
|
|
9
9
|
redirecting: false,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RedirectBoundary.js","sourceRoot":"","sources":["../../src/js/RedirectBoundary.tsx"],"names":[],"mappings":"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","sourcesContent":["\"use client\";\n\n/**\n * Performs a redirect, or shows a missing page, that was decided too late to\n * be a status code.\n *\n * A redirect thrown above every Suspense boundary is answered by the host\n * before anything is written — the browser never sees this page, and this\n * component is never involved. One thrown inside a boundary arrives after the\n * shell, as an error carrying the destination in its digest, and this is what\n * turns that back into a navigation.\n *\n * An error boundary rather than a hook because that is the only thing React\n * offers for \"a child threw\": the throw happens in a server component whose\n * error is serialised into the payload, and it surfaces here when the client\n * renders it.\n *\n * A page that said it does not exist, after its shell was sent, arrives the\n * same way and is answered the same way: the server is asked for not-found.tsx\n * for this url and it is rendered where the page was, with the layouts kept and\n * the url and its history entry as they are. The status is already 200 and the\n * document says noindex; this is what a person sees.\n *\n * Anything that is neither is rethrown untouched, so an app's own error\n * boundaries still see the errors they exist for.\n */\n\nimport type { Route } from \"../routes.js\";\nimport { Component, createElement } from \"react\";\nimport type { ErrorInfo, ReactNode } from \"react\";\nimport { parseRedirectDigest } from \"../redirectDigest.js\";\nimport { isNotFoundDigest } from \"../notFound.js\";\nimport { visit } from \"./router\";\nimport { DefaultRouteError } from \"./DefaultRouteError\";\n\ninterface Props {\n children: ReactNode;\n /** Shown while the navigation is in flight. Null keeps the space empty. */\n fallback?: ReactNode;\n /**\n * Whether what this boundary wraps is the page on screen. A segment keeps\n * pages alive behind the active one, each under its own boundary, and a\n * redirect caught on a page that is not showing is not performed — it was\n * already performed when it was. Shown again, the boundary renders the\n * page afresh, and a refusal that still stands redirects again.\n */\n active?: boolean;\n}\n\ninterface State {\n redirecting: boolean;\n wasActive: boolean;\n /** A missing page that could not be answered with one: shown as the error it is. */\n failed: unknown;\n /** The children that said the page is missing, while not-found.tsx is being fetched. */\n asked: ReactNode | null;\n /** Whether not-found.tsx has been fetched and put where those children were. */\n answered: boolean;\n /** The children that are the answer, so a page replacing it is told from it. */\n shown: ReactNode | null;\n}\n\nexport class RedirectBoundary extends Component<Props, State> {\n state: State = {\n redirecting: false,\n wasActive: this.props.active !== false,\n failed: null,\n asked: null,\n answered: false,\n shown: null,\n };\n\n static getDerivedStateFromError(error: unknown): Partial<State> | null {\n // Reading `digest` rather than the message: React replaces a server\n // error's message in production and transmits the digest either way.\n const digest = (error as { digest?: unknown })?.digest;\n\n return parseRedirectDigest(digest) || isNotFoundDigest(digest) ? { redirecting: true } : null;\n }\n\n static getDerivedStateFromProps(props: Props, state: State): Partial<State> | null {\n const active = props.active !== false;\n let next: Partial<State> = {};\n\n // Revealed again: render the page, not the space left by its redirect.\n if (active !== state.wasActive) {\n next = { wasActive: active, redirecting: active ? false : state.redirecting };\n }\n\n // The tree that stands for a missing page has replaced the one that threw:\n // render it. Not before the answer is in - a parent rendering again hands\n // down new children that are the same page, and rendering those would\n // throw again.\n if (state.asked !== null && state.answered && props.children !== state.asked) {\n next = { ...next, asked: null, shown: props.children, redirecting: false };\n } else if (state.shown !== null && props.children !== state.shown) {\n // Something else took its place - the person came back to a page that\n // exists now. The next missing page is a first one again.\n next = { ...next, shown: null, answered: false };\n }\n\n return Object.keys(next).length ? next : null;\n }\n\n componentDidCatch(error: unknown, _info: ErrorInfo): void {\n const digest = (error as { digest?: unknown })?.digest;\n\n if (isNotFoundDigest(digest)) return this.showNotFound(error);\n\n const target = parseRedirectDigest(digest);\n\n if (!target) throw error;\n if (this.props.active === false) return;\n\n // An SPA navigation, not a location assignment: the layouts above this\n // boundary are already mounted and correct, so replacing the document\n // would throw away state the user can see — including whatever they had\n // typed into a page that is only being redirected past.\n //\n // replace, because the url being left never became a page the user was\n // on; leaving a history entry for it means Back returns to a redirect.\n // The server chose this, so it is not one of the app's authored hrefs.\n void visit(target.location as Route, { replace: true });\n }\n\n private showNotFound(error: unknown): void {\n if (this.props.active === false) return;\n\n // The answer itself said the page is missing: a not-found.tsx that calls\n // notFound() would otherwise be answered with itself for ever. It is\n // shown as the error it has become.\n if (this.state.answered) {\n this.setState({ failed: error });\n\n return;\n }\n\n const here = window.location.pathname + window.location.search;\n\n this.setState({ asked: this.props.children });\n\n // replace: the url is the page's own, and nothing was pushed for it to\n // leave behind. Not-found.tsx replaces the page in the history entry the\n // person is already on.\n visit(here as Route, { replace: true, notFound: true }).then(\n () => this.setState({ answered: true }),\n // Announced by the navigation as rsc-navigate-error. The person is left\n // with the error the page would have shown, not an empty space.\n () => this.setState({ failed: error }),\n );\n }\n\n render(): ReactNode {\n if (this.state.failed) {\n return createElement(DefaultRouteError as never, {\n error: this.state.failed,\n reset: () => this.setState({ failed: null, redirecting: false }),\n });\n }\n\n if (this.state.redirecting) return this.props.fallback ?? null;\n\n return this.props.children;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"RedirectBoundary.js","sourceRoot":"","sources":["../../src/js/RedirectBoundary.tsx"],"names":[],"mappings":"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","sourcesContent":["\"use client\";\n\n/**\n * Performs a redirect, or shows a missing page, that was decided too late to\n * be a status code.\n *\n * A redirect thrown above every Suspense boundary is answered by the host\n * before anything is written — the browser never sees this page, and this\n * component is never involved. One thrown inside a boundary arrives after the\n * shell, as an error carrying the destination in its digest, and this is what\n * turns that back into a navigation.\n *\n * An error boundary rather than a hook because that is the only thing React\n * offers for \"a child threw\": the throw happens in a server component whose\n * error is serialised into the payload, and it surfaces here when the client\n * renders it.\n *\n * A page that said it does not exist, after its shell was sent, arrives the\n * same way and is answered the same way: the server is asked for not-found.tsx\n * for this url and it is rendered where the page was, with the layouts kept and\n * the url and its history entry as they are. The status is already 200 and the\n * document says noindex; this is what a person sees.\n *\n * Anything that is neither is rethrown untouched, so an app's own error\n * boundaries still see the errors they exist for.\n */\n\nimport type { Route } from \"../routes.js\";\nimport { Component, createElement } from \"react\";\nimport type { ErrorInfo, ReactNode } from \"react\";\nimport { parseRedirectDigest } from \"../redirectDigest.js\";\nimport { isNotFoundDigest } from \"../notFound.js\";\nimport { visit } from \"./router.js\";\nimport { DefaultRouteError } from \"./DefaultRouteError.js\";\n\ninterface Props {\n children: ReactNode;\n /** Shown while the navigation is in flight. Null keeps the space empty. */\n fallback?: ReactNode;\n /**\n * Whether what this boundary wraps is the page on screen. A segment keeps\n * pages alive behind the active one, each under its own boundary, and a\n * redirect caught on a page that is not showing is not performed — it was\n * already performed when it was. Shown again, the boundary renders the\n * page afresh, and a refusal that still stands redirects again.\n */\n active?: boolean;\n}\n\ninterface State {\n redirecting: boolean;\n wasActive: boolean;\n /** A missing page that could not be answered with one: shown as the error it is. */\n failed: unknown;\n /** The children that said the page is missing, while not-found.tsx is being fetched. */\n asked: ReactNode | null;\n /** Whether not-found.tsx has been fetched and put where those children were. */\n answered: boolean;\n /** The children that are the answer, so a page replacing it is told from it. */\n shown: ReactNode | null;\n}\n\nexport class RedirectBoundary extends Component<Props, State> {\n state: State = {\n redirecting: false,\n wasActive: this.props.active !== false,\n failed: null,\n asked: null,\n answered: false,\n shown: null,\n };\n\n static getDerivedStateFromError(error: unknown): Partial<State> | null {\n // Reading `digest` rather than the message: React replaces a server\n // error's message in production and transmits the digest either way.\n const digest = (error as { digest?: unknown })?.digest;\n\n return parseRedirectDigest(digest) || isNotFoundDigest(digest) ? { redirecting: true } : null;\n }\n\n static getDerivedStateFromProps(props: Props, state: State): Partial<State> | null {\n const active = props.active !== false;\n let next: Partial<State> = {};\n\n // Revealed again: render the page, not the space left by its redirect.\n if (active !== state.wasActive) {\n next = { wasActive: active, redirecting: active ? false : state.redirecting };\n }\n\n // The tree that stands for a missing page has replaced the one that threw:\n // render it. Not before the answer is in - a parent rendering again hands\n // down new children that are the same page, and rendering those would\n // throw again.\n if (state.asked !== null && state.answered && props.children !== state.asked) {\n next = { ...next, asked: null, shown: props.children, redirecting: false };\n } else if (state.shown !== null && props.children !== state.shown) {\n // Something else took its place - the person came back to a page that\n // exists now. The next missing page is a first one again.\n next = { ...next, shown: null, answered: false };\n }\n\n return Object.keys(next).length ? next : null;\n }\n\n componentDidCatch(error: unknown, _info: ErrorInfo): void {\n const digest = (error as { digest?: unknown })?.digest;\n\n if (isNotFoundDigest(digest)) return this.showNotFound(error);\n\n const target = parseRedirectDigest(digest);\n\n if (!target) throw error;\n if (this.props.active === false) return;\n\n // An SPA navigation, not a location assignment: the layouts above this\n // boundary are already mounted and correct, so replacing the document\n // would throw away state the user can see — including whatever they had\n // typed into a page that is only being redirected past.\n //\n // replace, because the url being left never became a page the user was\n // on; leaving a history entry for it means Back returns to a redirect.\n // The server chose this, so it is not one of the app's authored hrefs.\n void visit(target.location as Route, { replace: true });\n }\n\n private showNotFound(error: unknown): void {\n if (this.props.active === false) return;\n\n // The answer itself said the page is missing: a not-found.tsx that calls\n // notFound() would otherwise be answered with itself for ever. It is\n // shown as the error it has become.\n if (this.state.answered) {\n this.setState({ failed: error });\n\n return;\n }\n\n const here = window.location.pathname + window.location.search;\n\n this.setState({ asked: this.props.children });\n\n // replace: the url is the page's own, and nothing was pushed for it to\n // leave behind. Not-found.tsx replaces the page in the history entry the\n // person is already on.\n visit(here as Route, { replace: true, notFound: true }).then(\n () => this.setState({ answered: true }),\n // Announced by the navigation as rsc-navigate-error. The person is left\n // with the error the page would have shown, not an empty space.\n () => this.setState({ failed: error }),\n );\n }\n\n render(): ReactNode {\n if (this.state.failed) {\n return createElement(DefaultRouteError as never, {\n error: this.state.failed,\n reset: () => this.setState({ failed: null, redirecting: false }),\n });\n }\n\n if (this.state.redirecting) return this.props.fallback ?? null;\n\n return this.props.children;\n }\n}\n"]}
|
|
@@ -43,11 +43,11 @@ export const NAVIGATION_TRANSITION_TYPE = "rsc-navigation";
|
|
|
43
43
|
const addTransitionType = React.addTransitionType ??
|
|
44
44
|
React
|
|
45
45
|
.unstable_addTransitionType;
|
|
46
|
-
import { SegmentDepthContext } from "./segmentDepth";
|
|
47
|
-
import { RedirectBoundary } from "./RedirectBoundary";
|
|
48
|
-
import { retentionKey } from "../routing";
|
|
49
|
-
import { navigationCommitted } from "./perf";
|
|
50
|
-
import { getSegmentState, replaceActive, navigatedOnce, seedSegment, subscribeToSegment, } from "./segmentStore";
|
|
46
|
+
import { SegmentDepthContext } from "./segmentDepth.js";
|
|
47
|
+
import { RedirectBoundary } from "./RedirectBoundary.js";
|
|
48
|
+
import { retentionKey } from "../routing.js";
|
|
49
|
+
import { navigationCommitted } from "./perf.js";
|
|
50
|
+
import { getSegmentState, replaceActive, navigatedOnce, seedSegment, subscribeToSegment, } from "./segmentStore.js";
|
|
51
51
|
/**
|
|
52
52
|
* The key the page this document arrived with is filed under: the url's,
|
|
53
53
|
* query included, when the url is that page - which is always, in an app,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SegmentBoundary.js","sourceRoot":"","sources":["../../src/js/SegmentBoundary.tsx"],"names":[],"mappings":"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","sourcesContent":["\"use client\";\n\n/**\n * The point in the tree a navigation can replace on its own.\n *\n * Sits between a layout and its children, so showing a different segment\n * re-renders from here down and leaves the layouts above it mounted. Server\n * components cannot be re-rendered on the client, which is why the seam has to\n * be a client component reading from a store rather than the layout itself.\n *\n * Pages it has already shown stay mounted behind <Activity mode=\"hidden\">.\n * Hidden is not unmounted: effects are torn down but state survives, so\n * returning to a page brings back the form you were filling in. Rendering only\n * the current one would throw that away, which is what replacing the root did.\n */\n\nimport * as React from \"react\";\nimport { Activity, startTransition, useEffect, useState } from \"react\";\n\n/**\n * The transition type a navigation carries.\n *\n * The engine does not animate a navigation itself; React's own\n * <ViewTransition> does, wherever an app puts one. What the app cannot do\n * from outside is tell a navigation from the seed after hydration - the\n * boundary taking over its own server-rendered children, which animated\n * would be the page fading into itself on every load. So a navigation's\n * update carries this type, and the seed's does not: a boundary keyed on it,\n * `default={{ \"rsc-navigation\": \"page\", default: \"none\" }}`, animates\n * navigations and nothing else.\n *\n * An earlier shape wrapped the segment in a boundary of the engine's own,\n * behind a flag. React names every top-level element under a boundary and\n * morphs each from where it was to where it is, so the stylesheet pulled\n * them back into one root fade - and fought React over the root, which it\n * cancels when nothing outside a boundary changed: a captured root with a\n * hidden group, a dark viewport on the first navigation. One wrapper element\n * under the app's own boundary is one snapshot pair, which is the dissolve\n * wanted, with nothing to fight.\n */\nexport const NAVIGATION_TRANSITION_TYPE = \"rsc-navigation\";\n\n// Exported by React 19.3; `unstable_` before it. Read at call time from the\n// namespace rather than imported by name, so a React that lacks it still\n// loads this module and simply does not mark the type.\nconst addTransitionType: ((type: string) => void) | undefined =\n (React as { addTransitionType?: (type: string) => void }).addTransitionType ??\n (React as { unstable_addTransitionType?: (type: string) => void })\n .unstable_addTransitionType;\nimport type { ReactNode } from \"react\";\nimport { SegmentDepthContext } from \"./segmentDepth\";\nimport { RedirectBoundary } from \"./RedirectBoundary\";\nimport { retentionKey } from \"../routing\";\nimport { navigationCommitted } from \"./perf\";\nimport {\n getSegmentState,\n replaceActive,\n navigatedOnce,\n seedSegment,\n subscribeToSegment,\n} from \"./segmentStore\";\n\n/**\n * The key the page this document arrived with is filed under: the url's,\n * query included, when the url is that page - which is always, in an app,\n * because the server keys a page by the document's own pathname. Anything\n * else keeps the server's key rather than guess.\n */\nfunction seedKey(pageKey: string): string {\n if (typeof window === \"undefined\") return pageKey;\n\n return retentionKey(window.location.pathname, null) === retentionKey(pageKey, null)\n ? retentionKey(window.location.pathname + window.location.search, null)\n : pageKey;\n}\n\nexport function SegmentBoundary({\n depth,\n pageKey,\n children,\n}: {\n depth: number;\n /** The page these server-rendered children belong to. */\n pageKey?: string;\n children: ReactNode;\n}) {\n // The store still addresses the boundary; the render reads React state, so\n // the update can be a transition. Initialised from the store on the client\n // and null on the server — exactly what getServerSnapshot did.\n const [state, setState] = useState<ReturnType<typeof getSegmentState>>(() =>\n typeof window === \"undefined\" ? null : getSegmentState(depth),\n );\n\n // A pattern shell is rendered for every url its route matches, so its tree\n // carries no key - and neither does the payload its resume streams in. The\n // page is still this url's: filed under it, read once, at the document's\n // own boot.\n const [fallback] = useState(() =>\n typeof window !== \"undefined\" && !navigatedOnce() ? window.location.pathname : \"\",\n );\n const key = pageKey || fallback;\n\n useEffect(\n () =>\n subscribeToSegment(depth, () => {\n startTransition(() => {\n // A navigation, not the seed: the seed is the page taking over\n // its own server-rendered children, and fading that is the page\n // fading into itself.\n if (navigatedOnce()) addTransitionType?.(NAVIGATION_TRANSITION_TYPE);\n\n setState(getSegmentState(depth));\n });\n }),\n [depth],\n );\n\n // The commit that put a navigated segment on screen: the end of the\n // navigation's measure, see perf.ts. Not on the first render, which is the\n // seed.\n useEffect(() => {\n if (state !== null) navigationCommitted();\n }, [state]);\n\n // Record the page we arrived on, so a later navigation away and back can\n // return to it. Without this the first page is the one page you cannot keep.\n // New children while the store already holds this depth is the document\n // rendered again in place - revalidate(\"all\") - and the page on screen\n // takes them under the key it has; see replaceActive.\n useEffect(() => {\n if (getSegmentState(depth)) replaceActive(depth, children);\n // Filed under the url's key, path and query, which is what every\n // navigation and refresh looks it up by; mounted under the server's, the\n // pathname the shell was frozen with. Seeded under the server's alone,\n // the first refresh of a page loaded at ?c=25 found nothing, mounted a\n // second copy, and showed every fallback in it.\n else if (key) seedSegment(depth, seedKey(key), children, key);\n }, [depth, key, children]);\n\n // Wrapped here rather than around the whole app because this is the closest\n // client component above a page: a redirect thrown inside the page's own\n // Suspense boundary surfaces at the nearest error boundary, and catching it\n // here leaves the layouts above mounted while the navigation runs. One\n // boundary per page, inside its Activity, not one around them all: a\n // boundary that catches renders its fallback in place of everything it\n // wraps, and one around them all unmounted every page being kept alive\n // behind the one redirecting - the destination among them, when it was\n // held - and then kept showing the fallback over the destination once it\n // arrived. The port's report was a sidebar and a breadcrumb over an empty\n // main.\n // The same shape before and after the seed. The server's render and the\n // first client render already place the children inside the retention\n // wrapper, keyed by the page, so when the store takes over after hydration\n // the tree changes state but not shape - and React keeps the DOM instead of\n // remounting the page, which was blank, then content, on every load.\n //\n // The Activity is there whether or not there is a page key to hang it on.\n // A parameterised route's PPR shell is rendered for every url it matches\n // and so carries no key - and the boundary used to leave the Activity out\n // then, so the shell had no <!--&--> markers where the client, hydrating\n // from the payload for the real url, rendered one. React 19.2 does not\n // recover from a hydration mismatch at an Activity: the boundary retries\n // hydrating, mismatches again, and the main thread never returns. A port\n // found /agent/tools/3 freezing the tab on every document load. The\n // markup of an Activity does not depend on its key, so the shell and the\n // client agree whenever both render one.\n return (\n <SegmentDepthContext value={depth}>\n {!state ? (\n <Activity key={key} mode=\"visible\">\n <RedirectBoundary>{children}</RedirectBoundary>\n </Activity>\n ) : state.entries.map((entry) => (\n <Activity\n key={entry.identity ?? entry.key}\n mode={entry.key === state.activeKey ? \"visible\" : \"hidden\"}\n >\n <RedirectBoundary active={entry.key === state.activeKey}>\n {entry.tree as ReactNode}\n </RedirectBoundary>\n </Activity>\n ))}\n </SegmentDepthContext>\n );\n}\n"]}
|
|
1
|
+
{"version":3,"file":"SegmentBoundary.js","sourceRoot":"","sources":["../../src/js/SegmentBoundary.tsx"],"names":[],"mappings":"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","sourcesContent":["\"use client\";\n\n/**\n * The point in the tree a navigation can replace on its own.\n *\n * Sits between a layout and its children, so showing a different segment\n * re-renders from here down and leaves the layouts above it mounted. Server\n * components cannot be re-rendered on the client, which is why the seam has to\n * be a client component reading from a store rather than the layout itself.\n *\n * Pages it has already shown stay mounted behind <Activity mode=\"hidden\">.\n * Hidden is not unmounted: effects are torn down but state survives, so\n * returning to a page brings back the form you were filling in. Rendering only\n * the current one would throw that away, which is what replacing the root did.\n */\n\nimport * as React from \"react\";\nimport { Activity, startTransition, useEffect, useState } from \"react\";\n\n/**\n * The transition type a navigation carries.\n *\n * The engine does not animate a navigation itself; React's own\n * <ViewTransition> does, wherever an app puts one. What the app cannot do\n * from outside is tell a navigation from the seed after hydration - the\n * boundary taking over its own server-rendered children, which animated\n * would be the page fading into itself on every load. So a navigation's\n * update carries this type, and the seed's does not: a boundary keyed on it,\n * `default={{ \"rsc-navigation\": \"page\", default: \"none\" }}`, animates\n * navigations and nothing else.\n *\n * An earlier shape wrapped the segment in a boundary of the engine's own,\n * behind a flag. React names every top-level element under a boundary and\n * morphs each from where it was to where it is, so the stylesheet pulled\n * them back into one root fade - and fought React over the root, which it\n * cancels when nothing outside a boundary changed: a captured root with a\n * hidden group, a dark viewport on the first navigation. One wrapper element\n * under the app's own boundary is one snapshot pair, which is the dissolve\n * wanted, with nothing to fight.\n */\nexport const NAVIGATION_TRANSITION_TYPE = \"rsc-navigation\";\n\n// Exported by React 19.3; `unstable_` before it. Read at call time from the\n// namespace rather than imported by name, so a React that lacks it still\n// loads this module and simply does not mark the type.\nconst addTransitionType: ((type: string) => void) | undefined =\n (React as { addTransitionType?: (type: string) => void }).addTransitionType ??\n (React as { unstable_addTransitionType?: (type: string) => void })\n .unstable_addTransitionType;\nimport type { ReactNode } from \"react\";\nimport { SegmentDepthContext } from \"./segmentDepth.js\";\nimport { RedirectBoundary } from \"./RedirectBoundary.js\";\nimport { retentionKey } from \"../routing.js\";\nimport { navigationCommitted } from \"./perf.js\";\nimport {\n getSegmentState,\n replaceActive,\n navigatedOnce,\n seedSegment,\n subscribeToSegment,\n} from \"./segmentStore.js\";\n\n/**\n * The key the page this document arrived with is filed under: the url's,\n * query included, when the url is that page - which is always, in an app,\n * because the server keys a page by the document's own pathname. Anything\n * else keeps the server's key rather than guess.\n */\nfunction seedKey(pageKey: string): string {\n if (typeof window === \"undefined\") return pageKey;\n\n return retentionKey(window.location.pathname, null) === retentionKey(pageKey, null)\n ? retentionKey(window.location.pathname + window.location.search, null)\n : pageKey;\n}\n\nexport function SegmentBoundary({\n depth,\n pageKey,\n children,\n}: {\n depth: number;\n /** The page these server-rendered children belong to. */\n pageKey?: string;\n children: ReactNode;\n}) {\n // The store still addresses the boundary; the render reads React state, so\n // the update can be a transition. Initialised from the store on the client\n // and null on the server — exactly what getServerSnapshot did.\n const [state, setState] = useState<ReturnType<typeof getSegmentState>>(() =>\n typeof window === \"undefined\" ? null : getSegmentState(depth),\n );\n\n // A pattern shell is rendered for every url its route matches, so its tree\n // carries no key - and neither does the payload its resume streams in. The\n // page is still this url's: filed under it, read once, at the document's\n // own boot.\n const [fallback] = useState(() =>\n typeof window !== \"undefined\" && !navigatedOnce() ? window.location.pathname : \"\",\n );\n const key = pageKey || fallback;\n\n useEffect(\n () =>\n subscribeToSegment(depth, () => {\n startTransition(() => {\n // A navigation, not the seed: the seed is the page taking over\n // its own server-rendered children, and fading that is the page\n // fading into itself.\n if (navigatedOnce()) addTransitionType?.(NAVIGATION_TRANSITION_TYPE);\n\n setState(getSegmentState(depth));\n });\n }),\n [depth],\n );\n\n // The commit that put a navigated segment on screen: the end of the\n // navigation's measure, see perf.ts. Not on the first render, which is the\n // seed.\n useEffect(() => {\n if (state !== null) navigationCommitted();\n }, [state]);\n\n // Record the page we arrived on, so a later navigation away and back can\n // return to it. Without this the first page is the one page you cannot keep.\n // New children while the store already holds this depth is the document\n // rendered again in place - revalidate(\"all\") - and the page on screen\n // takes them under the key it has; see replaceActive.\n useEffect(() => {\n if (getSegmentState(depth)) replaceActive(depth, children);\n // Filed under the url's key, path and query, which is what every\n // navigation and refresh looks it up by; mounted under the server's, the\n // pathname the shell was frozen with. Seeded under the server's alone,\n // the first refresh of a page loaded at ?c=25 found nothing, mounted a\n // second copy, and showed every fallback in it.\n else if (key) seedSegment(depth, seedKey(key), children, key);\n }, [depth, key, children]);\n\n // Wrapped here rather than around the whole app because this is the closest\n // client component above a page: a redirect thrown inside the page's own\n // Suspense boundary surfaces at the nearest error boundary, and catching it\n // here leaves the layouts above mounted while the navigation runs. One\n // boundary per page, inside its Activity, not one around them all: a\n // boundary that catches renders its fallback in place of everything it\n // wraps, and one around them all unmounted every page being kept alive\n // behind the one redirecting - the destination among them, when it was\n // held - and then kept showing the fallback over the destination once it\n // arrived. The port's report was a sidebar and a breadcrumb over an empty\n // main.\n // The same shape before and after the seed. The server's render and the\n // first client render already place the children inside the retention\n // wrapper, keyed by the page, so when the store takes over after hydration\n // the tree changes state but not shape - and React keeps the DOM instead of\n // remounting the page, which was blank, then content, on every load.\n //\n // The Activity is there whether or not there is a page key to hang it on.\n // A parameterised route's PPR shell is rendered for every url it matches\n // and so carries no key - and the boundary used to leave the Activity out\n // then, so the shell had no <!--&--> markers where the client, hydrating\n // from the payload for the real url, rendered one. React 19.2 does not\n // recover from a hydration mismatch at an Activity: the boundary retries\n // hydrating, mismatches again, and the main thread never returns. A port\n // found /agent/tools/3 freezing the tab on every document load. The\n // markup of an Activity does not depend on its key, so the shell and the\n // client agree whenever both render one.\n return (\n <SegmentDepthContext value={depth}>\n {!state ? (\n <Activity key={key} mode=\"visible\">\n <RedirectBoundary>{children}</RedirectBoundary>\n </Activity>\n ) : state.entries.map((entry) => (\n <Activity\n key={entry.identity ?? entry.key}\n mode={entry.key === state.activeKey ? \"visible\" : \"hidden\"}\n >\n <RedirectBoundary active={entry.key === state.activeKey}>\n {entry.tree as ReactNode}\n </RedirectBoundary>\n </Activity>\n ))}\n </SegmentDepthContext>\n );\n}\n"]}
|
package/dist/js/SlotBoundary.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
3
|
import { startTransition, useContext, useEffect, useState } from "react";
|
|
4
|
-
import { getSlotState, subscribeToSlot } from "./slotStore";
|
|
5
|
-
import { RedirectBoundary } from "./RedirectBoundary";
|
|
6
|
-
import { SegmentDepthContext } from "./segmentDepth";
|
|
4
|
+
import { getSlotState, subscribeToSlot } from "./slotStore.js";
|
|
5
|
+
import { RedirectBoundary } from "./RedirectBoundary.js";
|
|
6
|
+
import { SegmentDepthContext } from "./segmentDepth.js";
|
|
7
7
|
/**
|
|
8
8
|
* The seam a re-rendered slot is swapped in at.
|
|
9
9
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SlotBoundary.js","sourceRoot":"","sources":["../../src/js/SlotBoundary.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAEzE,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"SlotBoundary.js","sourceRoot":"","sources":["../../src/js/SlotBoundary.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAEzE,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAC/D,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAExD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,UAAU,YAAY,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAyC;IACpF,0DAA0D;IAC1D,MAAM,KAAK,GAAG,UAAU,CAAC,mBAAmB,CAAC,CAAC;IAC9C,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAC,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC;IAE7D,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,IAAI,GAAG,GAAG,EAAE,CAAC,eAAe,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACvE,MAAM,WAAW,GAAG,eAAe,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;QAEvD,wEAAwE;QACxE,oBAAoB;QACpB,IAAI,EAAE,CAAC;QAEP,OAAO,WAAW,CAAC;IACrB,CAAC,EAAE,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC;IAElB,OAAO,CACL,KAAC,gBAAgB,cACd,CAAC,KAAK,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAc,GAC/C,CACpB,CAAC;AACJ,CAAC","sourcesContent":["\"use client\";\n\nimport { startTransition, useContext, useEffect, useState } from \"react\";\nimport type { ReactNode } from \"react\";\nimport { getSlotState, subscribeToSlot } from \"./slotStore.js\";\nimport { RedirectBoundary } from \"./RedirectBoundary.js\";\nimport { SegmentDepthContext } from \"./segmentDepth.js\";\n\n/**\n * The seam a re-rendered slot is swapped in at.\n *\n * Server components cannot be re-rendered in the browser, so the swap point\n * has to be a client component reading from a store. With nothing stored it\n * renders what the server sent with the page — which is the behaviour that\n * existed before slots could be revalidated, and is what makes this safe to\n * wrap every slot in.\n *\n * Inside a RedirectBoundary, because a slot is a page too and may decide a\n * redirect inside its own Suspense boundary. A slot of a nested layout sits\n * under the SegmentBoundary above it, which carries one; a slot of the root\n * layout sits under nothing, and without this its redirect would unmount\n * the document.\n *\n * A refresh is swapped in as a transition. Read through useSyncExternalStore it\n * was applied at once - React never treats that store's update as one it can\n * hold back - so content still arriving suspended to the nearest fallback, and\n * a team picker and its breadcrumb blinked to their skeleton on every save.\n * Held in this boundary's state instead, React keeps what is on screen until\n * the new content is ready, and one that is ready shows at once.\n */\nexport function SlotBoundary({ name, children }: { name: string; children: ReactNode }) {\n // Which navigation replaces this region - see clearSlots.\n const depth = useContext(SegmentDepthContext);\n const [state, setState] = useState(() => getSlotState(name));\n\n useEffect(() => {\n const sync = () => startTransition(() => setState(getSlotState(name)));\n const unsubscribe = subscribeToSlot(name, sync, depth);\n\n // A write between the render and this subscription would otherwise wait\n // for the next one.\n sync();\n\n return unsubscribe;\n }, [name, depth]);\n\n return (\n <RedirectBoundary>\n {(state.tree === undefined ? children : state.tree) as ReactNode}\n </RedirectBoundary>\n );\n}\n"]}
|
package/dist/js/changesStore.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
// name, through the same refresh() a page calls itself. One stream per tab
|
|
7
7
|
// however many regions, reopened only when the set of names changes, closed
|
|
8
8
|
// while the tab is hidden and caught up when it is seen again.
|
|
9
|
-
import { refresh, refreshOnChange } from "./router";
|
|
9
|
+
import { refresh, refreshOnChange } from "./router.js";
|
|
10
10
|
const CHANGES_PATH = "/_rsc/changes";
|
|
11
11
|
const registrations = new Set();
|
|
12
12
|
let source = null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"changesStore.js","sourceRoot":"","sources":["../../src/js/changesStore.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,EAAE;AACF,4EAA4E;AAC5E,0EAA0E;AAC1E,2EAA2E;AAC3E,2EAA2E;AAC3E,4EAA4E;AAC5E,+DAA+D;AAE/D,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAQpD,MAAM,YAAY,GAAG,eAAe,CAAC;AAErC,MAAM,aAAa,GAAG,IAAI,GAAG,EAAgB,CAAC;AAE9C,IAAI,MAAM,GAAuB,IAAI,CAAC;AACtC,IAAI,UAAU,GAAG,EAAE,CAAC;AACpB,IAAI,MAAiD,CAAC;AACtD,IAAI,KAAgD,CAAC;AACrD,IAAI,QAAQ,GAAG,CAAC,CAAC;AACjB,IAAI,SAAS,GAAG,KAAK,CAAC;AAEtB,oFAAoF;AACpF,MAAM,UAAU,QAAQ,CAAC,KAAmB;IAC1C,aAAa,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IACzB,QAAQ,EAAE,CAAC;IAEX,OAAO,GAAG,EAAE;QACV,aAAa,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAC5B,QAAQ,EAAE,CAAC;IACb,CAAC,CAAC;AACJ,CAAC;AAED,SAAS,MAAM;IACb,IAAI,SAAS,IAAI,OAAO,QAAQ,KAAK,WAAW;QAAE,OAAO;IAEzD,SAAS,GAAG,IAAI,CAAC;IACjB,QAAQ,CAAC,gBAAgB,CAAC,kBAAkB,EAAE,GAAG,EAAE;QACjD,IAAI,CAAC,QAAQ,CAAC,MAAM;YAAE,OAAO,QAAQ,EAAE,CAAC;QAExC,uEAAuE;QACvE,wEAAwE;QACxE,uCAAuC;QACvC,IAAI,MAAM;YACR,IAAI,CACF,oEAAoE,CACrE,CAAC;QACJ,KAAK,EAAE,CAAC;IACV,CAAC,CAAC,CAAC;IACH,MAAM,CAAC,gBAAgB,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;AAC9C,CAAC;AAED,0EAA0E;AAC1E,SAAS,QAAQ;IACf,MAAM,EAAE,CAAC;IACT,YAAY,CAAC,MAAM,CAAC,CAAC;IACrB,MAAM,GAAG,UAAU,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;AACrC,CAAC;AAED,sGAAsG;AACtG,SAAS,KAAK;IACZ,MAAM,IAAI,GAAG,IAAI,GAAG,EAA4B,CAAC;IAEjD,KAAK,MAAM,EAAE,KAAK,EAAE,IAAI,aAAa,EAAE,CAAC;QACtC,KAAK,MAAM,CAAC,IAAI,EAAE,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YACjE,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YAE5B,IAAI,CAAC,IAAI,IAAI,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC;gBAAE,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC,CAAC;QACvE,CAAC;IACH,CAAC;IAED,OAAO,CAAC,GAAG,IAAI,CAAC;SACb,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC,EAA4B,EAAE,CAAC;QAC/D,IAAI;QACJ,OAAO;QACP,SAAS;KACV,CAAC;SACD,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC5C,CAAC;AAED,SAAS,SAAS;IAChB,MAAM,OAAO,GAAG,KAAK,EAAE,CAAC;IAExB,IACE,OAAO,CAAC,MAAM,KAAK,CAAC;QACpB,CAAC,OAAO,QAAQ,KAAK,WAAW,IAAI,QAAQ,CAAC,MAAM,CAAC;QACpD,OAAO,WAAW,KAAK,WAAW,EAClC,CAAC;QACD,KAAK,EAAE,CAAC;QAER,OAAO;IACT,CAAC;IAED,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;IAEpC,wEAAwE;IACxE,4EAA4E;IAC5E,IAAI,GAAG,KAAK,UAAU;QAAE,QAAQ,GAAG,CAAC,CAAC;IACrC,IAAI,MAAM,IAAI,GAAG,KAAK,UAAU;QAAE,OAAO;IAEzC,IAAI,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC;QACzB,MAAM,KAAK,GAAG,CAAC,GAAG,aAAa,CAAC,CAAC,GAAG,CAClC,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,EAAE,CACpB,KAAK,MAAM,KAAK,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC;aAClC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,IAAI,KAAK,OAAO,EAAE,CAAC;aACjD,IAAI,CAAC,IAAI,CAAC,EAAE,CAClB,CAAC;QAEF,IAAI,CAAC,mCAAmC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC9D,CAAC;IAED,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;AACrB,CAAC;AAED;;;;GAIG;AACH,SAAS,IAAI,CAAC,OAAe;IAC3B,IAAI,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG;QAAE,OAAO,CAAC,IAAI,CAAC,YAAY,GAAG,OAAO,CAAC,CAAC;AACjE,CAAC;AAED,SAAS,IAAI,CAAC,GAAW,EAAE,OAAmC;IAC5D,KAAK,EAAE,CAAC;IACR,UAAU,GAAG,GAAG,CAAC;IAEjB,MAAM,MAAM,GAAG,IAAI,WAAW,CAC5B,YAAY,GAAG,KAAK,GAAG,kBAAkB,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CACnE,CAAC;IAEF,MAAM,GAAG,MAAM,CAAC;IAEhB,MAAM,CAAC,MAAM,GAAG,GAAG,EAAE;QACnB,QAAQ,GAAG,CAAC,CAAC;IACf,CAAC,CAAC;IAEF,MAAM,CAAC,SAAS,GAAG,CAAC,KAAmB,EAAE,EAAE;QACzC,IAAI,KAA4C,CAAC;QAEjD,IAAI,CAAC;YACH,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAc,CAGtC,CAAC;QACJ,CAAC;QAAC,MAAM,CAAC;YACP,OAAO;QACT,CAAC;QAED,IAAI,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ,IAAI,OAAO,KAAK,CAAC,OAAO,KAAK,QAAQ;YACrE,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;IACrC,CAAC,CAAC;IAEF,MAAM,CAAC,OAAO,GAAG,GAAG,EAAE;QACpB,2EAA2E;QAC3E,0EAA0E;QAC1E,0EAA0E;QAC1E,mDAAmD;QACnD,IAAI,MAAM,CAAC,UAAU,KAAK,WAAW,CAAC,MAAM;YAAE,OAAO;QAErD,MAAM,CAAC,KAAK,EAAE,CAAC;QACf,IAAI,MAAM,KAAK,MAAM;YAAE,MAAM,GAAG,IAAI,CAAC;QACrC,IAAI,EAAE,QAAQ,GAAG,CAAC;YAAE,OAAO;QAE3B,KAAK,GAAG,UAAU,CAChB,GAAG,EAAE,CAAC,IAAI,CAAC,UAAU,EAAE,OAAO,CAAC,EAC/B,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,GAAG,CAAC,IAAI,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC,CAC7C,CAAC;IACJ,CAAC,CAAC;AACJ,CAAC;AAED,SAAS,KAAK;IACZ,YAAY,CAAC,KAAK,CAAC,CAAC;IACpB,MAAM,EAAE,KAAK,EAAE,CAAC;IAChB,MAAM,GAAG,IAAI,CAAC;IACd,UAAU,GAAG,EAAE,CAAC;AAClB,CAAC;AAED,oFAAoF;AACpF,IAAI,OAAO,GAAoC,IAAI,CAAC;AAEpD,6FAA6F;AAC7F,SAAS,KAAK,CAAC,IAAY,EAAE,OAAe;IAC1C,KAAK,MAAM,KAAK,IAAI,aAAa,EAAE,CAAC;QAClC,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAE/B,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,OAAO;YAAE,SAAS;QAE3C,IAAI,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC;QAElB,MAAM,OAAO,GACX,CAAC,OAAO,KAAK,IAAI,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,IAAI,GAAG,EAAU,CAAC;QAEjE,OAAO,CAAC,GAAG,CAAC,IAAI,GAAG,GAAG,GAAG,OAAO,CAAC,CAAC;QAClC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrC,CAAC;IAED,IAAI,CAAC,OAAO;QAAE,OAAO;IAErB,cAAc,CAAC,GAAG,EAAE;QAClB,MAAM,OAAO,GAAG,OAAO,CAAC;QAExB,OAAO,GAAG,IAAI,CAAC;QACf,IAAI,CAAC,OAAO;YAAE,OAAO;QAErB,yEAAyE;QACzE,IAAI,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;YACxB,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;YAErC,OAAO;QACT,CAAC;QAED,qEAAqE;QACrE,6CAA6C;QAC7C,KAAK,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI,OAAO,EAAE,CAAC;YACxC,KAAK,eAAe,CAAC,MAAM,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAC/D,GAAG,EAAE,GAAE,CAAC,CACT,CAAC;QACJ,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC;AAED,iBAAiB;AACjB,MAAM,UAAU,YAAY;IAC1B,aAAa,CAAC,KAAK,EAAE,CAAC;IACtB,KAAK,EAAE,CAAC;IACR,QAAQ,GAAG,CAAC,CAAC;IACb,OAAO,GAAG,IAAI,CAAC;AACjB,CAAC","sourcesContent":["// The tab's side of live sections: what the page is showing, on one stream.\n//\n// Every section or page rendered with `live` registers its names here, with\n// the version each was at and its signature. The union is what the stream\n// watches; a version that moved refreshes exactly the regions live on that\n// name, through the same refresh() a page calls itself. One stream per tab\n// however many regions, reopened only when the set of names changes, closed\n// while the tab is hidden and caught up when it is seen again.\n\nimport { refresh, refreshOnChange } from \"./router\";\n\n/** The names a region is live on, as the server rendered them: version at render and signature. */\nexport interface Registration {\n target: string;\n names: Record<string, [version: number, signature: string]>;\n}\n\nconst CHANGES_PATH = \"/_rsc/changes\";\n\nconst registrations = new Set<Registration>();\n\nlet source: EventSource | null = null;\nlet openedWith = \"\";\nlet settle: ReturnType<typeof setTimeout> | undefined;\nlet retry: ReturnType<typeof setTimeout> | undefined;\nlet failures = 0;\nlet listening = false;\n\n/** Register what a rendered region is live on; the returned function forgets it. */\nexport function register(entry: Registration): () => void {\n registrations.add(entry);\n schedule();\n\n return () => {\n registrations.delete(entry);\n schedule();\n };\n}\n\nfunction listen(): void {\n if (listening || typeof document === \"undefined\") return;\n\n listening = true;\n document.addEventListener(\"visibilitychange\", () => {\n if (!document.hidden) return schedule();\n\n // Hidden tabs do not hold a connection. Nothing is missed: seen again,\n // the stream reopens at the versions this tab holds and every name that\n // moved meanwhile is reported at once.\n if (source)\n note(\n \"refreshOn paused: tab hidden. It catches up when the tab is shown.\",\n );\n close();\n });\n window.addEventListener(\"online\", schedule);\n}\n\n/** Many regions register in one commit; one reconcile serves them all. */\nfunction schedule(): void {\n listen();\n clearTimeout(settle);\n settle = setTimeout(reconcile, 20);\n}\n\n/** Every name any region is live on, at the lowest version held - the one furthest behind decides. */\nfunction union(): [string, number, string][] {\n const held = new Map<string, [number, string]>();\n\n for (const { names } of registrations) {\n for (const [name, [version, signature]] of Object.entries(names)) {\n const seen = held.get(name);\n\n if (!seen || version < seen[0]) held.set(name, [version, signature]);\n }\n }\n\n return [...held]\n .map(([name, [version, signature]]): [string, number, string] => [\n name,\n version,\n signature,\n ])\n .sort((a, b) => (a[0] < b[0] ? -1 : 1));\n}\n\nfunction reconcile(): void {\n const entries = union();\n\n if (\n entries.length === 0 ||\n (typeof document !== \"undefined\" && document.hidden) ||\n typeof EventSource === \"undefined\"\n ) {\n close();\n\n return;\n }\n\n const key = JSON.stringify(entries);\n\n // Something changed: a region came or went, or one re-rendered at a new\n // version. Either way the set is new, and a failed stream gets a fresh try.\n if (key !== openedWith) failures = 0;\n if (source && key === openedWith) return;\n\n if (import.meta.env?.DEV) {\n const lines = [...registrations].map(\n ({ target, names }) =>\n ` ${target}: ${Object.entries(names)\n .map(([name, [version]]) => `${name} @${version}`)\n .join(\", \")}`,\n );\n\n note(`refreshOn watching, by region:\\n${lines.join(\"\\n\")}`);\n }\n\n open(key, entries);\n}\n\n/**\n * Development only: what the page refreshes on, and why it stopped. A region\n * that declared refreshOn but is missing from the list rendered no names -\n * the server said why, once, in its own log.\n */\nfunction note(message: string): void {\n if (import.meta.env?.DEV) console.info(\"[rsc-kit] \" + message);\n}\n\nfunction open(key: string, entries: [string, number, string][]): void {\n close();\n openedWith = key;\n\n const stream = new EventSource(\n CHANGES_PATH + \"?w=\" + encodeURIComponent(JSON.stringify(entries)),\n );\n\n source = stream;\n\n stream.onopen = () => {\n failures = 0;\n };\n\n stream.onmessage = (event: MessageEvent) => {\n let moved: { name?: unknown; version?: unknown };\n\n try {\n moved = JSON.parse(event.data as string) as {\n name?: unknown;\n version?: unknown;\n };\n } catch {\n return;\n }\n\n if (typeof moved.name === \"string\" && typeof moved.version === \"number\")\n apply(moved.name, moved.version);\n };\n\n stream.onerror = () => {\n // CONNECTING: the browser is retrying a dropped connection itself. CLOSED:\n // an error answer - a 403 for names signed by another deploy, a 502 - and\n // only a new stream comes back. Three in a row and the page is left alone\n // until something re-renders and registers afresh.\n if (stream.readyState !== EventSource.CLOSED) return;\n\n stream.close();\n if (source === stream) source = null;\n if (++failures > 3) return;\n\n retry = setTimeout(\n () => open(openedWith, entries),\n Math.min(30_000, 1000 * 2 ** (failures - 1)),\n );\n };\n}\n\nfunction close(): void {\n clearTimeout(retry);\n source?.close();\n source = null;\n openedWith = \"\";\n}\n\n/** Regions to refresh this tick, each with the changes that moved it: `stock@5`. */\nlet pending: Map<string, Set<string>> | null = null;\n\n/** A version moved: every region on the name at another version refreshes, once per tick. */\nfunction apply(name: string, version: number): void {\n for (const entry of registrations) {\n const held = entry.names[name];\n\n if (!held || held[0] === version) continue;\n\n held[0] = version;\n\n const changes =\n (pending ??= new Map()).get(entry.target) ?? new Set<string>();\n\n changes.add(name + \"@\" + version);\n pending.set(entry.target, changes);\n }\n\n if (!pending) return;\n\n queueMicrotask(() => {\n const targets = pending;\n\n pending = null;\n if (!targets) return;\n\n // The page re-renders its sections with it, so refreshing both is twice.\n if (targets.has(\"page\")) {\n void refresh(\"page\").catch(() => {});\n\n return;\n }\n\n // Saying which change asked lets every tab asking about the same one\n // share a single render of a shared section.\n for (const [target, changes] of targets) {\n void refreshOnChange(target, [...changes].sort().join(\",\")).catch(\n () => {},\n );\n }\n });\n}\n\n/** For tests. */\nexport function resetChanges(): void {\n registrations.clear();\n close();\n failures = 0;\n pending = null;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"changesStore.js","sourceRoot":"","sources":["../../src/js/changesStore.ts"],"names":[],"mappings":"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","sourcesContent":["// The tab's side of live sections: what the page is showing, on one stream.\n//\n// Every section or page rendered with `live` registers its names here, with\n// the version each was at and its signature. The union is what the stream\n// watches; a version that moved refreshes exactly the regions live on that\n// name, through the same refresh() a page calls itself. One stream per tab\n// however many regions, reopened only when the set of names changes, closed\n// while the tab is hidden and caught up when it is seen again.\n\nimport { refresh, refreshOnChange } from \"./router.js\";\n\n/** The names a region is live on, as the server rendered them: version at render and signature. */\nexport interface Registration {\n target: string;\n names: Record<string, [version: number, signature: string]>;\n}\n\nconst CHANGES_PATH = \"/_rsc/changes\";\n\nconst registrations = new Set<Registration>();\n\nlet source: EventSource | null = null;\nlet openedWith = \"\";\nlet settle: ReturnType<typeof setTimeout> | undefined;\nlet retry: ReturnType<typeof setTimeout> | undefined;\nlet failures = 0;\nlet listening = false;\n\n/** Register what a rendered region is live on; the returned function forgets it. */\nexport function register(entry: Registration): () => void {\n registrations.add(entry);\n schedule();\n\n return () => {\n registrations.delete(entry);\n schedule();\n };\n}\n\nfunction listen(): void {\n if (listening || typeof document === \"undefined\") return;\n\n listening = true;\n document.addEventListener(\"visibilitychange\", () => {\n if (!document.hidden) return schedule();\n\n // Hidden tabs do not hold a connection. Nothing is missed: seen again,\n // the stream reopens at the versions this tab holds and every name that\n // moved meanwhile is reported at once.\n if (source)\n note(\n \"refreshOn paused: tab hidden. It catches up when the tab is shown.\",\n );\n close();\n });\n window.addEventListener(\"online\", schedule);\n}\n\n/** Many regions register in one commit; one reconcile serves them all. */\nfunction schedule(): void {\n listen();\n clearTimeout(settle);\n settle = setTimeout(reconcile, 20);\n}\n\n/** Every name any region is live on, at the lowest version held - the one furthest behind decides. */\nfunction union(): [string, number, string][] {\n const held = new Map<string, [number, string]>();\n\n for (const { names } of registrations) {\n for (const [name, [version, signature]] of Object.entries(names)) {\n const seen = held.get(name);\n\n if (!seen || version < seen[0]) held.set(name, [version, signature]);\n }\n }\n\n return [...held]\n .map(([name, [version, signature]]): [string, number, string] => [\n name,\n version,\n signature,\n ])\n .sort((a, b) => (a[0] < b[0] ? -1 : 1));\n}\n\nfunction reconcile(): void {\n const entries = union();\n\n if (\n entries.length === 0 ||\n (typeof document !== \"undefined\" && document.hidden) ||\n typeof EventSource === \"undefined\"\n ) {\n close();\n\n return;\n }\n\n const key = JSON.stringify(entries);\n\n // Something changed: a region came or went, or one re-rendered at a new\n // version. Either way the set is new, and a failed stream gets a fresh try.\n if (key !== openedWith) failures = 0;\n if (source && key === openedWith) return;\n\n if (import.meta.env?.DEV) {\n const lines = [...registrations].map(\n ({ target, names }) =>\n ` ${target}: ${Object.entries(names)\n .map(([name, [version]]) => `${name} @${version}`)\n .join(\", \")}`,\n );\n\n note(`refreshOn watching, by region:\\n${lines.join(\"\\n\")}`);\n }\n\n open(key, entries);\n}\n\n/**\n * Development only: what the page refreshes on, and why it stopped. A region\n * that declared refreshOn but is missing from the list rendered no names -\n * the server said why, once, in its own log.\n */\nfunction note(message: string): void {\n if (import.meta.env?.DEV) console.info(\"[rsc-kit] \" + message);\n}\n\nfunction open(key: string, entries: [string, number, string][]): void {\n close();\n openedWith = key;\n\n const stream = new EventSource(\n CHANGES_PATH + \"?w=\" + encodeURIComponent(JSON.stringify(entries)),\n );\n\n source = stream;\n\n stream.onopen = () => {\n failures = 0;\n };\n\n stream.onmessage = (event: MessageEvent) => {\n let moved: { name?: unknown; version?: unknown };\n\n try {\n moved = JSON.parse(event.data as string) as {\n name?: unknown;\n version?: unknown;\n };\n } catch {\n return;\n }\n\n if (typeof moved.name === \"string\" && typeof moved.version === \"number\")\n apply(moved.name, moved.version);\n };\n\n stream.onerror = () => {\n // CONNECTING: the browser is retrying a dropped connection itself. CLOSED:\n // an error answer - a 403 for names signed by another deploy, a 502 - and\n // only a new stream comes back. Three in a row and the page is left alone\n // until something re-renders and registers afresh.\n if (stream.readyState !== EventSource.CLOSED) return;\n\n stream.close();\n if (source === stream) source = null;\n if (++failures > 3) return;\n\n retry = setTimeout(\n () => open(openedWith, entries),\n Math.min(30_000, 1000 * 2 ** (failures - 1)),\n );\n };\n}\n\nfunction close(): void {\n clearTimeout(retry);\n source?.close();\n source = null;\n openedWith = \"\";\n}\n\n/** Regions to refresh this tick, each with the changes that moved it: `stock@5`. */\nlet pending: Map<string, Set<string>> | null = null;\n\n/** A version moved: every region on the name at another version refreshes, once per tick. */\nfunction apply(name: string, version: number): void {\n for (const entry of registrations) {\n const held = entry.names[name];\n\n if (!held || held[0] === version) continue;\n\n held[0] = version;\n\n const changes =\n (pending ??= new Map()).get(entry.target) ?? new Set<string>();\n\n changes.add(name + \"@\" + version);\n pending.set(entry.target, changes);\n }\n\n if (!pending) return;\n\n queueMicrotask(() => {\n const targets = pending;\n\n pending = null;\n if (!targets) return;\n\n // The page re-renders its sections with it, so refreshing both is twice.\n if (targets.has(\"page\")) {\n void refresh(\"page\").catch(() => {});\n\n return;\n }\n\n // Saying which change asked lets every tab asking about the same one\n // share a single render of a shared section.\n for (const [target, changes] of targets) {\n void refreshOnChange(target, [...changes].sort().join(\",\")).catch(\n () => {},\n );\n }\n });\n}\n\n/** For tests. */\nexport function resetChanges(): void {\n registrations.clear();\n close();\n failures = 0;\n pending = null;\n}\n"]}
|
|
@@ -3,26 +3,26 @@
|
|
|
3
3
|
// navigate.ts SPA engine (Link, prefetch, popstate) through it. This replaces
|
|
4
4
|
// the bun engine's createRscApp + the hand-rolled webpack shim — the plugin
|
|
5
5
|
// resolves client references itself.
|
|
6
|
-
import { SEARCH_PARAMS_FALLBACK } from "./useSearchParams";
|
|
7
|
-
import { recoverFromStaleAssets } from "./staleAssets";
|
|
8
|
-
import { afterHydration, replayEarlyClicks } from "./earlyClicks";
|
|
6
|
+
import { SEARCH_PARAMS_FALLBACK } from "./useSearchParams.js";
|
|
7
|
+
import { recoverFromStaleAssets } from "./staleAssets.js";
|
|
8
|
+
import { afterHydration, replayEarlyClicks } from "./earlyClicks.js";
|
|
9
9
|
import { parseRedirectDigest } from "../redirectDigest.js";
|
|
10
10
|
import { isNotFoundDigest } from "../notFound.js";
|
|
11
|
-
import { showDevNotice } from "./devNotice";
|
|
12
|
-
import { caughtByLoading } from "./fallbackReport";
|
|
13
|
-
import { noteNavigation } from "./segmentStore";
|
|
11
|
+
import { showDevNotice } from "./devNotice.js";
|
|
12
|
+
import { caughtByLoading } from "./fallbackReport.js";
|
|
13
|
+
import { noteNavigation } from "./segmentStore.js";
|
|
14
14
|
import { isSafeRedirect } from "../safeUrl.js";
|
|
15
15
|
import { createFromReadableStream, encodeReply, setServerCallback, } from "@vitejs/plugin-rsc/browser";
|
|
16
16
|
import { createElement, startTransition } from "react";
|
|
17
17
|
import { createRoot, hydrateRoot } from "react-dom/client";
|
|
18
|
-
import { activityMarkersIn } from "./activityMarkers";
|
|
19
|
-
import { ActivityRoot } from "./ActivityRouter";
|
|
20
|
-
import { ActionRefusedError, ServerRedirectError, ServerValidationError, noteRedirected, refusalOf, throwForFailedAction, } from "./errors";
|
|
21
|
-
import { fetchPagePayload } from "./pagePayload";
|
|
22
|
-
import { inlinePayload } from "./inlinePayload";
|
|
23
|
-
import { claimRead, setQueryCodec } from "./queryClient";
|
|
24
|
-
import { clearSegments, dropHidden, isHeld, prerenderSegment, restoreSegments, setSegment } from "./segmentStore";
|
|
25
|
-
import { cancelPrefetch, forgetOtherPages, isPrefetched, navigate, setApiRoutes, refresh, applyRevalidations, prefetch, retentionKey, setCallServer, setHeldLayouts, setStaticPayloads, setStaticRoutes, seedStaticChain, payloadUrl, setDeserializer, setInterceptManifest, getHeldLayouts, setNavigateHandler, setHeldHandlers, setPrerenderHandler, setReplaceRootHandler, setRestoreHandler, setVersion, } from "./navigate";
|
|
18
|
+
import { activityMarkersIn } from "./activityMarkers.js";
|
|
19
|
+
import { ActivityRoot } from "./ActivityRouter.js";
|
|
20
|
+
import { ActionRefusedError, ServerRedirectError, ServerValidationError, noteRedirected, refusalOf, throwForFailedAction, } from "./errors.js";
|
|
21
|
+
import { fetchPagePayload } from "./pagePayload.js";
|
|
22
|
+
import { inlinePayload } from "./inlinePayload.js";
|
|
23
|
+
import { claimRead, setQueryCodec } from "./queryClient.js";
|
|
24
|
+
import { clearSegments, dropHidden, isHeld, prerenderSegment, restoreSegments, setSegment } from "./segmentStore.js";
|
|
25
|
+
import { cancelPrefetch, forgetOtherPages, isPrefetched, navigate, setApiRoutes, refresh, applyRevalidations, prefetch, retentionKey, setCallServer, setHeldLayouts, setStaticPayloads, setStaticRoutes, seedStaticChain, payloadUrl, setDeserializer, setInterceptManifest, getHeldLayouts, setNavigateHandler, setHeldHandlers, setPrerenderHandler, setReplaceRootHandler, setRestoreHandler, setVersion, } from "./navigate.js";
|
|
26
26
|
/**
|
|
27
27
|
* A redirect that travelled as an error: the digest of the error itself, or
|
|
28
28
|
* of the cause React wraps it in when it reports client-rendering a boundary
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createViteRscApp.js","sourceRoot":"","sources":["../../src/js/createViteRscApp.ts"],"names":[],"mappings":"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","sourcesContent":["// Vite-engine client bootstrap. Uses @vitejs/plugin-rsc's browser runtime as\n// the Flight deserializer + action encoder, and drives the package's engine-agnostic\n// navigate.ts SPA engine (Link, prefetch, popstate) through it. This replaces\n// the bun engine's createRscApp + the hand-rolled webpack shim — the plugin\n// resolves client references itself.\nimport { SEARCH_PARAMS_FALLBACK } from \"./useSearchParams\";\nimport { recoverFromStaleAssets } from \"./staleAssets\";\nimport { afterHydration, replayEarlyClicks } from \"./earlyClicks\";\nimport { parseRedirectDigest } from \"../redirectDigest.js\";\nimport { isNotFoundDigest } from \"../notFound.js\";\nimport { showDevNotice } from \"./devNotice\";\nimport { caughtByLoading } from \"./fallbackReport\";\nimport { noteNavigation } from \"./segmentStore\";\nimport type { Route } from \"../routes.js\";\nimport { isSafeRedirect } from \"../safeUrl.js\";\nimport {\n createFromReadableStream,\n encodeReply,\n setServerCallback,\n} from \"@vitejs/plugin-rsc/browser\";\nimport { createElement, startTransition } from \"react\";\nimport { createRoot, hydrateRoot } from \"react-dom/client\";\nimport { activityMarkersIn } from \"./activityMarkers\";\nimport { ActivityRoot } from \"./ActivityRouter\";\nimport {\n ActionRefusedError,\n ServerRedirectError,\n ServerValidationError,\n noteRedirected,\n refusalOf,\n throwForFailedAction,\n} from \"./errors\";\nimport { fetchPagePayload } from \"./pagePayload\";\nimport { inlinePayload } from \"./inlinePayload\";\nimport { claimRead, setQueryCodec } from \"./queryClient\";\nimport { clearSegments, dropHidden, isHeld, prerenderSegment, restoreSegments, setSegment } from \"./segmentStore\";\nimport type { ReactNode } from \"react\";\nimport {\n cancelPrefetch,\n forgetOtherPages,\n isPrefetched,\n navigate,\n setApiRoutes,\n refresh,\n applyRevalidations,\n prefetch,\n retentionKey,\n setCallServer,\n setHeldLayouts,\n setStaticPayloads,\n setStaticRoutes,\n seedStaticChain,\n payloadUrl,\n setDeserializer,\n setInterceptManifest,\n getHeldLayouts,\n setNavigateHandler,\n setHeldHandlers,\n setPrerenderHandler,\n setReplaceRootHandler,\n setRestoreHandler,\n setVersion,\n} from \"./navigate\";\n\n\n/**\n * A redirect that travelled as an error: the digest of the error itself, or\n * of the cause React wraps it in when it reports client-rendering a boundary\n * the server had already failed.\n */\nfunction isRedirect(error: unknown): boolean {\n const digest = (error as { digest?: unknown } | null)?.digest;\n const cause = (error as { cause?: { digest?: unknown } } | null)?.cause;\n\n return (\n parseRedirectDigest(digest) !== null ||\n parseRedirectDigest(cause?.digest) !== null ||\n // A missing page decided inside a boundary is answered the same way, by\n // the same boundary, and is just as little a fault to report.\n isNotFoundDigest(digest) ||\n isNotFoundDigest(cause?.digest)\n );\n}\n\nexport async function createViteRscApp(\n container: Document | Element = document,\n interceptEntries: { urlPattern: string; slot: string }[] = [],\n options: { staticPayloads?: string | null; routes?: unknown[] | null; apiRoutes?: string[] } = {},\n): Promise<void> {\n // The urls a route.ts answers: a link to one is an anchor, never a\n // prefetch, never a payload fetch.\n if (options.apiRoutes) setApiRoutes(options.apiRoutes);\n // An exported build has no server to negotiate with, so payloads live at\n // their own urls rather than behind a header on the page's url.\n setStaticPayloads(options.staticPayloads ?? null);\n // Only an exported build ships this: with no server to negotiate with, the\n // client works out for itself how much of a page it still holds.\n if (options.routes) setStaticRoutes(options.routes as never);\n // The router has to recognise an intercepted link before it asks the server,\n // so the patterns are baked into the generated browser entry. Without them\n // every intercepted route falls through to a full-page navigation.\n setInterceptManifest(interceptEntries);\n\n async function callServer(id: string, args: unknown[]): Promise<unknown> {\n // A read opened a slot before calling the reference, and this is the first\n // point at which the id exists on the client — React keeps it private and\n // hands it over only here. Claiming the slot enqueues the read for the\n // batched GET instead of posting it.\n const read = claimRead(id, args);\n\n if (read) return await read;\n\n const encoded = await encodeReply(args);\n\n // encodeReply returns FormData as soon as an argument contains a File.\n // Sending that as multipart would make PHP consume php://input while\n // parsing it, leaving the action with an empty body — so serialize it to\n // raw bytes under an opaque content-type and send the real one in\n // X-RSC-Content-Type for the worker to rebuild FormData from.\n let body: BodyInit;\n let realContentType: string;\n\n if (encoded instanceof FormData) {\n const serialized = new Response(encoded);\n body = await serialized.arrayBuffer();\n realContentType =\n serialized.headers.get(\"content-type\") ?? \"multipart/form-data\";\n } else {\n body = encoded as BodyInit;\n realContentType = \"text/plain;charset=UTF-8\";\n }\n\n // Where the action was invoked from. The host resolves it to the\n // components that render the page, so anything the action says it\n // invalidated can come back with the answer instead of being fetched\n // afterwards - and what comes back is for this page, not whichever is\n // showing when it lands.\n const from = window.location.pathname + window.location.search;\n\n const res = await fetch(\"/_rsc/action\", {\n method: \"POST\",\n headers: {\n \"X-RSC-Action\": id,\n \"X-RSC-Referer\": from,\n \"X-RSC-Content-Type\": realContentType,\n \"Content-Type\": \"application/octet-stream\",\n \"X-XSRF-TOKEN\": decodeURIComponent(\n document.cookie.match(/XSRF-TOKEN=([^;]+)/)?.[1] ?? \"\",\n ),\n },\n body,\n });\n\n // A failed action does not answer with a Flight stream, and the decoder\n // cannot tell — it reports its own parse failure instead of what the\n // server said.\n try {\n await throwForFailedAction(res);\n } catch (err) {\n // A redirect is an instruction, not something for a form to display:\n // an expired session answers this way, and the destination is the login\n // page rather than a message about one.\n if (err instanceof ServerRedirectError) {\n // The destination came off a response header, so it is checked here\n // too — the engine refuses these at the source, but a proxy or a host\n // in front of it can write whatever it likes. A navigation, not a\n // document load: the layouts stay mounted and the history entry the\n // form was on is replaced, the way a redirect after a POST should\n // be - Back does not return to the submitted form.\n //\n // Awaited, so the action is still pending when the destination's\n // tree is handed to React: the two are one transition, committed\n // together. Not awaited, the action ended first - its optimistic\n // state dropped, pending went false - and the page it redirected to\n // arrived a frame later. A new chat's first message vanished from\n // the thread and came back with its reply.\n //\n // Asked of the server, never revealed from what the router holds. The\n // action may have changed anything the destination reads - a cookie,\n // a membership, a row - and a page kept from before it, or prefetched\n // before it, shows the world as it was: a sign-in that redirected\n // back showed the page signed out until a reload. What a revalidating\n // action already drops, a redirecting one drops too.\n if (isSafeRedirect(err.location)) {\n forgetOtherPages();\n\n try {\n await navigate(err.location as Route, { replace: true });\n } catch {\n // Announced by the navigation itself, as rsc-navigate-error. The\n // action did redirect; that is still its answer.\n }\n }\n\n // Performed, so resolved - not thrown. The call's answer is \"you are\n // being taken somewhere\": an object saying so, the shape an action's\n // result already has, so a caller reading result.validationErrors\n // reads undefined rather than throwing. A caller that awaited the\n // action in a plain startTransition had no catch for a throw, the\n // rejection reached React, and the root unmounted to a white page\n // on every logout.\n noteRedirected(err.location);\n\n return { redirected: err.location };\n }\n\n throw err;\n }\n\n const answer = await createFromReadableStream(res.body!, { callServer });\n const result = unwrapRevalidated(answer, from);\n\n // The backend turned the call down. Thrown, so the code after the await\n // does not take it for what it asked for; the message came in the answer\n // because React strips the message of anything the server throws.\n const refused = refusalOf(result);\n\n if (refused?.errors) throw new ServerValidationError(refused.message, refused.errors);\n if (refused) throw new ActionRefusedError(refused.message, refused.status);\n\n return result;\n }\n\n /**\n * Put anything the action re-rendered on screen, and hand back its result.\n *\n * The trees travel with the answer rather than being fetched afterwards, so\n * the caller sees only what its action returned and never knows the page\n * was updated around it.\n */\n function unwrapRevalidated(answer: unknown, from: string): unknown {\n if (\n answer === null ||\n typeof answer !== \"object\" ||\n !(\"__rscRevalidated\" in answer)\n ) {\n return answer;\n }\n\n const envelope = answer as {\n __rscRevalidated: Record<string, unknown>;\n result: unknown;\n };\n\n applyRevalidations(from, envelope.__rscRevalidated as Record<string, ReactNode>);\n\n return envelope.result;\n }\n\n setDeserializer(createFromReadableStream as never);\n // The query transport speaks Flight too, and reaches the runtime through here\n // rather than importing it: a second import of the browser runtime from the\n // client-component graph is a second client-reference registry, and the\n // symptom is components that render as undefined with nothing logged.\n setQueryCodec({\n deserialize: (stream) =>\n createFromReadableStream(stream, { callServer }) as Promise<unknown>,\n encode: (args) => encodeReply(args) as Promise<string | FormData>,\n // The way back when a read cannot ride in a url. Re-entering callServer is\n // safe: the slot was cleared the moment the reference returned, so this\n // takes the ordinary POST path rather than claiming a read again.\n asAction: (id, args) => callServer(id, args),\n });\n setCallServer(callServer);\n // The plugin's own \"use server\" client stubs route through its registered\n // server callback — register the same transport there too.\n setServerCallback(callServer as never);\n\n // Link / Form / router live in a separate build graph and reach the SPA\n // engine through these globals.\n (window as unknown as { __rsc_navigate: typeof navigate }).__rsc_navigate =\n navigate;\n (window as unknown as { __rsc_prefetch: typeof prefetch }).__rsc_prefetch =\n prefetch;\n (\n window as unknown as { __rsc_cancel_prefetch: typeof cancelPrefetch }\n ).__rsc_cancel_prefetch = cancelPrefetch;\n (\n window as unknown as { __rsc_is_prefetched: typeof isPrefetched }\n ).__rsc_is_prefetched = isPrefetched;\n (window as unknown as { __rsc_refresh: typeof refresh }).__rsc_refresh =\n refresh;\n\n // Hydrate from the RSC endpoint (same url + X-RSC, no version header).\n //\n // Everything from here to the decode is failure handling, because this is\n // the one request with nothing watching it. A page whose shell is already\n // rendered looks fine while this fails, and its fallbacks stay on screen\n // indefinitely with nothing reported anywhere.\n // The payload the document streamed in for itself, when it did - one\n // render per visit, see inlinePayload.ts. A page the build wrote whole\n // fetches its stored payload, as it always did.\n //\n // A page an edge may serve whole names its payload at a hashed asset url\n // (storedPayloadAsset in vite.ts), so booting it asks nothing of the app:\n // the same url with X-RSC would wake a sleeping one on every visit.\n const storedPayload = document.querySelector('meta[name=\"rsc-kit:payload\"]');\n const res =\n inlinePayload() ??\n (storedPayload\n ? await fetchPagePayload(storedPayload.getAttribute(\"content\")!, fetch, false)\n : await fetchPagePayload(payloadUrl(window.location.href)));\n\n // Seed the router with the build this DOCUMENT is, so a redeploy is caught\n // on the next navigation: the host answers 409 to a client of another\n // build, and the document is loaded again. From the document's own meta\n // first - a document a service worker served from its cache is the last\n // build's, while the payload just fetched is this one's, and seeding from\n // the payload would have the old client claim to be new. The header is\n // the fallback for a document with no meta.\n const documentBuild = document.querySelector('meta[name=\"rsc-kit:build\"]')?.getAttribute(\"content\");\n const servedVersion = documentBuild || res.headers.get(\"X-RSC-Version\");\n\n if (servedVersion) {\n setVersion(servedVersion);\n }\n\n // The chain this page is built from, so the next navigation can say what is\n // already mounted and be sent only what changed.\n // A server says what this page is built from; a file server says nothing,\n // so an exported build works it out from the table it was given.\n // An asset says nothing, so the document says it for its payload.\n const servedLayouts = res.headers.get(\"X-RSC-Layouts\") ?? storedPayload?.getAttribute(\"data-layouts\") ?? null;\n\n if (servedLayouts !== null) {\n setHeldLayouts(servedLayouts ? servedLayouts.split(\",\") : []);\n } else if (!seedStaticChain(window.location.href)) {\n setHeldLayouts([]);\n }\n const tree = await createFromReadableStream(res.body!, { callServer });\n\n // Retaining the previous page behind <Activity> needs a wrapper above the\n // page, and React will not hydrate a *document* container through one: the\n // root child of a document has to be <html>, and wrapping it hangs the\n // renderer outright (React 19.2.7). An app whose root layout owns <html>\n // therefore hydrates the tree directly and navigations replace it, as before.\n //\n // Apps that hydrate into an element get retention. Giving it to document-\n // rooted apps means SPA navigation returning only the changed segment rather\n // than a whole document, which is an engine change, not a client one.\n const retains = container !== document;\n\n const shell = retains\n ? createElement(ActivityRoot, {\n initialKey: retentionKey(window.location.href, null),\n initialTree: tree as ReactNode,\n })\n : (tree as ReactNode);\n\n // A document that cannot be hydrated by this tree is client-rendered\n // instead - a repaint, not a freeze. React 19.2 does not recover from a\n // hydration mismatch at an <Activity>: it retries hydrating the boundary,\n // mismatches again, and never returns to the main thread. Every segment\n // boundary is an Activity, one per layout, so a document with none where\n // the page has layouts is that mismatch, guaranteed, before React starts.\n // What produced one: a parameterised route's PPR shell, rendered without\n // a page key and, by a build before this one, without the Activities too.\n // None rather than fewer: a boundary inside a Suspense hole the shell left\n // unfinished has no marker and is client-rendered by React on its own,\n // which is not a mismatch. The stale-asset reload does not apply - the\n // document would come back the same.\n const missing = retains && getHeldLayouts().length > 0 && activityMarkersIn(container) === 0;\n\n if (missing) {\n console.warn(\n \"[rsc-kit] The document has no <Activity> boundaries where the page has layouts, so it cannot be hydrated; rendering the page instead. A PPR shell built by an earlier release lacks them - rebuild.\",\n );\n }\n\n // The payload answered with an error status - the not-found page for a\n // url the shell was served for anyway. It is not the document on screen,\n // so it is rendered, not hydrated: a mismatch at an Activity is the loop\n // above, and this one is certain.\n const disagrees = !res.ok;\n\n const onRecoverableError = (error: unknown, errorInfo: unknown) => {\n // A client component whose chunk the server no longer has fails while\n // hydrating, and React reports that as recoverable: the page is loaded\n // again, with the current names.\n if (recoverFromStaleAssets(error)) return;\n\n // A redirect decided inside a boundary: the server's row carried it as\n // the digest, React client-renders the boundary and reports that it\n // did, and the RedirectBoundary is already performing it. Nothing to\n // read in the console about a page doing what it was told.\n if (isRedirect(error)) return;\n\n // A PPR shell is served with its Suspense boundaries deliberately\n // unfinished — the build aborts the render once the static part is out.\n // React reports that as #419 and client-renders the boundary from the\n // Flight payload, which is the intended path, not a fault to report.\n const message = String((error as { message?: string })?.message ?? error);\n\n if (\n message.includes(\"419\") ||\n message.includes(\"did not finish this Suspense boundary\")\n ) {\n return;\n }\n\n // A view transition the browser cancelled because the tab was not\n // visible. React reports it here; the update still landed, and a tab\n // in the background is not a fault in the page.\n if (message.includes(\"Transition was aborted\")) return;\n\n // A navigation another one overtook: its request was aborted, and a\n // row of its payload that a component was still reading rejects with\n // the abort. React recovers by rendering the root again synchronously\n // and reports the recovery here as #520, with the abort as the cause.\n // The page it recovered to is the one the second navigation asked for;\n // the abort was the design, not a fault.\n const cause = (error as { cause?: { name?: string; message?: string } } | null)?.cause;\n\n if (\n cause?.name === \"AbortError\" ||\n /\\baborted\\b/i.test(cause?.message ?? \"\") ||\n /\\baborted\\b/i.test(message)\n ) {\n return;\n }\n // A page whose query string was read under a boundary carries the\n // fallback there; React reports the recovery on hydration. Under a\n // boundary the developer wrote, that is the designed path and nothing\n // is said. With nothing closer than a loading.tsx, the whole segment\n // showed the fallback until the query arrived - said here, in the\n // page and the console, for whoever is looking at either. Production\n // has no stack to tell the two apart; the build's note on the route is\n // the record there.\n if (\n (error as { digest?: string })?.digest === SEARCH_PARAMS_FALLBACK ||\n message.includes(\"useSearchParams()\")\n ) {\n const stack = (errorInfo as { componentStack?: string } | null)\n ?.componentStack;\n\n if (!caughtByLoading(stack)) return;\n\n const hint =\n \"useSearchParams() was read on the server with nothing closer than a loading.tsx, so the \" +\n \"whole segment showed that fallback until the query arrived. A <Suspense> around the \" +\n \"component that reads keeps the rest of the page painted.\";\n\n showDevNotice(hint, stack);\n console.error(new Error(hint), errorInfo);\n\n return;\n }\n\n console.error(error, errorInfo);\n };\n\n const rootOptions = {\n onRecoverableError,\n // A chunk the deploy no longer serves is not a fault in the page; the\n // document is loaded again, and the new names come with it. Anything\n // else is reported the way React would have.\n onUncaughtError(error: unknown, errorInfo: unknown) {\n if (recoverFromStaleAssets(error)) return;\n\n console.error(error, errorInfo);\n },\n onCaughtError(error: unknown, errorInfo: unknown) {\n if (recoverFromStaleAssets(error)) return;\n // Caught by the RedirectBoundary, which is performing it.\n if (isRedirect(error)) return;\n\n console.error(error, errorInfo);\n },\n };\n\n const root = missing || disagrees\n ? (() => {\n const created = createRoot(container as Element, rootOptions);\n\n created.render(shell);\n\n return created;\n })()\n : hydrateRoot(container, shell, rootOptions);\n\n // Depth 0 is a whole document and replaces the root. Anything deeper is one\n // segment: handing it to the boundary at that depth leaves the layouts above\n // it mounted, which is the point of asking for a partial render at all.\n setNavigateHandler((tree: unknown, key: string, segmentDepth: number, inPlaceOf?: string | null, keepsPrevious?: boolean) => {\n const newTree = tree as ReactNode;\n\n // From here on the boundary animates; the seed commit before this did not.\n noteNavigation();\n\n if (segmentDepth > 0) {\n setSegment(segmentDepth, key, newTree, inPlaceOf, keepsPrevious);\n\n return;\n }\n\n clearSegments();\n root.render(newTree);\n });\n\n // The whole document again, in place - revalidate(\"all\"). Not through the\n // handler above: that clears the boundaries and renders the tree as a new\n // page, and a boundary emptied re-keys its Activity to the current url and\n // remounts everything under it. A port's \"added to cart\" went with the\n // form's state that way, on every product reached by a link. Here the root\n // takes the tree in a transition and each boundary hands its page the new\n // children under the key it has - see replaceActive.\n setReplaceRootHandler((tree: unknown) => {\n startTransition(() => root.render(tree as ReactNode));\n });\n\n // Back and forward reveal a page the boundaries are still holding, with the\n // form you were filling in still filled in, and without asking the server.\n setRestoreHandler((key: string, maxAge?: number) =>\n restoreSegments(key, maxAge),\n );\n setHeldHandlers(isHeld, dropHidden);\n\n // A touch or a settled hover: the page is rendered hidden now, and the\n // click reveals it. See warm() in navigate.ts and prerenderSegment.\n setPrerenderHandler((tree: unknown, key: string, segmentDepth: number) => {\n prerenderSegment(segmentDepth, key, tree as ReactNode);\n });\n\n window.addEventListener(\"popstate\", () => {\n // restore: back and forward reveal the page you were on, with its state.\n // Wherever the browser just went; not a literal this app wrote.\n navigate(window.location.href as Route, { replace: true, restore: true });\n });\n\n history.replaceState(\n { rscUrl: window.location.href },\n \"\",\n window.location.href,\n );\n\n // A tap held by the bootstrap script, navigated to once hydration has\n // committed - not now: the runtime's script running is seconds before\n // React can dispatch a click on a phone still downloading chunks, and\n // a tap in that window would be the browser's. See earlyClicks.ts.\n afterHydration(() => replayEarlyClicks((url) => navigate(url as Route)));\n}\n\n"]}
|
|
1
|
+
{"version":3,"file":"createViteRscApp.js","sourceRoot":"","sources":["../../src/js/createViteRscApp.ts"],"names":[],"mappings":"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","sourcesContent":["// Vite-engine client bootstrap. Uses @vitejs/plugin-rsc's browser runtime as\n// the Flight deserializer + action encoder, and drives the package's engine-agnostic\n// navigate.ts SPA engine (Link, prefetch, popstate) through it. This replaces\n// the bun engine's createRscApp + the hand-rolled webpack shim — the plugin\n// resolves client references itself.\nimport { SEARCH_PARAMS_FALLBACK } from \"./useSearchParams.js\";\nimport { recoverFromStaleAssets } from \"./staleAssets.js\";\nimport { afterHydration, replayEarlyClicks } from \"./earlyClicks.js\";\nimport { parseRedirectDigest } from \"../redirectDigest.js\";\nimport { isNotFoundDigest } from \"../notFound.js\";\nimport { showDevNotice } from \"./devNotice.js\";\nimport { caughtByLoading } from \"./fallbackReport.js\";\nimport { noteNavigation } from \"./segmentStore.js\";\nimport type { Route } from \"../routes.js\";\nimport { isSafeRedirect } from \"../safeUrl.js\";\nimport {\n createFromReadableStream,\n encodeReply,\n setServerCallback,\n} from \"@vitejs/plugin-rsc/browser\";\nimport { createElement, startTransition } from \"react\";\nimport { createRoot, hydrateRoot } from \"react-dom/client\";\nimport { activityMarkersIn } from \"./activityMarkers.js\";\nimport { ActivityRoot } from \"./ActivityRouter.js\";\nimport {\n ActionRefusedError,\n ServerRedirectError,\n ServerValidationError,\n noteRedirected,\n refusalOf,\n throwForFailedAction,\n} from \"./errors.js\";\nimport { fetchPagePayload } from \"./pagePayload.js\";\nimport { inlinePayload } from \"./inlinePayload.js\";\nimport { claimRead, setQueryCodec } from \"./queryClient.js\";\nimport { clearSegments, dropHidden, isHeld, prerenderSegment, restoreSegments, setSegment } from \"./segmentStore.js\";\nimport type { ReactNode } from \"react\";\nimport {\n cancelPrefetch,\n forgetOtherPages,\n isPrefetched,\n navigate,\n setApiRoutes,\n refresh,\n applyRevalidations,\n prefetch,\n retentionKey,\n setCallServer,\n setHeldLayouts,\n setStaticPayloads,\n setStaticRoutes,\n seedStaticChain,\n payloadUrl,\n setDeserializer,\n setInterceptManifest,\n getHeldLayouts,\n setNavigateHandler,\n setHeldHandlers,\n setPrerenderHandler,\n setReplaceRootHandler,\n setRestoreHandler,\n setVersion,\n} from \"./navigate.js\";\n\n\n/**\n * A redirect that travelled as an error: the digest of the error itself, or\n * of the cause React wraps it in when it reports client-rendering a boundary\n * the server had already failed.\n */\nfunction isRedirect(error: unknown): boolean {\n const digest = (error as { digest?: unknown } | null)?.digest;\n const cause = (error as { cause?: { digest?: unknown } } | null)?.cause;\n\n return (\n parseRedirectDigest(digest) !== null ||\n parseRedirectDigest(cause?.digest) !== null ||\n // A missing page decided inside a boundary is answered the same way, by\n // the same boundary, and is just as little a fault to report.\n isNotFoundDigest(digest) ||\n isNotFoundDigest(cause?.digest)\n );\n}\n\nexport async function createViteRscApp(\n container: Document | Element = document,\n interceptEntries: { urlPattern: string; slot: string }[] = [],\n options: { staticPayloads?: string | null; routes?: unknown[] | null; apiRoutes?: string[] } = {},\n): Promise<void> {\n // The urls a route.ts answers: a link to one is an anchor, never a\n // prefetch, never a payload fetch.\n if (options.apiRoutes) setApiRoutes(options.apiRoutes);\n // An exported build has no server to negotiate with, so payloads live at\n // their own urls rather than behind a header on the page's url.\n setStaticPayloads(options.staticPayloads ?? null);\n // Only an exported build ships this: with no server to negotiate with, the\n // client works out for itself how much of a page it still holds.\n if (options.routes) setStaticRoutes(options.routes as never);\n // The router has to recognise an intercepted link before it asks the server,\n // so the patterns are baked into the generated browser entry. Without them\n // every intercepted route falls through to a full-page navigation.\n setInterceptManifest(interceptEntries);\n\n async function callServer(id: string, args: unknown[]): Promise<unknown> {\n // A read opened a slot before calling the reference, and this is the first\n // point at which the id exists on the client — React keeps it private and\n // hands it over only here. Claiming the slot enqueues the read for the\n // batched GET instead of posting it.\n const read = claimRead(id, args);\n\n if (read) return await read;\n\n const encoded = await encodeReply(args);\n\n // encodeReply returns FormData as soon as an argument contains a File.\n // Sending that as multipart would make PHP consume php://input while\n // parsing it, leaving the action with an empty body — so serialize it to\n // raw bytes under an opaque content-type and send the real one in\n // X-RSC-Content-Type for the worker to rebuild FormData from.\n let body: BodyInit;\n let realContentType: string;\n\n if (encoded instanceof FormData) {\n const serialized = new Response(encoded);\n body = await serialized.arrayBuffer();\n realContentType =\n serialized.headers.get(\"content-type\") ?? \"multipart/form-data\";\n } else {\n body = encoded as BodyInit;\n realContentType = \"text/plain;charset=UTF-8\";\n }\n\n // Where the action was invoked from. The host resolves it to the\n // components that render the page, so anything the action says it\n // invalidated can come back with the answer instead of being fetched\n // afterwards - and what comes back is for this page, not whichever is\n // showing when it lands.\n const from = window.location.pathname + window.location.search;\n\n const res = await fetch(\"/_rsc/action\", {\n method: \"POST\",\n headers: {\n \"X-RSC-Action\": id,\n \"X-RSC-Referer\": from,\n \"X-RSC-Content-Type\": realContentType,\n \"Content-Type\": \"application/octet-stream\",\n \"X-XSRF-TOKEN\": decodeURIComponent(\n document.cookie.match(/XSRF-TOKEN=([^;]+)/)?.[1] ?? \"\",\n ),\n },\n body,\n });\n\n // A failed action does not answer with a Flight stream, and the decoder\n // cannot tell — it reports its own parse failure instead of what the\n // server said.\n try {\n await throwForFailedAction(res);\n } catch (err) {\n // A redirect is an instruction, not something for a form to display:\n // an expired session answers this way, and the destination is the login\n // page rather than a message about one.\n if (err instanceof ServerRedirectError) {\n // The destination came off a response header, so it is checked here\n // too — the engine refuses these at the source, but a proxy or a host\n // in front of it can write whatever it likes. A navigation, not a\n // document load: the layouts stay mounted and the history entry the\n // form was on is replaced, the way a redirect after a POST should\n // be - Back does not return to the submitted form.\n //\n // Awaited, so the action is still pending when the destination's\n // tree is handed to React: the two are one transition, committed\n // together. Not awaited, the action ended first - its optimistic\n // state dropped, pending went false - and the page it redirected to\n // arrived a frame later. A new chat's first message vanished from\n // the thread and came back with its reply.\n //\n // Asked of the server, never revealed from what the router holds. The\n // action may have changed anything the destination reads - a cookie,\n // a membership, a row - and a page kept from before it, or prefetched\n // before it, shows the world as it was: a sign-in that redirected\n // back showed the page signed out until a reload. What a revalidating\n // action already drops, a redirecting one drops too.\n if (isSafeRedirect(err.location)) {\n forgetOtherPages();\n\n try {\n await navigate(err.location as Route, { replace: true });\n } catch {\n // Announced by the navigation itself, as rsc-navigate-error. The\n // action did redirect; that is still its answer.\n }\n }\n\n // Performed, so resolved - not thrown. The call's answer is \"you are\n // being taken somewhere\": an object saying so, the shape an action's\n // result already has, so a caller reading result.validationErrors\n // reads undefined rather than throwing. A caller that awaited the\n // action in a plain startTransition had no catch for a throw, the\n // rejection reached React, and the root unmounted to a white page\n // on every logout.\n noteRedirected(err.location);\n\n return { redirected: err.location };\n }\n\n throw err;\n }\n\n const answer = await createFromReadableStream(res.body!, { callServer });\n const result = unwrapRevalidated(answer, from);\n\n // The backend turned the call down. Thrown, so the code after the await\n // does not take it for what it asked for; the message came in the answer\n // because React strips the message of anything the server throws.\n const refused = refusalOf(result);\n\n if (refused?.errors) throw new ServerValidationError(refused.message, refused.errors);\n if (refused) throw new ActionRefusedError(refused.message, refused.status);\n\n return result;\n }\n\n /**\n * Put anything the action re-rendered on screen, and hand back its result.\n *\n * The trees travel with the answer rather than being fetched afterwards, so\n * the caller sees only what its action returned and never knows the page\n * was updated around it.\n */\n function unwrapRevalidated(answer: unknown, from: string): unknown {\n if (\n answer === null ||\n typeof answer !== \"object\" ||\n !(\"__rscRevalidated\" in answer)\n ) {\n return answer;\n }\n\n const envelope = answer as {\n __rscRevalidated: Record<string, unknown>;\n result: unknown;\n };\n\n applyRevalidations(from, envelope.__rscRevalidated as Record<string, ReactNode>);\n\n return envelope.result;\n }\n\n setDeserializer(createFromReadableStream as never);\n // The query transport speaks Flight too, and reaches the runtime through here\n // rather than importing it: a second import of the browser runtime from the\n // client-component graph is a second client-reference registry, and the\n // symptom is components that render as undefined with nothing logged.\n setQueryCodec({\n deserialize: (stream) =>\n createFromReadableStream(stream, { callServer }) as Promise<unknown>,\n encode: (args) => encodeReply(args) as Promise<string | FormData>,\n // The way back when a read cannot ride in a url. Re-entering callServer is\n // safe: the slot was cleared the moment the reference returned, so this\n // takes the ordinary POST path rather than claiming a read again.\n asAction: (id, args) => callServer(id, args),\n });\n setCallServer(callServer);\n // The plugin's own \"use server\" client stubs route through its registered\n // server callback — register the same transport there too.\n setServerCallback(callServer as never);\n\n // Link / Form / router live in a separate build graph and reach the SPA\n // engine through these globals.\n (window as unknown as { __rsc_navigate: typeof navigate }).__rsc_navigate =\n navigate;\n (window as unknown as { __rsc_prefetch: typeof prefetch }).__rsc_prefetch =\n prefetch;\n (\n window as unknown as { __rsc_cancel_prefetch: typeof cancelPrefetch }\n ).__rsc_cancel_prefetch = cancelPrefetch;\n (\n window as unknown as { __rsc_is_prefetched: typeof isPrefetched }\n ).__rsc_is_prefetched = isPrefetched;\n (window as unknown as { __rsc_refresh: typeof refresh }).__rsc_refresh =\n refresh;\n\n // Hydrate from the RSC endpoint (same url + X-RSC, no version header).\n //\n // Everything from here to the decode is failure handling, because this is\n // the one request with nothing watching it. A page whose shell is already\n // rendered looks fine while this fails, and its fallbacks stay on screen\n // indefinitely with nothing reported anywhere.\n // The payload the document streamed in for itself, when it did - one\n // render per visit, see inlinePayload.ts. A page the build wrote whole\n // fetches its stored payload, as it always did.\n //\n // A page an edge may serve whole names its payload at a hashed asset url\n // (storedPayloadAsset in vite.ts), so booting it asks nothing of the app:\n // the same url with X-RSC would wake a sleeping one on every visit.\n const storedPayload = document.querySelector('meta[name=\"rsc-kit:payload\"]');\n const res =\n inlinePayload() ??\n (storedPayload\n ? await fetchPagePayload(storedPayload.getAttribute(\"content\")!, fetch, false)\n : await fetchPagePayload(payloadUrl(window.location.href)));\n\n // Seed the router with the build this DOCUMENT is, so a redeploy is caught\n // on the next navigation: the host answers 409 to a client of another\n // build, and the document is loaded again. From the document's own meta\n // first - a document a service worker served from its cache is the last\n // build's, while the payload just fetched is this one's, and seeding from\n // the payload would have the old client claim to be new. The header is\n // the fallback for a document with no meta.\n const documentBuild = document.querySelector('meta[name=\"rsc-kit:build\"]')?.getAttribute(\"content\");\n const servedVersion = documentBuild || res.headers.get(\"X-RSC-Version\");\n\n if (servedVersion) {\n setVersion(servedVersion);\n }\n\n // The chain this page is built from, so the next navigation can say what is\n // already mounted and be sent only what changed.\n // A server says what this page is built from; a file server says nothing,\n // so an exported build works it out from the table it was given.\n // An asset says nothing, so the document says it for its payload.\n const servedLayouts = res.headers.get(\"X-RSC-Layouts\") ?? storedPayload?.getAttribute(\"data-layouts\") ?? null;\n\n if (servedLayouts !== null) {\n setHeldLayouts(servedLayouts ? servedLayouts.split(\",\") : []);\n } else if (!seedStaticChain(window.location.href)) {\n setHeldLayouts([]);\n }\n const tree = await createFromReadableStream(res.body!, { callServer });\n\n // Retaining the previous page behind <Activity> needs a wrapper above the\n // page, and React will not hydrate a *document* container through one: the\n // root child of a document has to be <html>, and wrapping it hangs the\n // renderer outright (React 19.2.7). An app whose root layout owns <html>\n // therefore hydrates the tree directly and navigations replace it, as before.\n //\n // Apps that hydrate into an element get retention. Giving it to document-\n // rooted apps means SPA navigation returning only the changed segment rather\n // than a whole document, which is an engine change, not a client one.\n const retains = container !== document;\n\n const shell = retains\n ? createElement(ActivityRoot, {\n initialKey: retentionKey(window.location.href, null),\n initialTree: tree as ReactNode,\n })\n : (tree as ReactNode);\n\n // A document that cannot be hydrated by this tree is client-rendered\n // instead - a repaint, not a freeze. React 19.2 does not recover from a\n // hydration mismatch at an <Activity>: it retries hydrating the boundary,\n // mismatches again, and never returns to the main thread. Every segment\n // boundary is an Activity, one per layout, so a document with none where\n // the page has layouts is that mismatch, guaranteed, before React starts.\n // What produced one: a parameterised route's PPR shell, rendered without\n // a page key and, by a build before this one, without the Activities too.\n // None rather than fewer: a boundary inside a Suspense hole the shell left\n // unfinished has no marker and is client-rendered by React on its own,\n // which is not a mismatch. The stale-asset reload does not apply - the\n // document would come back the same.\n const missing = retains && getHeldLayouts().length > 0 && activityMarkersIn(container) === 0;\n\n if (missing) {\n console.warn(\n \"[rsc-kit] The document has no <Activity> boundaries where the page has layouts, so it cannot be hydrated; rendering the page instead. A PPR shell built by an earlier release lacks them - rebuild.\",\n );\n }\n\n // The payload answered with an error status - the not-found page for a\n // url the shell was served for anyway. It is not the document on screen,\n // so it is rendered, not hydrated: a mismatch at an Activity is the loop\n // above, and this one is certain.\n const disagrees = !res.ok;\n\n const onRecoverableError = (error: unknown, errorInfo: unknown) => {\n // A client component whose chunk the server no longer has fails while\n // hydrating, and React reports that as recoverable: the page is loaded\n // again, with the current names.\n if (recoverFromStaleAssets(error)) return;\n\n // A redirect decided inside a boundary: the server's row carried it as\n // the digest, React client-renders the boundary and reports that it\n // did, and the RedirectBoundary is already performing it. Nothing to\n // read in the console about a page doing what it was told.\n if (isRedirect(error)) return;\n\n // A PPR shell is served with its Suspense boundaries deliberately\n // unfinished — the build aborts the render once the static part is out.\n // React reports that as #419 and client-renders the boundary from the\n // Flight payload, which is the intended path, not a fault to report.\n const message = String((error as { message?: string })?.message ?? error);\n\n if (\n message.includes(\"419\") ||\n message.includes(\"did not finish this Suspense boundary\")\n ) {\n return;\n }\n\n // A view transition the browser cancelled because the tab was not\n // visible. React reports it here; the update still landed, and a tab\n // in the background is not a fault in the page.\n if (message.includes(\"Transition was aborted\")) return;\n\n // A navigation another one overtook: its request was aborted, and a\n // row of its payload that a component was still reading rejects with\n // the abort. React recovers by rendering the root again synchronously\n // and reports the recovery here as #520, with the abort as the cause.\n // The page it recovered to is the one the second navigation asked for;\n // the abort was the design, not a fault.\n const cause = (error as { cause?: { name?: string; message?: string } } | null)?.cause;\n\n if (\n cause?.name === \"AbortError\" ||\n /\\baborted\\b/i.test(cause?.message ?? \"\") ||\n /\\baborted\\b/i.test(message)\n ) {\n return;\n }\n // A page whose query string was read under a boundary carries the\n // fallback there; React reports the recovery on hydration. Under a\n // boundary the developer wrote, that is the designed path and nothing\n // is said. With nothing closer than a loading.tsx, the whole segment\n // showed the fallback until the query arrived - said here, in the\n // page and the console, for whoever is looking at either. Production\n // has no stack to tell the two apart; the build's note on the route is\n // the record there.\n if (\n (error as { digest?: string })?.digest === SEARCH_PARAMS_FALLBACK ||\n message.includes(\"useSearchParams()\")\n ) {\n const stack = (errorInfo as { componentStack?: string } | null)\n ?.componentStack;\n\n if (!caughtByLoading(stack)) return;\n\n const hint =\n \"useSearchParams() was read on the server with nothing closer than a loading.tsx, so the \" +\n \"whole segment showed that fallback until the query arrived. A <Suspense> around the \" +\n \"component that reads keeps the rest of the page painted.\";\n\n showDevNotice(hint, stack);\n console.error(new Error(hint), errorInfo);\n\n return;\n }\n\n console.error(error, errorInfo);\n };\n\n const rootOptions = {\n onRecoverableError,\n // A chunk the deploy no longer serves is not a fault in the page; the\n // document is loaded again, and the new names come with it. Anything\n // else is reported the way React would have.\n onUncaughtError(error: unknown, errorInfo: unknown) {\n if (recoverFromStaleAssets(error)) return;\n\n console.error(error, errorInfo);\n },\n onCaughtError(error: unknown, errorInfo: unknown) {\n if (recoverFromStaleAssets(error)) return;\n // Caught by the RedirectBoundary, which is performing it.\n if (isRedirect(error)) return;\n\n console.error(error, errorInfo);\n },\n };\n\n const root = missing || disagrees\n ? (() => {\n const created = createRoot(container as Element, rootOptions);\n\n created.render(shell);\n\n return created;\n })()\n : hydrateRoot(container, shell, rootOptions);\n\n // Depth 0 is a whole document and replaces the root. Anything deeper is one\n // segment: handing it to the boundary at that depth leaves the layouts above\n // it mounted, which is the point of asking for a partial render at all.\n setNavigateHandler((tree: unknown, key: string, segmentDepth: number, inPlaceOf?: string | null, keepsPrevious?: boolean) => {\n const newTree = tree as ReactNode;\n\n // From here on the boundary animates; the seed commit before this did not.\n noteNavigation();\n\n if (segmentDepth > 0) {\n setSegment(segmentDepth, key, newTree, inPlaceOf, keepsPrevious);\n\n return;\n }\n\n clearSegments();\n root.render(newTree);\n });\n\n // The whole document again, in place - revalidate(\"all\"). Not through the\n // handler above: that clears the boundaries and renders the tree as a new\n // page, and a boundary emptied re-keys its Activity to the current url and\n // remounts everything under it. A port's \"added to cart\" went with the\n // form's state that way, on every product reached by a link. Here the root\n // takes the tree in a transition and each boundary hands its page the new\n // children under the key it has - see replaceActive.\n setReplaceRootHandler((tree: unknown) => {\n startTransition(() => root.render(tree as ReactNode));\n });\n\n // Back and forward reveal a page the boundaries are still holding, with the\n // form you were filling in still filled in, and without asking the server.\n setRestoreHandler((key: string, maxAge?: number) =>\n restoreSegments(key, maxAge),\n );\n setHeldHandlers(isHeld, dropHidden);\n\n // A touch or a settled hover: the page is rendered hidden now, and the\n // click reveals it. See warm() in navigate.ts and prerenderSegment.\n setPrerenderHandler((tree: unknown, key: string, segmentDepth: number) => {\n prerenderSegment(segmentDepth, key, tree as ReactNode);\n });\n\n window.addEventListener(\"popstate\", () => {\n // restore: back and forward reveal the page you were on, with its state.\n // Wherever the browser just went; not a literal this app wrote.\n navigate(window.location.href as Route, { replace: true, restore: true });\n });\n\n history.replaceState(\n { rscUrl: window.location.href },\n \"\",\n window.location.href,\n );\n\n // A tap held by the bootstrap script, navigated to once hydration has\n // committed - not now: the runtime's script running is seconds before\n // React can dispatch a click on a phone still downloading chunks, and\n // a tap in that window would be the browser's. See earlyClicks.ts.\n afterHydration(() => replayEarlyClicks((url) => navigate(url as Route)));\n}\n\n"]}
|
package/dist/js/navigate.d.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* duplicate bundling of react-server-dom-webpack.
|
|
7
7
|
*/
|
|
8
8
|
import type { Route } from "../routes.js";
|
|
9
|
-
import type { ManifestRoute } from "../manifest";
|
|
9
|
+
import type { ManifestRoute } from "../manifest.js";
|
|
10
10
|
type ReactNode = unknown;
|
|
11
11
|
type Deserializer = (stream: ReadableStream, options: Record<string, unknown>) => Promise<ReactNode>;
|
|
12
12
|
type CallServerFn = (id: string, args: unknown[]) => Promise<unknown>;
|