@rsc-kit/core 0.18.0 → 0.19.0

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.
Files changed (73) hide show
  1. package/dist/action.d.ts +16 -2
  2. package/dist/action.js +21 -12
  3. package/dist/action.js.map +1 -1
  4. package/dist/apiPrerender.js +24 -6
  5. package/dist/apiPrerender.js.map +1 -1
  6. package/dist/clientPackages.d.ts +30 -0
  7. package/dist/clientPackages.js +234 -0
  8. package/dist/clientPackages.js.map +1 -0
  9. package/dist/compress.d.ts +12 -0
  10. package/dist/compress.js +134 -0
  11. package/dist/compress.js.map +1 -0
  12. package/dist/compressRuntime.d.ts +8 -0
  13. package/dist/compressRuntime.js +62 -0
  14. package/dist/compressRuntime.js.map +1 -0
  15. package/dist/files.d.ts +20 -0
  16. package/dist/files.js +38 -0
  17. package/dist/files.js.map +1 -1
  18. package/dist/formSubmit.d.ts +1 -0
  19. package/dist/formSubmit.js +14 -0
  20. package/dist/formSubmit.js.map +1 -0
  21. package/dist/host.d.ts +23 -0
  22. package/dist/host.js +175 -31
  23. package/dist/host.js.map +1 -1
  24. package/dist/hostCalls.d.ts +15 -0
  25. package/dist/hostCalls.js +75 -8
  26. package/dist/hostCalls.js.map +1 -1
  27. package/dist/js/Form.d.ts +19 -2
  28. package/dist/js/Form.js +110 -83
  29. package/dist/js/Form.js.map +1 -1
  30. package/dist/js/LoadingBoundary.d.ts +5 -0
  31. package/dist/js/LoadingBoundary.js +19 -0
  32. package/dist/js/LoadingBoundary.js.map +1 -0
  33. package/dist/js/createViteRscApp.d.ts +1 -0
  34. package/dist/js/createViteRscApp.js +34 -5
  35. package/dist/js/createViteRscApp.js.map +1 -1
  36. package/dist/js/errors.d.ts +3 -1
  37. package/dist/js/errors.js +26 -3
  38. package/dist/js/errors.js.map +1 -1
  39. package/dist/js/fallbackReport.js +10 -8
  40. package/dist/js/fallbackReport.js.map +1 -1
  41. package/dist/js/formEncoding.d.ts +72 -3
  42. package/dist/js/formEncoding.js +284 -20
  43. package/dist/js/formEncoding.js.map +1 -1
  44. package/dist/js/navigate.d.ts +3 -0
  45. package/dist/js/navigate.js +56 -6
  46. package/dist/js/navigate.js.map +1 -1
  47. package/dist/js/updateStore.js +8 -2
  48. package/dist/js/updateStore.js.map +1 -1
  49. package/dist/js/useEvents.js +9 -7
  50. package/dist/js/useEvents.js.map +1 -1
  51. package/dist/js/usePolling.js +38 -37
  52. package/dist/js/usePolling.js.map +1 -1
  53. package/dist/openapi.d.ts +74 -0
  54. package/dist/openapi.js +172 -0
  55. package/dist/openapi.js.map +1 -0
  56. package/dist/prerender.js +1 -0
  57. package/dist/prerender.js.map +1 -1
  58. package/dist/redirect.d.ts +2 -2
  59. package/dist/redirect.js.map +1 -1
  60. package/dist/request.d.ts +56 -2
  61. package/dist/request.js +68 -4
  62. package/dist/request.js.map +1 -1
  63. package/dist/routeSchema.d.ts +49 -0
  64. package/dist/routeSchema.js.map +1 -1
  65. package/dist/routes.d.ts +15 -1
  66. package/dist/routes.js.map +1 -1
  67. package/dist/testing.d.ts +22 -0
  68. package/dist/testing.js +83 -5
  69. package/dist/testing.js.map +1 -1
  70. package/dist/vite.d.ts +80 -1
  71. package/dist/vite.js +625 -82
  72. package/dist/vite.js.map +1 -1
  73. package/package.json +7 -3
