/** * `@nifrajs/web/forms` - a typed form ↔ backend-schema binding. The three artifacts that must agree - * a form's ``, the action's `formData.get`, and the typed-client payload - all key off the * ONE route body schema, derived purely from `typeof backend`. A typo'd field name, or a field the * schema doesn't have, becomes a COMPILE error instead of a silent runtime empty. * * import type { backend } from "../backend" * import { formFor } from "@nifrajs/web/forms" * * const f = formFor() // method defaults to "post" * // In the component (any framework - spread the props onto an input): * // "text" ∈ the body's keys, else a compile error * // In the action: * const text = f.read(await request.formData(), "text") // an orphan key won't compile * await api.todos.post({ text }) // payload already typed by nifra * * Framework-agnostic + dependency-free: no codegen, no schema is bundled into the client, and the * runtime is a trivial pass-through - all the work is in the types. It checks the field KEY, never the * MEANING (a `field("email")` collecting a phone is still valid here); that stays an app/AI concern. */ import type { RouteInfo, Server } from "@nifrajs/core/server"; type FormEntry = ReturnType; type FormEntries = ReturnType; /** The route registry baked into a server's type (`typeof app`). */ type RegistryOf = App extends Server ? R : never; /** Every route path the app declares - constrains `Path`, so a wrong path is itself a type error. */ export type RoutePaths = keyof RegistryOf & string; /** The body object type of `App`'s `Method Path` route (`never` when the route declares no body). */ export type RouteBody = Path extends keyof RegistryOf ? Uppercase extends keyof RegistryOf[Path] ? (RegistryOf[Path][Uppercase] & RouteInfo)["body"] : never : never; /** The valid field names for that route's body - the schema's keys as a string union. */ export type FieldKey = [ RouteBody ] extends [never] ? never : keyof RouteBody & string; /** Extra attributes merged into the returned input props (id, type, defaultValue, placeholder, …). */ export type FieldProps = Record; export interface FormHandle { /** Input props for a schema field. `name` is constrained to the body's keys - a typo, or a field the * schema doesn't have, is a COMPILE error. Spread onto an element: ``. */ field>(name: K, props?: FieldProps): FieldProps & { name: K; }; /** `formData.get`, key-constrained to the body's fields - reading an orphan key won't compile. */ read>(form: FormData, name: K): FormEntry; /** `formData.getAll`, key-checked the same way. */ readAll>(form: FormData, name: K): FormEntries; } /** * Bind a form to a backend route's body schema at the type level. `App` is `typeof backend`; `Path` is * constrained to the app's real routes (a wrong path is a type error); `Method` defaults to `"post"`. */ export declare function formFor, Method extends string = "post">(): FormHandle; export {}; //# sourceMappingURL=forms.d.ts.map