@@ -1 +1 @@
1
- {"version":3,"file":"Form.js","sourceRoot":"","sources":["../../src/js/Form.tsx"],"names":[],"mappings":"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","sourcesContent":["\"use client\";\n\nimport type { Href } from \"../routes.js\";\nimport {\n type FormHTMLAttributes,\n type FormEvent,\n type ReactNode,\n createContext,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n useSyncExternalStore,\n useTransition,\n} from \"react\";\nimport { ServerValidationError, ServerDumpError } from \"./errors\";\nimport { buildFormData } from \"./formEncoding\";\nimport { createFormStore } from \"./formStore\";\nimport type { FormStore } from \"./formStore\";\nimport { validateWith } from \"./standardSchema\";\nimport type { StandardSchemaV1 } from \"./standardSchema\";\n\n/**\n * How long a blur that leaves the form waits before checking the field. A\n * dialog's exit animation is shorter than this; a form still on screen after\n * it is one somebody is looking at.\n */\nconst LEAVE_FORM_SETTLE_MS = 300;\n\ntype PrefetchStrategy = \"hover\" | \"mount\" | \"none\";\n\n/**\n * What `field(name)` hands a control, spread straight onto it.\n *\n * The same four things react-hook-form's `<Controller>` gives, because it is\n * the same job: a component with no native control behind it needs a value and\n * a way to report a new one.\n */\ninterface FieldBinding<V> {\n name: string;\n value: V;\n /**\n * Either shape: a DOM event, or the value itself.\n *\n * A native input passes the event; a Radix select or a rich editor passes\n * what was chosen. A binder understanding only one of them would work on\n * half the controls anyone actually uses.\n */\n onChange: (next: V | { target: { value: V } }) => void;\n onBlur: () => void;\n}\n\n/**\n * What is known about one field, separately from what is spread onto it.\n *\n * Two objects rather than one, which is react-hook-form's split and it is right\n * for a mechanical reason: `touched` and `invalid` are not DOM attributes, so a\n * single spreadable object would put them on the element and React would warn\n * about every one.\n */\ninterface FieldState {\n /** Whether it has been left at least once. */\n touched: boolean;\n /** Whether it currently has errors. */\n invalid: boolean;\n /** Its messages, ready for a `<FieldError>`. */\n errors: string[];\n}\n\ninterface FormRenderProps<\n T extends Record<string, unknown> = Record<string, unknown>,\n> {\n pending: boolean;\n data: T;\n /**\n * Keyed by field name, so a typo is a type error rather than undefined.\n *\n * Partial because most fields have none, and nested paths join with dots —\n * `errors['address.city']`, which is the key a Standard Schema issue for that\n * field produces.\n */\n errors: Partial<Record<keyof T & string, string[]>> &\n Record<string, string[] | undefined>;\n error: (field: keyof T & string) => string | undefined;\n clearErrors: (...fields: (keyof T & string)[]) => void;\n reset: () => void;\n /** Whether the last submit was accepted. */\n succeeded: boolean;\n /**\n * The same thing, for two seconds.\n *\n * The \"Saved ✓\" that appears and fades. Worth having as state rather than a\n * timer in every form that wants one, because the timer has to be cleared\n * when the component goes away and that is the part people forget.\n */\n recentlySucceeded: boolean;\n /**\n * Bind one field so this component holds its value.\n *\n * Most fields need nothing: they are uncontrolled, the DOM holds the value,\n * and it is read back as FormData on submit. Reach for this when the DOM\n * cannot hold it for you — a control with no native element behind it, or a\n * value you want to read as it is typed:\n *\n * <Input {...field('title')} />\n * <span>{field('body').value.length}/100</span>\n *\n * A bound field is still an ordinary named input, so it arrives in FormData\n * with everything else. Nothing merges; there is one source of truth.\n */\n field: <K extends keyof T & string>(name: K) => FieldBinding<T[K]>;\n /**\n * What is known about a field, for deciding how to show it.\n *\n * const title = fieldState('title')\n *\n * <Field data-invalid={title.invalid}>\n * <Input {...field('title')} aria-invalid={title.invalid} />\n * <FieldError errors={title.errors.map((message) => ({ message }))} />\n * </Field>\n *\n * `touched` is what separates \"not filled in yet\" from \"filled in wrongly\" —\n * an error on a field nobody has visited is a form shouting before anyone\n * has done anything.\n */\n fieldState: (name: string) => FieldState;\n}\n\ninterface FormProps<\n T extends Record<string, unknown> = Record<string, unknown>,\n> extends Omit<\n FormHTMLAttributes<HTMLFormElement>,\n \"action\" | \"method\" | \"children\" | \"onSubmit\" | \"onError\"\n> {\n action: Href | ((formData: FormData) => Promise<unknown>);\n method?: \"get\" | \"post\";\n /**\n * Starting values for fields bound with `field()`.\n *\n * Uncontrolled fields do not need this — they take React's own\n * `defaultValue`, and the DOM keeps whatever is typed into them.\n */\n defaultValues?: Partial<T>;\n /**\n * A store created above this form, from `useFormStore()`.\n *\n * For the one case the context cannot reach: something that is not a\n * descendant — a top bar showing unsaved changes, a sidebar preview — needs\n * the values to exist above both of them. Create the store where they share\n * an ancestor and hand it down.\n *\n * Without it the form makes its own, which is what almost every form wants.\n */\n store?: FormStore;\n prefetch?: PrefetchStrategy;\n cacheFor?: number;\n replace?: boolean;\n preserveScroll?: boolean;\n resetOnSuccess?: boolean;\n /**\n * Check the fields before submitting, with any Standard Schema — Zod,\n * Valibot, ArkType.\n *\n * A failure fills `errors` and the action is never called, so a mistake\n * costs no round trip. It is a courtesy and not a control: the same action\n * is reachable without this form, so the server still has to check.\n */\n schema?: StandardSchemaV1;\n /** Transform form data before submitting to the server action. */\n transform?: (data: T) => Record<string, unknown>;\n /** Called inside the transition with typed form data. Use it to call your useOptimistic setter. */\n optimistic?: (data: T) => void;\n onSuccess?: (result: unknown) => void;\n /**\n * Called when a submit does not succeed.\n *\n * Validation failures arrive as field errors, with no second argument.\n * Anything else arrives as an empty error map and the thrown value — there\n * are no field errors to report, but the form still has to say so.\n */\n onError?: (errors: Record<string, string[]>, error?: unknown) => void;\n onSubmit?: (formData: FormData) => void | false;\n children: ReactNode | ((form: FormRenderProps<T>) => ReactNode);\n}\n\n/**\n * What an action built with createActionClient answers with.\n *\n * Recognised rather than thrown, because React serialises a rejected server\n * action opaquely: production strips the message and the fields it named are\n * gone. A returned object crosses intact, so a form reads it.\n */\nfunction resultOf(\n value: unknown,\n): { errors?: Record<string, string[]>; serverError?: string } | null {\n if (typeof value !== \"object\" || value === null) return null;\n\n const result = value as {\n validationErrors?: Record<string, string[]>;\n serverError?: string;\n };\n\n if (result.validationErrors) return { errors: result.validationErrors };\n if (result.serverError) return { serverError: result.serverError };\n\n return null;\n}\n\nconst FormStatusContext = createContext<FormRenderProps>({\n pending: false,\n data: {},\n errors: {},\n error: () => undefined,\n clearErrors: () => {},\n reset: () => {},\n succeeded: false,\n recentlySucceeded: false,\n // Outside a Form there is nothing holding a value, so a binding that reported\n // one would be lying. Name only, which is the part that is still true.\n field: ((name: string) => ({\n name,\n value: \"\",\n onChange: () => {},\n onBlur: () => {},\n })) as FormRenderProps[\"field\"],\n fieldState: () => ({ touched: false, invalid: false, errors: [] }),\n});\n\n/**\n * The store, on its own context.\n *\n * Separate from the status context because that one holds a fresh object every\n * render, so anything reading it re-renders with the form. The store is stable\n * for the life of the form, which is what lets a subscriber below it re-render\n * alone.\n */\nconst FormStoreContext = createContext<{\n store: FormStore;\n touch: (name: string) => void;\n} | null>(null);\n\n/**\n * A value store created above the form rather than by it.\n *\n * const store = useFormStore({ title: '' })\n *\n * <TopBar store={store} /> // not inside the form\n * <Form action={save} store={store}>…</Form>\n *\n * For the one case the context cannot reach. `<Form>` makes its own otherwise,\n * and almost every form should let it — this exists so that a component which\n * is not a descendant can still read the values, which is the flexibility\n * react-hook-form and TanStack Form get from `useForm()` being yours to call.\n *\n * Deliberately not reactive itself: creating the store does not subscribe to\n * it, so the component holding it does not re-render on every keystroke and\n * take the whole subtree with it. Read it with `useFormValues(store)`.\n */\nexport function useFormStore<T extends Record<string, unknown>>(\n initial: Partial<T> = {},\n): FormStore {\n const ref = useRef<FormStore | null>(null);\n\n ref.current ??= createFormStore({ ...initial });\n\n return ref.current;\n}\n\n/**\n * One field, subscribed on its own.\n *\n * The same thing `field()` gives, from a component that re-renders when this\n * field changes and at no other time. Reach for it when a form is large enough\n * that re-rendering all of it per keystroke is real:\n *\n * function Title() {\n * const { field, invalid, errors } = useField('title')\n *\n * return <Input {...field} aria-invalid={invalid} />\n * }\n *\n * Which is react-hook-form's `<Controller>` without the render prop: the\n * component you already had to write is the subscription boundary.\n */\nexport function useField(\n name: string,\n store?: FormStore,\n): FieldBinding<string> & FieldState {\n const ctx = useContext(FormStoreContext);\n const status = useContext(FormStatusContext);\n\n if (!ctx && !store) {\n throw new Error(\n \"useField() was called outside a <Form>. It reads that form's values, so there has to be one above it.\",\n );\n }\n\n const source = store ?? ctx!.store;\n const touch = ctx?.touch;\n\n const value = useSyncExternalStore(\n source.subscribe,\n () => (source.get(name) ?? \"\") as string,\n () => \"\",\n );\n\n const errors = status.errors[name] ?? [];\n\n return {\n name,\n value,\n onChange: (next) => {\n source.set(\n name,\n typeof next === \"object\" && next !== null && \"target\" in next\n ? (next as { target: { value: string } }).target.value\n : next,\n );\n },\n onBlur: () => void touch?.(name),\n touched: status.fieldState(name).touched,\n invalid: errors.length > 0,\n errors,\n };\n}\n\n/**\n * Every bound value, from anywhere inside the form.\n *\n * For a summary, a preview, a count of what has changed — something that reads\n * the form without being a field in it. Only values bound through `field()` or\n * `useField` are here: an uncontrolled input's value belongs to the DOM, and\n * this has no way to know it changed.\n */\nexport function useFormValues<T extends Record<string, unknown>>(\n store?: FormStore,\n): Partial<T> {\n const ctx = useContext(FormStoreContext);\n\n if (!ctx && !store) {\n throw new Error(\n \"useFormValues() was called outside a <Form>. It reads that form's values, so there has to be one above it.\",\n );\n }\n\n const source = store ?? ctx!.store;\n\n return useSyncExternalStore(\n source.subscribe,\n () => source.all() as Partial<T>,\n () => ({}) as Partial<T>,\n );\n}\n\nexport function useFormStatus<\n T extends Record<string, unknown> = Record<string, unknown>,\n>(): FormRenderProps<T> {\n return useContext(FormStatusContext) as FormRenderProps<T>;\n}\n\n/**\n * The pieces of a field name: `items[0].name` is items, 0, name.\n *\n * Both spellings, because both are in use and a form should not care which one\n * a person reached for: `items[0].name` and `items[0][name]` are the same\n * field. A trailing `[]` is a piece of its own — see below.\n */\nfunction pathOf(name: string): string[] {\n return name\n .replace(/\\[(\\w*)\\]/g, \".$1\")\n .split(\".\")\n .filter((piece, index, all) => piece !== \"\" || index === all.length - 1);\n}\n\n/** Whether a piece names an array index rather than a property. */\nconst isIndex = (piece: string): boolean => /^\\d+$/.test(piece);\n\n/**\n * Put one value at one path, making the containers it passes through.\n *\n * Whether a container is an array or an object is decided by the NEXT piece, so\n * `items[0].name` makes an array holding an object without being told which is\n * which.\n */\nfunction place(\n root: Record<string, unknown>,\n path: string[],\n value: unknown,\n): void {\n let node: Record<string, unknown> | unknown[] = root;\n\n for (let i = 0; i < path.length - 1; i++) {\n const key = path[i];\n const container = node as Record<string, unknown>;\n\n if (container[key] === undefined || typeof container[key] !== \"object\") {\n // An index makes an array, and so does the empty piece a trailing `[]`\n // leaves — `tags[]` has to reach an array to be pushed into, and building\n // an object there is how this first went wrong.\n const next = path[i + 1];\n\n container[key] = isIndex(next) || next === \"\" ? [] : {};\n }\n\n node = container[key] as Record<string, unknown> | unknown[];\n }\n\n const last = path[path.length - 1];\n\n // The empty piece a trailing `[]` leaves: push rather than assign, so\n // `tags[]` twice is two entries rather than one overwriting the other.\n if (last === \"\") (node as unknown[]).push(value);\n else (node as Record<string, unknown>)[last] = value;\n}\n\n/**\n * A FormData as the object a schema expects.\n *\n * Four things beyond copying entries across, and each of them was a bug or a\n * gap someone would meet on their first non-trivial form:\n *\n * A repeated name is an array. Three checkboxes sharing a name, a multiple\n * select, a list of tags — this used to keep the LAST one and drop the rest\n * silently, so a schema validated an object the person had not submitted.\n *\n * A name ending in `[]` is always an array, even with one value selected.\n * Otherwise a list of checkboxes is a string when one is ticked and an array\n * when two are, and no schema can describe both. It is also what `useForm`\n * writes when it serialises an array, so the two round-trip.\n *\n * Nested names nest. `address.city` and `items[0].name` build the object they\n * describe, which is the shape the schema was written against — and the shape\n * whose validation errors come back keyed the same way, because Standard\n * Schema issue paths are joined with dots too.\n *\n * Files are kept. They were dropped for being non-strings, which meant a schema\n * checking an upload was handed undefined and refused a file that was there.\n */\nfunction formDataToObject<T extends Record<string, unknown>>(\n formData: FormData,\n): T {\n const obj: Record<string, unknown> = {};\n\n for (const name of new Set(formData.keys())) {\n const all = formData.getAll(name);\n const path = pathOf(name);\n\n // A plain name used more than once is the array case, and it has no\n // brackets to say so — `tags` twice is `['a', 'b']`.\n if (path.length === 1 && path[0] !== \"\" && all.length > 1) {\n obj[path[0]] = all;\n continue;\n }\n\n for (const value of all) place(obj, path, value);\n }\n\n return obj as T;\n}\n\n/**\n * Also exported by name, and re-exported below, because both spellings are in\n * use: `import Form from` and `import { Form } from`.\n */\nexport default function Form<\n T extends Record<string, unknown> = Record<string, unknown>,\n>({\n action,\n method: methodProp,\n defaultValues,\n store: providedStore,\n prefetch = \"hover\",\n cacheFor,\n replace = false,\n preserveScroll = false,\n resetOnSuccess = true,\n schema,\n transform,\n optimistic,\n onSuccess,\n onError,\n onSubmit,\n children,\n ...rest\n}: FormProps<T>) {\n const isGetForm = typeof action === \"string\";\n const method = methodProp ?? (isGetForm ? \"get\" : \"post\");\n const [errors, setErrors] = useState<Record<string, string[]>>({});\n const [touched, setTouched] = useState<Record<string, boolean>>({});\n\n /**\n * Mark a field visited, and check it.\n *\n * Checking on blur rather than on every keystroke, because an error that\n * appears while someone is halfway through typing an email address is a form\n * arguing with them. Leaving the field is the moment they have finished\n * saying what they meant.\n *\n * The whole object is validated and only this field's issues are kept: a\n * Standard Schema has no notion of one field, and filtering by path is the\n * honest way to ask it about one. Everything else's errors are left as they\n * were, so blurring an empty field does not light up the rest of the form.\n */\n const touch = useCallback(\n async (name: string) => {\n setTouched((prev) => (prev[name] ? prev : { ...prev, [name]: true }));\n\n if (!schema || !formRef.current) return;\n\n const invalid = await validateWith(\n schema,\n formDataToObject(new FormData(formRef.current)),\n );\n\n setErrors((prev) => {\n const next = { ...prev };\n\n if (invalid?.[name]) next[name] = invalid[name];\n else delete next[name];\n\n return next;\n });\n },\n [schema],\n );\n\n const [succeeded, setSucceeded] = useState(false);\n const [recentlySucceeded, setRecentlySucceeded] = useState(false);\n const recentTimer = useRef<ReturnType<typeof setTimeout> | undefined>(\n undefined,\n );\n\n // Cleared on unmount: a timer that fires into a component that has gone is\n // the warning nobody reads and the leak nobody finds.\n useEffect(() => () => clearTimeout(recentTimer.current), []);\n\n // Only the fields someone bound. Everything else is the DOM's.\n //\n // A store rather than state, so a component using `useField` can re-render\n // for one field while this one does not. See formStore.ts.\n const storeRef = useRef<FormStore | null>(null);\n\n storeRef.current ??= createFormStore({\n ...(defaultValues as Record<string, unknown> | undefined),\n });\n\n const store = providedStore ?? storeRef.current;\n\n // Which names the render prop read through `field()`. A change to one of\n // those has to re-render this component, because that is where the value is\n // being displayed; a change to anything else does not, which is what lets a\n // `useField` child stand on its own.\n const readHere = useRef(new Set<string>());\n const [, bump] = useState(0);\n\n useEffect(\n () =>\n store.subscribe((name) => {\n if (name === \"\" || readHere.current.has(name)) bump((n) => n + 1);\n }),\n [store],\n );\n const [currentData, setCurrentData] = useState<T>({} as T);\n const [isPending, startTransition] = useTransition();\n const formRef = useRef<HTMLFormElement>(null);\n\n const error = useCallback(\n (field: keyof T & string): string | undefined => errors[field]?.[0],\n [errors],\n );\n\n const clearErrors = useCallback((...fields: (keyof T & string)[]) => {\n if (fields.length === 0) {\n setErrors({});\n } else {\n setErrors((prev) => {\n const next = { ...prev };\n for (const f of fields) {\n delete next[f];\n }\n return next;\n });\n }\n }, []);\n\n const resetForm = useCallback(() => {\n formRef.current?.reset();\n setErrors({});\n setCurrentData({} as T);\n }, []);\n\n useEffect(() => {\n if (isGetForm && prefetch === \"mount\") {\n const fn = (window as any).__rsc_prefetch;\n fn?.(action, cacheFor);\n }\n }, [isGetForm, prefetch, action, cacheFor]);\n\n const doPrefetch = useCallback(() => {\n if (!isGetForm) return;\n const fn = (window as any).__rsc_prefetch;\n fn?.(action as string, cacheFor);\n }, [isGetForm, action, cacheFor]);\n\n const handleSubmit = useCallback(\n async (e: FormEvent<HTMLFormElement>) => {\n e.preventDefault();\n const formData = new FormData(e.currentTarget);\n const data = formDataToObject<T>(formData);\n setCurrentData(data);\n\n if (onSubmit?.(formData) === false) {\n return;\n }\n\n if (isGetForm && method === \"get\") {\n const url = new URL(action as string, window.location.origin);\n for (const [key, value] of formData.entries()) {\n if (typeof value === \"string\" && value !== \"\") {\n url.searchParams.set(key, value);\n }\n }\n\n const path = url.pathname + url.search;\n const shell = action as string;\n const nav = (window as any).__rsc_navigate;\n const prefetched = (window as any).__rsc_is_prefetched;\n\n // The route without its query is that route's shell: the layout, the\n // chrome, and whatever it renders with nothing to show yet. Prefetching\n // on hover put it in the cache, so going there first costs no request\n // and puts the page on screen while the real query is still running.\n //\n // The query itself is never prefetched. It is the expensive half, and\n // hovering a search button is not a reason to run someone's search.\n if (path !== shell && prefetched?.(shell)) {\n // Awaited rather than raced: navigate() aborts whatever is in flight,\n // so starting the real one first would cancel the shell before it\n // could render. It is a cache hit, so this is a render, not a wait.\n Promise.resolve(nav?.(shell, { replace, preserveScroll })).then(() =>\n // Replaces, so the shell does not become a back-button stop of its\n // own — the pair leaves exactly one entry behind.\n nav?.(path, { replace: true, preserveScroll }),\n );\n\n return;\n }\n\n nav?.(path, { replace, preserveScroll });\n return;\n }\n\n const serverAction = action as (formData: FormData) => Promise<unknown>;\n\n // Rebuilt rather than edited: transform returns the values to send, so\n // whatever was in the form and is not in the result should not go.\n if (transform) {\n for (const key of [...formData.keys()]) formData.delete(key);\n\n for (const [key, value] of buildFormData(transform(data))) {\n formData.append(key, value);\n }\n }\n\n setErrors({});\n\n // Before the transition, so a failure neither runs the optimistic\n // update nor leaves the form looking like it is submitting.\n const invalid = await validateWith(schema, data);\n\n if (invalid) {\n setErrors(invalid);\n onError?.(invalid);\n\n return;\n }\n\n startTransition(async () => {\n try {\n // Call optimistic updater inside the transition so React's\n // useOptimistic picks it up and auto-reverts on settle.\n optimistic?.(data);\n\n const result = await serverAction(formData);\n const refused = resultOf(result);\n\n if (refused) {\n if (refused.errors) {\n setErrors(refused.errors);\n onError?.(refused.errors);\n } else {\n onError?.({}, new Error(refused.serverError));\n }\n\n return;\n }\n\n if (resetOnSuccess) {\n formRef.current?.reset();\n setTouched({});\n setCurrentData({} as T);\n }\n\n setErrors({});\n setSucceeded(true);\n setRecentlySucceeded(true);\n\n clearTimeout(recentTimer.current);\n recentTimer.current = setTimeout(\n () => setRecentlySucceeded(false),\n 2_000,\n );\n\n onSuccess?.(result);\n } catch (err) {\n if (err instanceof ServerValidationError) {\n setErrors(err.errors);\n onError?.(err.errors);\n } else if (err instanceof ServerDumpError) {\n // Dump overlay is already shown — silently swallow\n } else if (onError) {\n // Not rethrown. A rejected action never settles, and until it\n // settles React keeps the optimistic update on screen — so an\n // unexpected failure left the row showing as though the write had\n // worked. Settling is what takes it back.\n onError({}, err);\n } else {\n // Nothing is handling it, and swallowing here would lose it\n // entirely — the reason this used to rethrow.\n console.error(\"[rsc-kit] form submit failed\", err);\n }\n }\n });\n },\n [\n action,\n isGetForm,\n method,\n replace,\n preserveScroll,\n resetOnSuccess,\n schema,\n transform,\n optimistic,\n onSubmit,\n onSuccess,\n onError,\n ],\n );\n\n const field = useCallback(\n <K extends keyof T & string>(name: K): FieldBinding<T[K]> => {\n // Recorded during render, deliberately: this is how the form knows which\n // values it is the one displaying. Idempotent, so a double render in\n // development records the same name twice and means the same thing.\n readHere.current.add(name);\n\n return {\n name,\n value: (store.get(name) ?? \"\") as T[K],\n onChange: (next: unknown) => {\n const value =\n typeof next === \"object\" && next !== null && \"target\" in next\n ? (next as { target: { value: string } }).target.value\n : next;\n\n store.set(name, value);\n },\n onBlur: () => void touch(name),\n };\n },\n [store, touch],\n );\n\n const fieldState = useCallback(\n (name: string): FieldState => ({\n touched: touched[name] === true,\n invalid: (errors[name]?.length ?? 0) > 0,\n errors: errors[name] ?? [],\n }),\n [touched, errors],\n );\n\n // Stable, so a subscriber below does not re-render because this one did.\n const storeContext = useMemo(() => ({ store, touch }), [store, touch]);\n\n const formStatus: FormRenderProps<T> = {\n pending: isPending,\n data: currentData,\n succeeded,\n recentlySucceeded,\n field,\n fieldState,\n errors: errors as FormRenderProps<T>[\"errors\"],\n error,\n clearErrors,\n reset: resetForm,\n };\n\n return (\n <FormStoreContext.Provider value={storeContext}>\n <FormStatusContext.Provider value={formStatus as FormRenderProps}>\n <form\n ref={formRef}\n // On the element as well as in the handler, which is what makes this\n // work before hydration. React emits a form a browser can submit on its\n // own for a server action, and an ordinary action/method pair for a\n // url — so a submit that happens before the javascript arrives still\n // reaches the server.\n //\n // The two do not fight: handleSubmit calls preventDefault() first, and\n // React does not run a form action when the submit event was cancelled.\n // So the enhanced path wins whenever there is one, and the native path\n // is what is left when there is not.\n action={action as never}\n // Only for a url. React sets the method itself for a server action, and\n // passing one alongside is what it warns about.\n method={isGetForm ? method : undefined}\n onSubmit={handleSubmit}\n // On the form, not only on the bound fields. `focusout` bubbles where\n // `blur` does not, so React's onBlur here sees every control that was\n // left — including the uncontrolled ones, which are most of them and\n // would otherwise never be marked touched at all.\n onBlur={(event) => {\n const target = event.target as unknown as {\n name?: string;\n value?: string;\n };\n const name = target.name;\n\n if (!name) return;\n\n // Leaving a field is the moment to check it; leaving the form is\n // not the same moment. Focus going to nothing, or to something\n // outside the form, is a click on the page - most often a dialog\n // closing - and an error painted into a dialog as it animates out\n // reads as a submit that nobody made. An empty field left that way\n // is not checked at all. One with something in it is, but only\n // once the dust settles: if the form is gone or hidden by then, it\n // was a dialog closing, and nobody is there to read the error.\n const left = event.relatedTarget as Node | null;\n const stillInForm = !!left && !!formRef.current?.contains(left);\n\n if (stillInForm) {\n void touch(name);\n\n return;\n }\n\n if (!target.value) return;\n\n setTimeout(() => {\n const form = formRef.current;\n\n if (\n !form ||\n !form.isConnected ||\n form.getClientRects().length === 0\n )\n return;\n if (\n form.closest(\n \"[hidden], [aria-hidden='true'], [data-ending-style], [data-closed]\",\n )\n )\n return;\n\n void touch(name);\n }, LEAVE_FORM_SETTLE_MS);\n }}\n onMouseEnter={prefetch === \"hover\" ? doPrefetch : undefined}\n data-pending={isPending ? \"\" : undefined}\n {...rest}\n >\n {typeof children === \"function\" ? children(formStatus) : children}\n </form>\n </FormStatusContext.Provider>\n </FormStoreContext.Provider>\n );\n}\n\n// Also by name, because both spellings are in use: `import Form` and\n// `import { Form }`. This was a re-export of \"./Form\" — from inside Form.tsx,\n// so the module named itself. It survived on the bundler tolerating a circular\n// self-reference, left over from when a separate barrel re-exported a\n// FormComponent.tsx that a case-insensitive filesystem would not let be called\n// Form.ts. There is one file now, and it can just export what it declares.\nexport { Form };\n"]}
1
+ {"version":3,"file":"Form.js","sourceRoot":"","sources":["../../src/js/Form.tsx"],"names":[],"mappings":"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","sourcesContent":["\"use client\";\n\nimport type { Href } from \"../routes.js\";\nimport {\n type FormHTMLAttributes,\n type FormEvent,\n type ReactNode,\n type Ref,\n createContext,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useActionState,\n useState,\n useSyncExternalStore,\n useTransition,\n} from \"react\";\nimport { submitForm } from \"../formSubmit\";\nimport { ServerValidationError, ServerDumpError, ServerRedirectError, redirectedTo } from \"./errors\";\nimport { buildFormData, decodeFormData } from \"./formEncoding\";\nimport { createFormStore } from \"./formStore\";\nimport type { FormStore } from \"./formStore\";\nimport { validateWith } from \"./standardSchema\";\nimport type { StandardSchemaV1 } from \"./standardSchema\";\n\n/**\n * How long a blur that leaves the form waits before checking the field. A\n * dialog's exit animation is shorter than this; a form still on screen after\n * it is one somebody is looking at.\n */\nconst LEAVE_FORM_SETTLE_MS = 300;\n\ntype PrefetchStrategy = \"hover\" | \"mount\" | \"none\";\n\n/**\n * What `field(name)` hands a control, spread straight onto it.\n *\n * The same four things react-hook-form's `<Controller>` gives, because it is\n * the same job: a component with no native control behind it needs a value and\n * a way to report a new one.\n */\ninterface FieldBinding<V> {\n name: string;\n value: V;\n /**\n * Either shape: a DOM event, or the value itself.\n *\n * A native input passes the event; a Radix select or a rich editor passes\n * what was chosen. A binder understanding only one of them would work on\n * half the controls anyone actually uses.\n */\n onChange: (next: V | { target: { value: V } }) => void;\n onBlur: () => void;\n}\n\n/**\n * What is known about one field, separately from what is spread onto it.\n *\n * Two objects rather than one, which is react-hook-form's split and it is right\n * for a mechanical reason: `touched` and `invalid` are not DOM attributes, so a\n * single spreadable object would put them on the element and React would warn\n * about every one.\n */\ninterface FieldState {\n /** Whether it has been left at least once. */\n touched: boolean;\n /** Whether it currently has errors. */\n invalid: boolean;\n /** Its messages, ready for a `<FieldError>`. */\n errors: string[];\n}\n\ninterface FormRenderProps<\n T extends Record<string, unknown> = Record<string, unknown>,\n> {\n pending: boolean;\n data: T;\n /**\n * Keyed by field name, so a typo is a type error rather than undefined.\n *\n * Partial because most fields have none, and nested paths join with dots —\n * `errors['address.city']`, which is the key a Standard Schema issue for that\n * field produces.\n */\n errors: Partial<Record<keyof T & string, string[]>> &\n Record<string, string[] | undefined>;\n error: (field: keyof T & string) => string | undefined;\n clearErrors: (...fields: (keyof T & string)[]) => void;\n reset: () => void;\n /**\n * Whether anything differs from what the form started with.\n *\n * For the Save button that stays quiet until there is something to save,\n * and the Discard that appears beside it. Read from the form itself - a\n * snapshot of its FormData on mount, compared on every input - so an\n * uncontrolled field counts, which nothing outside the form can do. A\n * successful submit makes the current values the new baseline; `reset()`\n * goes back to the first one.\n */\n dirty: boolean;\n /** Whether the last submit was accepted. */\n succeeded: boolean;\n /**\n * The same thing, for two seconds.\n *\n * The \"Saved ✓\" that appears and fades. Worth having as state rather than a\n * timer in every form that wants one, because the timer has to be cleared\n * when the component goes away and that is the part people forget.\n */\n recentlySucceeded: boolean;\n /**\n * Bind one field so this component holds its value.\n *\n * Most fields need nothing: they are uncontrolled, the DOM holds the value,\n * and it is read back as FormData on submit. Reach for this when the DOM\n * cannot hold it for you — a control with no native element behind it, or a\n * value you want to read as it is typed:\n *\n * <Input {...field('title')} />\n * <span>{field('body').value.length}/100</span>\n *\n * A bound field is still an ordinary named input, so it arrives in FormData\n * with everything else. Nothing merges; there is one source of truth.\n */\n field: <K extends keyof T & string>(name: K) => FieldBinding<T[K]>;\n /**\n * What is known about a field, for deciding how to show it.\n *\n * const title = fieldState('title')\n *\n * <Field data-invalid={title.invalid}>\n * <Input {...field('title')} aria-invalid={title.invalid} />\n * <FieldError errors={title.errors.map((message) => ({ message }))} />\n * </Field>\n *\n * `touched` is what separates \"not filled in yet\" from \"filled in wrongly\" —\n * an error on a field nobody has visited is a form shouting before anyone\n * has done anything.\n */\n fieldState: (name: string) => FieldState;\n}\n\ninterface FormProps<\n T extends Record<string, unknown> = Record<string, unknown>,\n> extends Omit<\n FormHTMLAttributes<HTMLFormElement>,\n \"action\" | \"method\" | \"children\" | \"onSubmit\" | \"onError\"\n> {\n action: Href | ((formData: FormData) => Promise<unknown>);\n method?: \"get\" | \"post\";\n /**\n * The <form> element, for a caller that needs it - to focus, to scroll to,\n * to hand a library. The form keeps its own handle beside it; a caller's\n * never replaces it.\n */\n ref?: Ref<HTMLFormElement>;\n /**\n * Starting values for fields bound with `field()`.\n *\n * Uncontrolled fields do not need this — they take React's own\n * `defaultValue`, and the DOM keeps whatever is typed into them.\n */\n defaultValues?: Partial<T>;\n /**\n * A store created above this form, from `useFormStore()`.\n *\n * For the one case the context cannot reach: something that is not a\n * descendant — a top bar showing unsaved changes, a sidebar preview — needs\n * the values to exist above both of them. Create the store where they share\n * an ancestor and hand it down.\n *\n * Without it the form makes its own, which is what almost every form wants.\n */\n store?: FormStore;\n prefetch?: PrefetchStrategy;\n cacheFor?: number;\n replace?: boolean;\n preserveScroll?: boolean;\n resetOnSuccess?: boolean;\n /**\n * Check the fields before submitting, with any Standard Schema — Zod,\n * Valibot, ArkType.\n *\n * A failure fills `errors` and the action is never called, so a mistake\n * costs no round trip. It is a courtesy and not a control: the same action\n * is reachable without this form, so the server still has to check.\n */\n schema?: StandardSchemaV1;\n /** Transform form data before submitting to the server action. */\n transform?: (data: T) => Record<string, unknown>;\n /** Called inside the transition with typed form data. Use it to call your useOptimistic setter. */\n optimistic?: (data: T) => void;\n onSuccess?: (result: unknown) => void;\n /**\n * Called when a submit does not succeed.\n *\n * Validation failures arrive as field errors, with no second argument.\n * Anything else arrives as an empty error map and the thrown value — there\n * are no field errors to report, but the form still has to say so.\n */\n onError?: (errors: Record<string, string[]>, error?: unknown) => void;\n onSubmit?: (formData: FormData) => void | false;\n children: ReactNode | ((form: FormRenderProps<T>) => ReactNode);\n}\n\n/**\n * What an action built with createActionClient answers with.\n *\n * Recognised rather than thrown, because React serialises a rejected server\n * action opaquely: production strips the message and the fields it named are\n * gone. A returned object crosses intact, so a form reads it.\n */\nfunction resultOf(\n value: unknown,\n): { errors?: Record<string, string[]>; serverError?: string; redirected?: string } | null {\n if (typeof value !== \"object\" || value === null) return null;\n\n const result = value as {\n validationErrors?: Record<string, string[]>;\n serverError?: string;\n redirected?: string;\n };\n\n if (result.validationErrors) return { errors: result.validationErrors };\n if (result.serverError) return { serverError: result.serverError };\n if (typeof result.redirected === \"string\") return { redirected: result.redirected };\n\n return null;\n}\n\nconst FormStatusContext = createContext<FormRenderProps>({\n pending: false,\n data: {},\n dirty: false,\n errors: {},\n error: () => undefined,\n clearErrors: () => {},\n reset: () => {},\n succeeded: false,\n recentlySucceeded: false,\n // Outside a Form there is nothing holding a value, so a binding that reported\n // one would be lying. Name only, which is the part that is still true.\n field: ((name: string) => ({\n name,\n value: \"\",\n onChange: () => {},\n onBlur: () => {},\n })) as FormRenderProps[\"field\"],\n fieldState: () => ({ touched: false, invalid: false, errors: [] }),\n});\n\n/**\n * The store, on its own context.\n *\n * Separate from the status context because that one holds a fresh object every\n * render, so anything reading it re-renders with the form. The store is stable\n * for the life of the form, which is what lets a subscriber below it re-render\n * alone.\n */\nconst FormStoreContext = createContext<{\n store: FormStore;\n touch: (name: string) => void;\n} | null>(null);\n\n/**\n * A value store created above the form rather than by it.\n *\n * const store = useFormStore({ title: '' })\n *\n * <TopBar store={store} /> // not inside the form\n * <Form action={save} store={store}>…</Form>\n *\n * For the one case the context cannot reach. `<Form>` makes its own otherwise,\n * and almost every form should let it — this exists so that a component which\n * is not a descendant can still read the values, which is the flexibility\n * react-hook-form and TanStack Form get from `useForm()` being yours to call.\n *\n * Deliberately not reactive itself: creating the store does not subscribe to\n * it, so the component holding it does not re-render on every keystroke and\n * take the whole subtree with it. Read it with `useFormValues(store)`.\n */\nexport function useFormStore<T extends Record<string, unknown>>(\n initial: Partial<T> = {},\n): FormStore {\n const ref = useRef<FormStore | null>(null);\n\n ref.current ??= createFormStore({ ...initial });\n\n return ref.current;\n}\n\n/**\n * One field, subscribed on its own.\n *\n * The same thing `field()` gives, from a component that re-renders when this\n * field changes and at no other time. Reach for it when a form is large enough\n * that re-rendering all of it per keystroke is real:\n *\n * function Title() {\n * const { field, invalid, errors } = useField('title')\n *\n * return <Input {...field} aria-invalid={invalid} />\n * }\n *\n * Which is react-hook-form's `<Controller>` without the render prop: the\n * component you already had to write is the subscription boundary.\n */\nexport function useField(\n name: string,\n store?: FormStore,\n): FieldBinding<string> & FieldState {\n const ctx = useContext(FormStoreContext);\n const status = useContext(FormStatusContext);\n\n if (!ctx && !store) {\n throw new Error(\n \"useField() was called outside a <Form>. It reads that form's values, so there has to be one above it.\",\n );\n }\n\n const source = store ?? ctx!.store;\n const touch = ctx?.touch;\n\n const value = useSyncExternalStore(\n source.subscribe,\n () => (source.get(name) ?? \"\") as string,\n () => \"\",\n );\n\n const errors = status.errors[name] ?? [];\n\n return {\n name,\n value,\n onChange: (next) => {\n source.set(\n name,\n typeof next === \"object\" && next !== null && \"target\" in next\n ? (next as { target: { value: string } }).target.value\n : next,\n );\n },\n onBlur: () => void touch?.(name),\n touched: status.fieldState(name).touched,\n invalid: errors.length > 0,\n errors,\n };\n}\n\n/**\n * Every bound value, from anywhere inside the form.\n *\n * For a summary, a preview, a count of what has changed — something that reads\n * the form without being a field in it. Only values bound through `field()` or\n * `useField` are here: an uncontrolled input's value belongs to the DOM, and\n * this has no way to know it changed.\n */\nexport function useFormValues<T extends Record<string, unknown>>(\n store?: FormStore,\n): Partial<T> {\n const ctx = useContext(FormStoreContext);\n\n if (!ctx && !store) {\n throw new Error(\n \"useFormValues() was called outside a <Form>. It reads that form's values, so there has to be one above it.\",\n );\n }\n\n const source = store ?? ctx!.store;\n\n return useSyncExternalStore(\n source.subscribe,\n () => source.all() as Partial<T>,\n () => ({}) as Partial<T>,\n );\n}\n\nexport function useFormStatus<\n T extends Record<string, unknown> = Record<string, unknown>,\n>(): FormRenderProps<T> {\n return useContext(FormStatusContext) as FormRenderProps<T>;\n}\n\n/**\n * submitForm bound to an action, once per action.\n *\n * Bound on every render, it was a fresh function with a fresh promise for\n * its bound arguments each time - and React, seating a posted form's state\n * during the server render, suspends on that promise until it settles, then\n * renders the component again, which bound again. A render that never\n * finished, on every page a form was posted to without javascript. One\n * bound function per action, and the promise settles once.\n */\nconst boundSubmits = new WeakMap<Function, (previous: unknown, formData: FormData) => Promise<unknown>>();\n\nfunction boundSubmit(action: (formData: FormData) => Promise<unknown>) {\n let bound = boundSubmits.get(action);\n\n if (!bound) {\n bound = submitForm.bind(null, action);\n boundSubmits.set(action, bound);\n }\n\n return bound;\n}\n\n/**\n * A form's values as one comparable string.\n *\n * FormData in document order, a file by its name and size: enough to say\n * whether anything changed, which is all `dirty` asks.\n */\nfunction serializeForm(form: HTMLFormElement): string {\n const parts: string[] = [];\n\n for (const [name, value] of new FormData(form)) {\n parts.push(\n name + \"=\" + (typeof value === \"string\" ? value : \"file:\" + value.name + \":\" + value.size),\n );\n }\n\n return parts.join(\"\\n\");\n}\n\n/**\n * Also exported by name, and re-exported below, because both spellings are in\n * use: `import Form from` and `import { Form } from`.\n */\nexport default function Form<\n T extends Record<string, unknown> = Record<string, unknown>,\n>({\n action,\n method: methodProp,\n defaultValues,\n store: providedStore,\n prefetch = \"hover\",\n cacheFor,\n replace = false,\n preserveScroll = false,\n resetOnSuccess = true,\n schema,\n transform,\n optimistic,\n onSuccess,\n onError,\n onSubmit,\n children,\n ref: callerRef,\n ...rest\n}: FormProps<T>) {\n const isGetForm = typeof action === \"string\";\n const method = methodProp ?? (isGetForm ? \"get\" : \"post\");\n\n // The answer to this form posted without a runtime, seated by React into\n // the form that posted it - which is the only way a visitor with no\n // javascript sees a refusal. Registered through submitForm, bound to the\n // action, because React hands a form-state action a (previous, formData)\n // pair and the action takes the FormData alone. On the server a plain\n // function - a closure, not a server reference - cannot be bound into a\n // form; the form falls back to the action itself, and posts nothing\n // seatable, which is all a closure could ever have done.\n const bindable =\n typeof action === \"function\" && (typeof window !== \"undefined\" || \"$$FORM_ACTION\" in action);\n const [posted, formAction] = useActionState(\n bindable ? boundSubmit(action as (formData: FormData) => Promise<unknown>) : async () => null,\n null as unknown,\n );\n const postedRefusal = resultOf(posted);\n const [errors, setErrors] = useState<Record<string, string[]>>(() => postedRefusal?.errors ?? {});\n const [touched, setTouched] = useState<Record<string, boolean>>({});\n\n /**\n * Mark a field visited, and check it.\n *\n * Checking on blur rather than on every keystroke, because an error that\n * appears while someone is halfway through typing an email address is a form\n * arguing with them. Leaving the field is the moment they have finished\n * saying what they meant.\n *\n * The whole object is validated and only this field's issues are kept: a\n * Standard Schema has no notion of one field, and filtering by path is the\n * honest way to ask it about one. Everything else's errors are left as they\n * were, so blurring an empty field does not light up the rest of the form.\n */\n const touch = useCallback(\n async (name: string) => {\n setTouched((prev) => (prev[name] ? prev : { ...prev, [name]: true }));\n\n if (!schema || !formRef.current) return;\n\n const invalid = await validateWith(\n schema,\n decodeFormData(new FormData(formRef.current), schema),\n );\n\n setErrors((prev) => {\n const next = { ...prev };\n\n if (invalid?.[name]) next[name] = invalid[name];\n else delete next[name];\n\n return next;\n });\n },\n [schema],\n );\n\n const [succeeded, setSucceeded] = useState(false);\n const [recentlySucceeded, setRecentlySucceeded] = useState(false);\n const recentTimer = useRef<ReturnType<typeof setTimeout> | undefined>(\n undefined,\n );\n\n // Cleared on unmount: a timer that fires into a component that has gone is\n // the warning nobody reads and the leak nobody finds.\n useEffect(() => () => clearTimeout(recentTimer.current), []);\n\n // Only the fields someone bound. Everything else is the DOM's.\n //\n // A store rather than state, so a component using `useField` can re-render\n // for one field while this one does not. See formStore.ts.\n const storeRef = useRef<FormStore | null>(null);\n\n storeRef.current ??= createFormStore({\n ...(defaultValues as Record<string, unknown> | undefined),\n });\n\n const store = providedStore ?? storeRef.current;\n\n // Which names the render prop read through `field()`. A change to one of\n // those has to re-render this component, because that is where the value is\n // being displayed; a change to anything else does not, which is what lets a\n // `useField` child stand on its own.\n const readHere = useRef(new Set<string>());\n const [, bump] = useState(0);\n\n useEffect(\n () =>\n store.subscribe((name) => {\n if (name === \"\" || readHere.current.has(name)) bump((n) => n + 1);\n }),\n [store],\n );\n const [currentData, setCurrentData] = useState<T>({} as T);\n const [isPending, startTransition] = useTransition();\n const formRef = useRef<HTMLFormElement>(null);\n\n // What the form started with, as its FormData reads: the baseline `dirty`\n // is measured against. Taken on mount, retaken after a successful submit.\n const baseline = useRef<string | null>(null);\n const [dirty, setDirty] = useState(false);\n // Only a form that reads `dirty` pays for it: the flip from clean to dirty\n // is a render of the whole form, and a field that subscribes for itself\n // is promised that typing in it renders it alone.\n const dirtyRead = useRef(false);\n\n const snapshot = useCallback(() => {\n if (!formRef.current) return;\n\n baseline.current = serializeForm(formRef.current);\n setDirty(false);\n }, []);\n\n const measureDirty = useCallback(() => {\n if (!dirtyRead.current || !formRef.current || baseline.current === null) return;\n\n const now = serializeForm(formRef.current) !== baseline.current;\n\n setDirty((was) => (was === now ? was : now));\n }, []);\n\n useEffect(snapshot, [snapshot]);\n\n // A bound control with no native element behind it changes through the\n // store, not through an input event - a Radix select - so the store is\n // watched too. Its input, if it has one, is read back with the rest.\n useEffect(() => store.subscribe(() => queueMicrotask(measureDirty)), [store, measureDirty]);\n\n // Both handles, one element. React 19 hands a function component its ref\n // as a prop, and spread after the form's own it replaced it - every\n // FormData read then found null. A caller's ref is filled beside ours.\n const attachForm = useCallback(\n (element: HTMLFormElement | null) => {\n formRef.current = element;\n\n if (typeof callerRef === \"function\") callerRef(element);\n else if (callerRef) callerRef.current = element;\n },\n [callerRef],\n );\n\n const error = useCallback(\n (field: keyof T & string): string | undefined => errors[field]?.[0],\n [errors],\n );\n\n const clearErrors = useCallback((...fields: (keyof T & string)[]) => {\n if (fields.length === 0) {\n setErrors({});\n } else {\n setErrors((prev) => {\n const next = { ...prev };\n for (const f of fields) {\n delete next[f];\n }\n return next;\n });\n }\n }, []);\n\n const resetForm = useCallback(() => {\n formRef.current?.reset();\n setErrors({});\n setCurrentData({} as T);\n queueMicrotask(measureDirty);\n }, [measureDirty]);\n\n useEffect(() => {\n if (isGetForm && prefetch === \"mount\") {\n const fn = (window as any).__rsc_prefetch;\n fn?.(action, cacheFor);\n }\n }, [isGetForm, prefetch, action, cacheFor]);\n\n const doPrefetch = useCallback(() => {\n if (!isGetForm) return;\n const fn = (window as any).__rsc_prefetch;\n fn?.(action as string, cacheFor);\n }, [isGetForm, action, cacheFor]);\n\n const handleSubmit = useCallback(\n async (e: FormEvent<HTMLFormElement>) => {\n e.preventDefault();\n const formData = new FormData(e.currentTarget);\n const data = decodeFormData<T>(formData, schema);\n setCurrentData(data);\n\n if (onSubmit?.(formData) === false) {\n return;\n }\n\n if (isGetForm && method === \"get\") {\n const url = new URL(action as string, window.location.origin);\n for (const [key, value] of formData.entries()) {\n if (typeof value === \"string\" && value !== \"\") {\n url.searchParams.set(key, value);\n }\n }\n\n const path = url.pathname + url.search;\n const shell = action as string;\n const nav = (window as any).__rsc_navigate;\n const prefetched = (window as any).__rsc_is_prefetched;\n\n // The route without its query is that route's shell: the layout, the\n // chrome, and whatever it renders with nothing to show yet. Prefetching\n // on hover put it in the cache, so going there first costs no request\n // and puts the page on screen while the real query is still running.\n //\n // The query itself is never prefetched. It is the expensive half, and\n // hovering a search button is not a reason to run someone's search.\n if (path !== shell && prefetched?.(shell)) {\n // Awaited rather than raced: navigate() aborts whatever is in flight,\n // so starting the real one first would cancel the shell before it\n // could render. It is a cache hit, so this is a render, not a wait.\n Promise.resolve(nav?.(shell, { replace, preserveScroll })).then(() =>\n // Replaces, so the shell does not become a back-button stop of its\n // own — the pair leaves exactly one entry behind.\n nav?.(path, { replace: true, preserveScroll }),\n );\n\n return;\n }\n\n nav?.(path, { replace, preserveScroll });\n return;\n }\n\n const serverAction = action as (formData: FormData) => Promise<unknown>;\n\n // Rebuilt rather than edited: transform returns the values to send, so\n // whatever was in the form and is not in the result should not go.\n if (transform) {\n for (const key of [...formData.keys()]) formData.delete(key);\n\n for (const [key, value] of buildFormData(transform(data))) {\n formData.append(key, value);\n }\n }\n\n setErrors({});\n\n // Before the transition, so a failure neither runs the optimistic\n // update nor leaves the form looking like it is submitting.\n const invalid = await validateWith(schema, data);\n\n if (invalid) {\n setErrors(invalid);\n onError?.(invalid);\n\n return;\n }\n\n startTransition(async () => {\n try {\n // Call optimistic updater inside the transition so React's\n // useOptimistic picks it up and auto-reverts on settle.\n optimistic?.(data);\n\n const result = await serverAction(formData);\n const refused = resultOf(result);\n\n // The action answered with somewhere to go, and callServer has\n // already started the navigation. Not an error for a form to\n // show, and not a save to announce either: signing in and going\n // to the dashboard is the whole success.\n if (refused?.redirected !== undefined || redirectedTo() !== null) return;\n\n if (refused) {\n if (refused.errors) {\n setErrors(refused.errors);\n onError?.(refused.errors);\n } else {\n onError?.({}, new Error(refused.serverError));\n }\n\n return;\n }\n\n if (resetOnSuccess) {\n formRef.current?.reset();\n setTouched({});\n setCurrentData({} as T);\n }\n\n // Saved: what is in the form now is what the server has.\n snapshot();\n\n setErrors({});\n setSucceeded(true);\n setRecentlySucceeded(true);\n\n clearTimeout(recentTimer.current);\n recentTimer.current = setTimeout(\n () => setRecentlySucceeded(false),\n 2_000,\n );\n\n onSuccess?.(result);\n } catch (err) {\n // A redirect no longer arrives here - callServer resolves after\n // performing it - but an action called through something older\n // than that still may.\n if (err instanceof ServerRedirectError) return;\n\n if (err instanceof ServerValidationError) {\n setErrors(err.errors);\n onError?.(err.errors);\n } else if (err instanceof ServerDumpError) {\n // Dump overlay is already shown — silently swallow\n } else if (onError) {\n // Not rethrown. A rejected action never settles, and until it\n // settles React keeps the optimistic update on screen — so an\n // unexpected failure left the row showing as though the write had\n // worked. Settling is what takes it back.\n onError({}, err);\n } else {\n // Nothing is handling it, and swallowing here would lose it\n // entirely — the reason this used to rethrow.\n console.error(\"[rsc-kit] form submit failed\", err);\n }\n }\n });\n },\n [\n action,\n isGetForm,\n method,\n replace,\n preserveScroll,\n resetOnSuccess,\n schema,\n transform,\n optimistic,\n onSubmit,\n onSuccess,\n onError,\n ],\n );\n\n const field = useCallback(\n <K extends keyof T & string>(name: K): FieldBinding<T[K]> => {\n // Recorded during render, deliberately: this is how the form knows which\n // values it is the one displaying. Idempotent, so a double render in\n // development records the same name twice and means the same thing.\n readHere.current.add(name);\n\n return {\n name,\n value: (store.get(name) ?? \"\") as T[K],\n onChange: (next: unknown) => {\n const value =\n typeof next === \"object\" && next !== null && \"target\" in next\n ? (next as { target: { value: string } }).target.value\n : next;\n\n store.set(name, value);\n },\n onBlur: () => void touch(name),\n };\n },\n [store, touch],\n );\n\n const fieldState = useCallback(\n (name: string): FieldState => ({\n touched: touched[name] === true,\n invalid: (errors[name]?.length ?? 0) > 0,\n errors: errors[name] ?? [],\n }),\n [touched, errors],\n );\n\n // Stable, so a subscriber below does not re-render because this one did.\n const storeContext = useMemo(() => ({ store, touch }), [store, touch]);\n\n const formStatus: FormRenderProps<T> = {\n pending: isPending,\n data: currentData,\n get dirty() {\n dirtyRead.current = true;\n\n return dirty;\n },\n succeeded,\n recentlySucceeded,\n field,\n fieldState,\n errors: errors as FormRenderProps<T>[\"errors\"],\n error,\n clearErrors,\n reset: resetForm,\n };\n\n return (\n <FormStoreContext.Provider value={storeContext}>\n <FormStatusContext.Provider value={formStatus as FormRenderProps}>\n <form\n ref={attachForm}\n // On the element as well as in the handler, which is what makes this\n // work before hydration. React emits a form a browser can submit on its\n // own for a server action, and an ordinary action/method pair for a\n // url — so a submit that happens before the javascript arrives still\n // reaches the server.\n //\n // The two do not fight: handleSubmit calls preventDefault() first, and\n // React does not run a form action when the submit event was cancelled.\n // So the enhanced path wins whenever there is one, and the native path\n // is what is left when there is not.\n action={(bindable ? formAction : action) as never}\n // Only for a url. React sets the method itself for a server action, and\n // passing one alongside is what it warns about.\n method={isGetForm ? method : undefined}\n onSubmit={handleSubmit}\n // Every keystroke and every toggle, from any control in the form,\n // uncontrolled ones included: React's onInput here is the bubbling\n // `input` event. A caller's own handler still runs.\n onInput={(event) => {\n rest.onInput?.(event);\n measureDirty();\n }}\n onChange={(event) => {\n rest.onChange?.(event);\n measureDirty();\n }}\n // On the form, not only on the bound fields. `focusout` bubbles where\n // `blur` does not, so React's onBlur here sees every control that was\n // left — including the uncontrolled ones, which are most of them and\n // would otherwise never be marked touched at all.\n onBlur={(event) => {\n const target = event.target as unknown as {\n name?: string;\n value?: string;\n };\n const name = target.name;\n\n if (!name) return;\n\n // Leaving a field is the moment to check it; leaving the form is\n // not the same moment. Focus going to nothing, or to something\n // outside the form, is a click on the page - most often a dialog\n // closing - and an error painted into a dialog as it animates out\n // reads as a submit that nobody made. An empty field left that way\n // is not checked at all. One with something in it is, but only\n // once the dust settles: if the form is gone or hidden by then, it\n // was a dialog closing, and nobody is there to read the error.\n const left = event.relatedTarget as Node | null;\n const stillInForm = !!left && !!formRef.current?.contains(left);\n\n if (stillInForm) {\n void touch(name);\n\n return;\n }\n\n if (!target.value) return;\n\n setTimeout(() => {\n const form = formRef.current;\n\n if (\n !form ||\n !form.isConnected ||\n form.getClientRects().length === 0\n )\n return;\n if (\n form.closest(\n \"[hidden], [aria-hidden='true'], [data-ending-style], [data-closed]\",\n )\n )\n return;\n\n void touch(name);\n }, LEAVE_FORM_SETTLE_MS);\n }}\n onMouseEnter={prefetch === \"hover\" ? doPrefetch : undefined}\n data-pending={isPending ? \"\" : undefined}\n {...rest}\n >\n {typeof children === \"function\" ? children(formStatus) : children}\n </form>\n </FormStatusContext.Provider>\n </FormStoreContext.Provider>\n );\n}\n\n// Also by name, because both spellings are in use: `import Form` and\n// `import { Form }`. This was a re-export of \"./Form\" — from inside Form.tsx,\n// so the module named itself. It survived on the bundler tolerating a circular\n// self-reference, left over from when a separate barrel re-exported a\n// FormComponent.tsx that a case-insensitive filesystem would not let be called\n// Form.ts. There is one file now, and it can just export what it declares.\nexport { Form };\n"]}
@@ -0,0 +1,5 @@
1
+ import { type ReactNode } from "react";
2
+ export declare function LoadingBoundary({ fallback, children, }: {
3
+ fallback: ReactNode;
4
+ children: ReactNode;
5
+ }): import("react").JSX.Element;
@@ -0,0 +1,19 @@
1
+ "use client";
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ // The engine's own Suspense: the one a loading.tsx becomes.
4
+ //
5
+ // A component, and a named one, for the report and nothing else. When a read
6
+ // is caught at a boundary during a server render, the component stack says
7
+ // whose boundary it was - and the stack is the only thing that does. It
8
+ // used to be inferred from what stood two frames outside the nearest
9
+ // Suspense, which held for a first render and broke on a PPR resume: React
10
+ // leaves server components out of that stack, so a <Suspense> the developer
11
+ // wrote as the first thing in a page sat directly under the engine's
12
+ // segment boundary and was reported as a loading.tsx catching the whole
13
+ // segment - a warning nobody could make go away, on every request. Now the
14
+ // engine's boundary is the one rendered by LoadingBoundary, and only that.
15
+ import { Suspense } from "react";
16
+ export function LoadingBoundary({ fallback, children, }) {
17
+ return _jsx(Suspense, { fallback: fallback, children: children });
18
+ }
19
+ //# sourceMappingURL=LoadingBoundary.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LoadingBoundary.js","sourceRoot":"","sources":["../../src/js/LoadingBoundary.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,4DAA4D;AAC5D,EAAE;AACF,6EAA6E;AAC7E,2EAA2E;AAC3E,wEAAwE;AACxE,qEAAqE;AACrE,2EAA2E;AAC3E,4EAA4E;AAC5E,qEAAqE;AACrE,wEAAwE;AACxE,2EAA2E;AAC3E,2EAA2E;AAC3E,OAAO,EAAE,QAAQ,EAAkB,MAAM,OAAO,CAAC;AAEjD,MAAM,UAAU,eAAe,CAAC,EAC9B,QAAQ,EACR,QAAQ,GAIT;IACC,OAAO,KAAC,QAAQ,IAAC,QAAQ,EAAE,QAAQ,YAAG,QAAQ,GAAY,CAAC;AAC7D,CAAC","sourcesContent":["\"use client\";\n\n// The engine's own Suspense: the one a loading.tsx becomes.\n//\n// A component, and a named one, for the report and nothing else. When a read\n// is caught at a boundary during a server render, the component stack says\n// whose boundary it was - and the stack is the only thing that does. It\n// used to be inferred from what stood two frames outside the nearest\n// Suspense, which held for a first render and broke on a PPR resume: React\n// leaves server components out of that stack, so a <Suspense> the developer\n// wrote as the first thing in a page sat directly under the engine's\n// segment boundary and was reported as a loading.tsx catching the whole\n// segment - a warning nobody could make go away, on every request. Now the\n// engine's boundary is the one rendered by LoadingBoundary, and only that.\nimport { Suspense, type ReactNode } from \"react\";\n\nexport function LoadingBoundary({\n fallback,\n children,\n}: {\n fallback: ReactNode;\n children: ReactNode;\n}) {\n return <Suspense fallback={fallback}>{children}</Suspense>;\n}\n"]}
@@ -4,4 +4,5 @@ export declare function createViteRscApp(container?: Document | Element, interce
4
4
  }[], options?: {
5
5
  staticPayloads?: string | null;
6
6
  routes?: unknown[] | null;
7
+ apiRoutes?: string[];
7
8
  }): Promise<void>;
@@ -13,12 +13,16 @@ import { createFromReadableStream, encodeReply, setServerCallback, } from "@vite
13
13
  import { createElement } from "react";
14
14
  import { hydrateRoot } from "react-dom/client";
15
15
  import { ActivityRoot } from "./ActivityRouter";
16
- import { ServerRedirectError, throwForFailedAction } from "./errors";
16
+ import { ServerRedirectError, noteRedirected, throwForFailedAction } from "./errors";
17
17
  import { fetchPagePayload } from "./pagePayload";
18
18
  import { claimRead, setQueryCodec } from "./queryClient";
19
19
  import { clearSegments, restoreSegments, setSegment } from "./segmentStore";
20
- import { cancelPrefetch, isPrefetched, navigate, refresh, applyRevalidated, prefetch, retentionKey, setCallServer, setHeldLayouts, setStaticPayloads, setStaticRoutes, seedStaticChain, payloadUrl, setDeserializer, setInterceptManifest, setNavigateHandler, setRestoreHandler, setVersion, } from "./navigate";
20
+ import { cancelPrefetch, isPrefetched, navigate, setApiRoutes, refresh, applyRevalidated, prefetch, retentionKey, setCallServer, setHeldLayouts, setStaticPayloads, setStaticRoutes, seedStaticChain, payloadUrl, setDeserializer, setInterceptManifest, setNavigateHandler, setRestoreHandler, setVersion, } from "./navigate";
21
21
  export async function createViteRscApp(container = document, interceptEntries = [], options = {}) {
22
+ // The urls a route.ts answers: a link to one is an anchor, never a
23
+ // prefetch, never a payload fetch.
24
+ if (options.apiRoutes)
25
+ setApiRoutes(options.apiRoutes);
22
26
  // An exported build has no server to negotiate with, so payloads live at
23
27
  // their own urls rather than behind a header on the page's url.
24
28
  setStaticPayloads(options.staticPayloads ?? null);
@@ -84,9 +88,22 @@ export async function createViteRscApp(container = document, interceptEntries =
84
88
  if (err instanceof ServerRedirectError) {
85
89
  // The destination came off a response header, so it is checked here
86
90
  // too — the engine refuses these at the source, but a proxy or a host
87
- // in front of it can write whatever it likes.
88
- if (isSafeRedirect(err.location))
89
- window.location.href = err.location;
91
+ // in front of it can write whatever it likes. A navigation, not a
92
+ // document load: the layouts stay mounted and the history entry the
93
+ // form was on is replaced, the way a redirect after a POST should
94
+ // be - Back does not return to the submitted form.
95
+ if (isSafeRedirect(err.location)) {
96
+ void navigate(err.location, { replace: true });
97
+ }
98
+ // Performed, so resolved - not thrown. The call's answer is "you are
99
+ // being taken somewhere": an object saying so, the shape an action's
100
+ // result already has, so a caller reading result.validationErrors
101
+ // reads undefined rather than throwing. A caller that awaited the
102
+ // action in a plain startTransition had no catch for a throw, the
103
+ // rejection reached React, and the root unmounted to a white page
104
+ // on every logout.
105
+ noteRedirected(err.location);
106
+ return { redirected: err.location };
90
107
  }
91
108
  throw err;
92
109
  }
@@ -202,6 +219,18 @@ export async function createViteRscApp(container = document, interceptEntries =
202
219
  // in the background is not a fault in the page.
203
220
  if (message.includes("Transition was aborted"))
204
221
  return;
222
+ // A navigation another one overtook: its request was aborted, and a
223
+ // row of its payload that a component was still reading rejects with
224
+ // the abort. React recovers by rendering the root again synchronously
225
+ // and reports the recovery here as #520, with the abort as the cause.
226
+ // The page it recovered to is the one the second navigation asked for;
227
+ // the abort was the design, not a fault.
228
+ const cause = error?.cause;
229
+ if (cause?.name === "AbortError" ||
230
+ /\baborted\b/i.test(cause?.message ?? "") ||
231
+ /\baborted\b/i.test(message)) {
232
+ return;
233
+ }
205
234
  // A page whose query string was read under a boundary carries the
206
235
  // fallback there; React reports the recovery on hydration. Under a
207
236
  // boundary the developer wrote, that is the designed path and nothing
@@ -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 { showDevNotice } from \"./devNotice\";\nimport { caughtByLoading } from \"./fallbackReport\";\nimport { noteNavigation } from \"./segmentStore\";\nimport type { Href } from \"../routes.js\";\nimport { isSafeRedirect } from \"../safeUrl.js\";\nimport {\n createFromReadableStream,\n encodeReply,\n setServerCallback,\n} from \"@vitejs/plugin-rsc/browser\";\nimport { createElement } from \"react\";\nimport { hydrateRoot } from \"react-dom/client\";\nimport { ActivityRoot } from \"./ActivityRouter\";\nimport { ServerRedirectError, throwForFailedAction } from \"./errors\";\nimport { fetchPagePayload } from \"./pagePayload\";\nimport { claimRead, setQueryCodec } from \"./queryClient\";\nimport { clearSegments, restoreSegments, setSegment } from \"./segmentStore\";\nimport type { ReactNode } from \"react\";\nimport {\n cancelPrefetch,\n isPrefetched,\n navigate,\n refresh,\n applyRevalidated,\n prefetch,\n retentionKey,\n setCallServer,\n setHeldLayouts,\n setStaticPayloads,\n setStaticRoutes,\n seedStaticChain,\n payloadUrl,\n setDeserializer,\n setInterceptManifest,\n setNavigateHandler,\n setRestoreHandler,\n setVersion,\n} from \"./navigate\";\n\nexport async function createViteRscApp(\n container: Document | Element = document,\n interceptEntries: { urlPattern: string; slot: string }[] = [],\n options: { staticPayloads?: string | null; routes?: unknown[] | null } = {},\n): Promise<void> {\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 const res = await fetch(\"/_rsc/action\", {\n method: \"POST\",\n headers: {\n \"X-RSC-Action\": id,\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.\n \"X-RSC-Referer\": window.location.pathname + window.location.search,\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.\n if (isSafeRedirect(err.location)) window.location.href = err.location;\n }\n\n throw err;\n }\n\n const answer = await createFromReadableStream(res.body!, { callServer });\n\n return unwrapRevalidated(answer);\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): 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 for (const [target, tree] of Object.entries(envelope.__rscRevalidated)) {\n applyRevalidated(target, tree);\n }\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 const res = await fetchPagePayload(payloadUrl(window.location.href));\n\n // Seed the SPA engine with the build this page was served from, so a\n // redeploy mid-session is caught on the next navigation. This matters most\n // behind a CDN, where the shell may be cached from an older build.\n const servedVersion = 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 const servedLayouts = res.headers.get(\"X-RSC-Layouts\");\n\n if (servedLayouts !== null) {\n setHeldLayouts(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 const root = hydrateRoot(container, shell, {\n 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 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 // 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 // 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\n console.error(error, errorInfo);\n },\n });\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) => {\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);\n\n return;\n }\n\n clearSegments();\n root.render(newTree);\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\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 Href, { replace: true, restore: true });\n });\n\n history.replaceState(\n { rscUrl: window.location.href },\n \"\",\n window.location.href,\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\";\nimport { recoverFromStaleAssets } from \"./staleAssets\";\nimport { showDevNotice } from \"./devNotice\";\nimport { caughtByLoading } from \"./fallbackReport\";\nimport { noteNavigation } from \"./segmentStore\";\nimport type { Href } from \"../routes.js\";\nimport { isSafeRedirect } from \"../safeUrl.js\";\nimport {\n createFromReadableStream,\n encodeReply,\n setServerCallback,\n} from \"@vitejs/plugin-rsc/browser\";\nimport { createElement } from \"react\";\nimport { hydrateRoot } from \"react-dom/client\";\nimport { ActivityRoot } from \"./ActivityRouter\";\nimport { ServerRedirectError, noteRedirected, throwForFailedAction } from \"./errors\";\nimport { fetchPagePayload } from \"./pagePayload\";\nimport { claimRead, setQueryCodec } from \"./queryClient\";\nimport { clearSegments, restoreSegments, setSegment } from \"./segmentStore\";\nimport type { ReactNode } from \"react\";\nimport {\n cancelPrefetch,\n isPrefetched,\n navigate,\n setApiRoutes,\n refresh,\n applyRevalidated,\n prefetch,\n retentionKey,\n setCallServer,\n setHeldLayouts,\n setStaticPayloads,\n setStaticRoutes,\n seedStaticChain,\n payloadUrl,\n setDeserializer,\n setInterceptManifest,\n setNavigateHandler,\n setRestoreHandler,\n setVersion,\n} from \"./navigate\";\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 const res = await fetch(\"/_rsc/action\", {\n method: \"POST\",\n headers: {\n \"X-RSC-Action\": id,\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.\n \"X-RSC-Referer\": window.location.pathname + window.location.search,\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 if (isSafeRedirect(err.location)) {\n void navigate(err.location as Href, { replace: true });\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\n return unwrapRevalidated(answer);\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): 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 for (const [target, tree] of Object.entries(envelope.__rscRevalidated)) {\n applyRevalidated(target, tree);\n }\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 const res = await fetchPagePayload(payloadUrl(window.location.href));\n\n // Seed the SPA engine with the build this page was served from, so a\n // redeploy mid-session is caught on the next navigation. This matters most\n // behind a CDN, where the shell may be cached from an older build.\n const servedVersion = 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 const servedLayouts = res.headers.get(\"X-RSC-Layouts\");\n\n if (servedLayouts !== null) {\n setHeldLayouts(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 const root = hydrateRoot(container, shell, {\n 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 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 // 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\n console.error(error, errorInfo);\n },\n });\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) => {\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);\n\n return;\n }\n\n clearSegments();\n root.render(newTree);\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\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 Href, { replace: true, restore: true });\n });\n\n history.replaceState(\n { rscUrl: window.location.href },\n \"\",\n window.location.href,\n );\n}\n"]}
@@ -2,7 +2,9 @@ export declare class ServerValidationError extends Error {
2
2
  readonly errors: Record<string, string[]>;
3
3
  constructor(message: string, errors: Record<string, string[]>);
4
4
  }
5
- /** An action answered with a location instead of a result. */
5
+ export declare function noteRedirected(location: string): void;
6
+ /** The redirect the action just performed, if it did - read once. */
7
+ export declare function redirectedTo(): string | null;
6
8
  export declare class ServerRedirectError extends Error {
7
9
  readonly location: string;
8
10
  constructor(location: string);
package/dist/js/errors.js CHANGED
@@ -7,6 +7,25 @@ export class ServerValidationError extends Error {
7
7
  }
8
8
  }
9
9
  /** An action answered with a location instead of a result. */
10
+ /**
11
+ * The redirect the last action answered with, for the one caller that asks.
12
+ *
13
+ * An action that redirects resolves - the navigation is already under way
14
+ * and the caller has nothing to do - which leaves a form that wants to know
15
+ * whether to say "saved" with no way to tell a redirect from a void answer.
16
+ * callServer notes the destination here; <Form> reads and clears it right
17
+ * after its await. Nothing else needs to.
18
+ */
19
+ let lastRedirect = null;
20
+ export function noteRedirected(location) {
21
+ lastRedirect = location;
22
+ }
23
+ /** The redirect the action just performed, if it did - read once. */
24
+ export function redirectedTo() {
25
+ const location = lastRedirect;
26
+ lastRedirect = null;
27
+ return location;
28
+ }
10
29
  export class ServerRedirectError extends Error {
11
30
  location;
12
31
  constructor(location) {
@@ -51,13 +70,17 @@ export class ServerSessionExpiredError extends Error {
51
70
  * Returns without throwing when the response is a stream to be decoded.
52
71
  */
53
72
  export async function throwForFailedAction(response) {
54
- if (response.ok)
55
- return;
56
- // Auth and explicit redirects travel as a header, whatever the status.
73
+ // Before the status: a redirect the action asked for is a 204 with the
74
+ // destination in this header - an ok answer with no Flight in it - and
75
+ // an expired session's is a 401. Read first, the header decides for both.
76
+ // Read after `ok`, the 204 fell through to the Flight decoder with an
77
+ // empty body, and the form waited forever.
57
78
  const location = response.headers.get("X-RSC-Redirect");
58
79
  if (location !== null && location !== "") {
59
80
  throw new ServerRedirectError(location);
60
81
  }
82
+ if (response.ok)
83
+ return;
61
84
  if (response.status === 422) {
62
85
  const payload = (await response.json().catch(() => null));
63
86
  throw new ServerValidationError(payload?.message ?? "Validation failed", payload?.errors ?? {});
@@ -1 +1 @@
1
- {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/js/errors.ts"],"names":[],"mappings":"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","sourcesContent":["export class ServerValidationError extends Error {\n public readonly errors: Record<string, string[]>;\n\n constructor(message: string, errors: Record<string, string[]>) {\n super(message);\n this.name = \"ServerValidationError\";\n this.errors = errors;\n }\n}\n\n/** An action answered with a location instead of a result. */\nexport class ServerRedirectError extends Error {\n public readonly location: string;\n\n constructor(location: string) {\n super(`Server action redirected to ${location}`);\n this.name = \"ServerRedirectError\";\n this.location = location;\n }\n}\n\nexport class ServerAuthenticationError extends Error {\n constructor(message: string = \"Unauthenticated.\") {\n super(message);\n this.name = \"ServerAuthenticationError\";\n }\n}\n\nexport class ServerAuthorizationError extends Error {\n constructor(message: string = \"This action is unauthorized.\") {\n super(message);\n this.name = \"ServerAuthorizationError\";\n }\n}\n\nexport class ServerDumpError extends Error {\n constructor() {\n super(\"Server returned a dump response.\");\n this.name = \"ServerDumpError\";\n }\n}\n\nexport class ServerSessionExpiredError extends Error {\n constructor(message: string = \"Your session has expired. Please refresh the page.\") {\n super(message);\n this.name = \"ServerSessionExpiredError\";\n }\n}\n\n/**\n * Turn a failed server-action response into the error it describes.\n *\n * A server action that does not succeed answers with JSON or a redirect\n * header rather than a Flight stream. Passing one of those to the Flight\n * decoder does not produce the server's message — it produces an internal\n * parser failure (\"enqueueModel is not a function\") or a truncated read\n * (\"Connection closed.\"), which is what reached onError before this existed.\n *\n * Returns without throwing when the response is a stream to be decoded.\n */\nexport async function throwForFailedAction(response: Response): Promise<void> {\n if (response.ok) return;\n\n // Auth and explicit redirects travel as a header, whatever the status.\n const location = response.headers.get(\"X-RSC-Redirect\");\n\n if (location !== null && location !== \"\") {\n throw new ServerRedirectError(location);\n }\n\n if (response.status === 422) {\n const payload = (await response.json().catch(() => null)) as\n | { message?: string; errors?: Record<string, string[]> }\n | null;\n\n throw new ServerValidationError(\n payload?.message ?? \"Validation failed\",\n payload?.errors ?? {},\n );\n }\n\n if (response.status === 413) {\n throw new Error(\n \"Server action refused: the request body is larger than the server accepts. \" +\n \"A file upload is the usual cause; the limit is the host's maxActionBody.\",\n );\n }\n\n throw new Error(`Server action failed with ${response.status}`);\n}\n\n/**\n * Reject a payload response that is not one.\n *\n * The page a PPR route serves is a static shell: real HTML, status 200, with\n * its Suspense fallbacks showing. Everything below them arrives in a second\n * request. If that request fails there is nothing on screen to say so — the\n * skeletons simply stay, for ever — and handing the failure body to the Flight\n * decoder reports the decoder's confusion rather than the status.\n */\nexport function throwForFailedPayload(response: Response): void {\n if (response.ok) return;\n\n throw new Error(`RSC payload request failed with ${response.status}`);\n}\n\n/**\n * Announce a failure that nothing else will.\n *\n * Dispatched as well as logged: an app that wants to replace a stuck skeleton\n * with something honest has no other way to find out.\n */\nexport function reportClientFailure(scope: string, error: unknown): void {\n if (typeof window !== \"undefined\") {\n window.dispatchEvent(new CustomEvent(\"rsc-client-error\", { detail: { scope, error } }));\n }\n\n console.error(`[rsc-kit] ${scope}`, error);\n}\n"]}
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/js/errors.ts"],"names":[],"mappings":"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","sourcesContent":["export class ServerValidationError extends Error {\n public readonly errors: Record<string, string[]>;\n\n constructor(message: string, errors: Record<string, string[]>) {\n super(message);\n this.name = \"ServerValidationError\";\n this.errors = errors;\n }\n}\n\n/** An action answered with a location instead of a result. */\n/**\n * The redirect the last action answered with, for the one caller that asks.\n *\n * An action that redirects resolves - the navigation is already under way\n * and the caller has nothing to do - which leaves a form that wants to know\n * whether to say \"saved\" with no way to tell a redirect from a void answer.\n * callServer notes the destination here; <Form> reads and clears it right\n * after its await. Nothing else needs to.\n */\nlet lastRedirect: string | null = null;\n\nexport function noteRedirected(location: string): void {\n lastRedirect = location;\n}\n\n/** The redirect the action just performed, if it did - read once. */\nexport function redirectedTo(): string | null {\n const location = lastRedirect;\n\n lastRedirect = null;\n\n return location;\n}\n\nexport class ServerRedirectError extends Error {\n public readonly location: string;\n\n constructor(location: string) {\n super(`Server action redirected to ${location}`);\n this.name = \"ServerRedirectError\";\n this.location = location;\n }\n}\n\nexport class ServerAuthenticationError extends Error {\n constructor(message: string = \"Unauthenticated.\") {\n super(message);\n this.name = \"ServerAuthenticationError\";\n }\n}\n\nexport class ServerAuthorizationError extends Error {\n constructor(message: string = \"This action is unauthorized.\") {\n super(message);\n this.name = \"ServerAuthorizationError\";\n }\n}\n\nexport class ServerDumpError extends Error {\n constructor() {\n super(\"Server returned a dump response.\");\n this.name = \"ServerDumpError\";\n }\n}\n\nexport class ServerSessionExpiredError extends Error {\n constructor(message: string = \"Your session has expired. Please refresh the page.\") {\n super(message);\n this.name = \"ServerSessionExpiredError\";\n }\n}\n\n/**\n * Turn a failed server-action response into the error it describes.\n *\n * A server action that does not succeed answers with JSON or a redirect\n * header rather than a Flight stream. Passing one of those to the Flight\n * decoder does not produce the server's message — it produces an internal\n * parser failure (\"enqueueModel is not a function\") or a truncated read\n * (\"Connection closed.\"), which is what reached onError before this existed.\n *\n * Returns without throwing when the response is a stream to be decoded.\n */\nexport async function throwForFailedAction(response: Response): Promise<void> {\n // Before the status: a redirect the action asked for is a 204 with the\n // destination in this header - an ok answer with no Flight in it - and\n // an expired session's is a 401. Read first, the header decides for both.\n // Read after `ok`, the 204 fell through to the Flight decoder with an\n // empty body, and the form waited forever.\n const location = response.headers.get(\"X-RSC-Redirect\");\n\n if (location !== null && location !== \"\") {\n throw new ServerRedirectError(location);\n }\n\n if (response.ok) return;\n\n if (response.status === 422) {\n const payload = (await response.json().catch(() => null)) as\n | { message?: string; errors?: Record<string, string[]> }\n | null;\n\n throw new ServerValidationError(\n payload?.message ?? \"Validation failed\",\n payload?.errors ?? {},\n );\n }\n\n if (response.status === 413) {\n throw new Error(\n \"Server action refused: the request body is larger than the server accepts. \" +\n \"A file upload is the usual cause; the limit is the host's maxActionBody.\",\n );\n }\n\n throw new Error(`Server action failed with ${response.status}`);\n}\n\n/**\n * Reject a payload response that is not one.\n *\n * The page a PPR route serves is a static shell: real HTML, status 200, with\n * its Suspense fallbacks showing. Everything below them arrives in a second\n * request. If that request fails there is nothing on screen to say so — the\n * skeletons simply stay, for ever — and handing the failure body to the Flight\n * decoder reports the decoder's confusion rather than the status.\n */\nexport function throwForFailedPayload(response: Response): void {\n if (response.ok) return;\n\n throw new Error(`RSC payload request failed with ${response.status}`);\n}\n\n/**\n * Announce a failure that nothing else will.\n *\n * Dispatched as well as logged: an app that wants to replace a stuck skeleton\n * with something honest has no other way to find out.\n */\nexport function reportClientFailure(scope: string, error: unknown): void {\n if (typeof window !== \"undefined\") {\n window.dispatchEvent(new CustomEvent(\"rsc-client-error\", { detail: { scope, error } }));\n }\n\n console.error(`[rsc-kit] ${scope}`, error);\n}\n"]}
@@ -9,12 +9,16 @@
9
9
  * arrives, and a boundary closer to the read would keep the rest painted.
10
10
  *
11
11
  * The component stack says which: frames run from the component outward,
12
- * and the engine's segment boundaries render through SegmentBoundary or
13
- * SlotBoundary, so the frame just outside the nearest Suspense tells whose
14
- * it is. Only development has the stack; production reports nothing here,
15
- * and the build's own note or warning on the route is the record.
12
+ * and the engine renders the boundary a loading.tsx becomes through a
13
+ * component named for it, so the frame just outside the nearest Suspense
14
+ * is LoadingBoundary exactly when the boundary is the engine's. Only that
15
+ * frame, and only that name: the check used to accept SegmentBoundary two
16
+ * frames out, which held for a first render and misfired on a PPR resume,
17
+ * where React leaves server components out of the stack and a developer's
18
+ * own <Suspense> at the top of a page sat directly under the segment
19
+ * boundary - a warning on every request that nothing could make go away.
16
20
  */
17
- const ENGINE_BOUNDARY = /^\s*at (SegmentBoundary|SlotBoundary)\b/;
21
+ const ENGINE_BOUNDARY = /^\s*at LoadingBoundary\b/;
18
22
  export function caughtByLoading(componentStack) {
19
23
  const frames = (componentStack ?? "")
20
24
  .split("\n")
@@ -22,9 +26,7 @@ export function caughtByLoading(componentStack) {
22
26
  const at = frames.findIndex((line) => /^\s*at Suspense\b/.test(line));
23
27
  if (at === -1)
24
28
  return false;
25
- return frames
26
- .slice(at + 1, at + 3)
27
- .some((line) => ENGINE_BOUNDARY.test(line));
29
+ return ENGINE_BOUNDARY.test(frames[at + 1] ?? "");
28
30
  }
29
31
  /**
30
32
  * Whether a render error is the consumer cancelling, not the app failing.