@thomasfosterau/effect-forms 0.0.0 → 0.2.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.
- package/README.md +19 -23
- package/dist/index.d.ts +34 -13
- package/dist/index.js +56 -33
- package/dist/index.js.map +1 -1
- package/package.json +6 -6
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["replaceAt","make","make","makeFormState"],"sources":["../src/Coerce.ts","../src/Command.ts","../src/Constraints.ts","../src/FormData.ts","../src/Path.ts","../src/Errors.ts","../src/Field.ts","../src/Issues.ts","../src/FormBuilder.ts","../src/State.ts","../src/Form.ts","../src/Mode.ts","../src/Result.ts","../src/Validate.ts"],"sourcesContent":["/**\n * @copyright Thomas Foster\n *\n * Tri-state coercers for the HTML-form boundary.\n *\n * An HTML form submits every value as a string, and an absent optional field\n * arrives as `undefined` (or an empty string). Mapping that onto a\n * value / `null` / `undefined` update contract — where a value **sets**, `null`\n * **clears** a nullable field, and `undefined` **skips** (carry-forward) — is\n * the same boundary discipline the host app applies, lifted here so any\n * consumer of the core gets it without a framework dependency.\n *\n * These are plain, total functions: they never throw and never reach for a\n * framework's `error()` helper (validation failures belong on the schema, not\n * in a coercer).\n *\n * @module effect-forms/Coerce\n */\n\n/** Empty string / `undefined` → `undefined`; otherwise the value (skip semantics). */\nexport function emptyToUndefined<T>(value: T | \"\" | undefined): T | undefined {\n return value === \"\" || value === undefined ? undefined : value;\n}\n\n/**\n * `undefined` stays `undefined` (skip); empty string / `null` → `null`\n * (clear a nullable field); otherwise the value (set). The three-state coercer\n * for nullable update fields.\n */\nexport function emptyToNull<T>(value: T | \"\" | null | undefined): T | null | undefined {\n if (value === undefined) return undefined;\n if (value === \"\" || value === null) return null;\n return value;\n}\n\n/** Trim, then {@link emptyToUndefined}: whitespace-only collapses to `undefined` (skip). */\nexport function trimToUndefined(value: string | undefined): string | undefined {\n return emptyToUndefined(value?.trim());\n}\n\n/** Trim, then {@link emptyToNull}: whitespace-only / blank clears (`null`). */\nexport function trimToNull(value: string | undefined): string | null | undefined {\n return emptyToNull(value?.trim());\n}\n\n/**\n * Map a numeric text field onto the value / `null` / `undefined` contract.\n * Blank clears on the nullable path and skips otherwise; a present value\n * parses with `Number` (`NaN` for non-numeric input — validate downstream).\n */\nexport function numberFromField(\n raw: string | undefined,\n options: { nullable: false },\n): number | undefined;\nexport function numberFromField(\n raw: string | undefined,\n options: { nullable: true },\n): number | null | undefined;\nexport function numberFromField(\n raw: string | undefined,\n { nullable }: { nullable: boolean },\n): number | null | undefined {\n const coerced = nullable ? emptyToNull(raw) : emptyToUndefined(raw);\n return typeof coerced === \"string\" ? Number(coerced) : coerced;\n}\n\n/**\n * Interpret a checkbox field. An HTML checkbox submits its `value` (default\n * `\"on\"`) only when checked and omits the field entirely when unchecked, so a\n * present field is `true` and an absent one is `false`. The truthy strings\n * `\"on\"` / `\"true\"` / `\"1\"` / `\"yes\"` all read as `true`; an explicit\n * `\"false\"` / `\"0\"` / `\"off\"` / `\"no\"` reads as `false`.\n */\nexport function booleanFromCheckbox(raw: string | undefined): boolean {\n if (raw === undefined) return false;\n const normalised = raw.trim().toLowerCase();\n return !(\n normalised === \"\" ||\n normalised === \"false\" ||\n normalised === \"0\" ||\n normalised === \"off\" ||\n normalised === \"no\"\n );\n}\n","/**\n * @copyright Thomas Foster\n *\n * Command-struct introspection and form derivation.\n *\n * A host app's write surface is a pair of flat command `Schema.Struct`s per\n * entity — a create struct (required fields bare, the rest `optional`) and an\n * update struct (keyed by a required `id`, every field `optional`, clearable\n * fields `optional(NullOr(...))` carrying the value / `null` / `undefined`\n * tri-state). This module reads that pair into a plain-data {@link CommandPlan}\n * and derives the three per-entity form artefacts that were previously\n * hand-written per entity: the all-string Form-Input schema fields, the blank\n * defaults, and the tri-state adapters that map a validated multipart input\n * onto the encoded command payload.\n *\n * Classification leads with behavioural decode probes — date codecs are\n * transformations and branded ids erase to `String`, so \"what does this\n * schema accept\" is the only robust signal for those (the same approach the\n * host app's model walkers use). Two kinds fall back to AST matching instead,\n * because no decode probe can name what they are: `enum`'s literal option set\n * (needed anyway for the renderer, not just the classification) and\n * `structured`'s \"this is a nested object, not a scalar\" shape. Neither\n * shadows a probe-classified kind — see {@link classify}.\n *\n * The derived adapters emit the **encoded** command payload (dates stay\n * `YYYY-MM-DD` strings, ids stay plain strings) — the command's canonical\n * decode downstream owns branding and validation. Genuinely irregular fields\n * (a create-time default, an asymmetric coercion) stay expressible via the\n * per-field {@link AdaptOverrides} escape hatch instead of forcing ejection.\n *\n * @module effect-forms/Command\n */\n\nimport * as Schema from \"effect/Schema\";\nimport * as SchemaAST from \"effect/SchemaAST\";\nimport {\n emptyToNull,\n emptyToUndefined,\n numberFromField,\n trimToNull,\n trimToUndefined,\n} from \"./Coerce.ts\";\n\n/** How a command field renders and coerces at the form boundary. */\nexport type FieldKind =\n | \"text\"\n | \"id\"\n | \"number\"\n | \"date\"\n | \"jsonArray\"\n | \"boolean\"\n | \"enum\"\n | \"structured\";\n\n/** One command field's derived plan, as plain data. */\nexport interface FieldPlan {\n readonly key: string;\n readonly kind: FieldKind;\n /** Present on the create struct. */\n readonly inCreate: boolean;\n /** Bare (non-optional) on the create struct. */\n readonly createRequired: boolean;\n /** Present on the update struct. */\n readonly inUpdate: boolean;\n /** `optional(NullOr(...))` on the update struct — blank clears (`null`). */\n readonly updateClearable: boolean;\n /**\n * The field's literal option values, read off the AST — present only when\n * `kind` is `\"enum\"`. In declaration order, stringified (a `<select>`'s\n * option values are always strings at the form boundary, whatever the\n * decoded literal's own type).\n */\n readonly options?: readonly string[];\n}\n\n/** The derived plan for one entity's create/update command pair. */\nexport interface CommandPlan {\n /** Every field except `id`, in update-struct declaration order (create-only fields appended). */\n readonly fields: readonly FieldPlan[];\n /** The create struct carries an optional client-generated `id` (idempotent retries). */\n readonly clientId: boolean;\n}\n\n/** Per-field adapter overrides — the escape hatch for genuinely irregular coercion. */\nexport type AdaptOverrides = Readonly<Record<string, (raw: string | undefined) => unknown>>;\n\n/** A validated all-string multipart input, as the Form-Input schemas produce it. */\nexport type FormInputRecord = Readonly<Record<string, string | undefined>>;\n\n// ── probes ────────────────────────────────────────────────────────────\n\n/**\n * Run one decode probe: whether the schema accepts the input, plus the decoded\n * value for instance checks (the date probe needs to see a `Date` come out,\n * not just a successful decode).\n */\nconst probe = (\n schema: Schema.Top,\n input: unknown,\n): { readonly ok: boolean; readonly value?: unknown } => {\n try {\n return { ok: true, value: Schema.decodeUnknownSync(schema as Schema.Codec<unknown>)(input) };\n } catch {\n return { ok: false };\n }\n};\n\n/** True when a schema decodes the given input without throwing. */\nconst decodes = (schema: Schema.Top, input: unknown): boolean => probe(schema, input).ok;\n\n/** A syntactically valid UUID no other field kind accepts as non-text. */\nconst PROBE_UUID = \"9f8c1c2e-4b3a-4c5d-8e6f-0a1b2c3d4e5f\";\n\n/**\n * Peel exactly the `optional` / `NullOr` wrapper layers off a property's type\n * AST, stopping at the first union that isn't itself a pure wrapper. A wrapper\n * union carries exactly one non-`null`/`undefined` member (the wrapped type);\n * a union with zero or several such members is a real value-level union (an\n * `enum` field's own literal set, say) rather than another layer to peel, so\n * the loop stops there. Unlike {@link module:effect-forms/Constraints}'s\n * `unwrapOptional` (which only ever needs the *first* real member), this\n * walks every wrapper layer and preserves a multi-member union intact —\n * `enumOptions` below needs the full literal set, not just one branch of it.\n */\nfunction unwrapWrapperUnion(ast: SchemaAST.AST): SchemaAST.AST {\n let current = ast;\n while (SchemaAST.isUnion(current)) {\n const real = current.types.filter((t) => !SchemaAST.isUndefined(t) && !SchemaAST.isNull(t));\n if (real.length !== 1 || real.length === current.types.length) break;\n current = real[0];\n }\n return current;\n}\n\n/**\n * The literal option values of a field shaped like `Schema.Literal(...)` or\n * `Schema.Literals([...])` (optionally `optional` / `NullOr`-wrapped) —\n * `undefined` when the field isn't literal-shaped. Stringified: a `<select>`'s\n * option values are strings at the form boundary regardless of the literal's\n * own type.\n */\nfunction enumOptions(ast: SchemaAST.AST): readonly string[] | undefined {\n const inner = unwrapWrapperUnion(ast);\n if (SchemaAST.isLiteral(inner)) return [String(inner.literal)];\n if (SchemaAST.isUnion(inner)) {\n const literals = inner.types.filter(SchemaAST.isLiteral);\n if (literals.length === inner.types.length && literals.length > 0) {\n return literals.map((literal) => String(literal.literal));\n }\n }\n return undefined;\n}\n\n/**\n * Whether a field is itself an object/struct schema (optionally `optional` /\n * `NullOr`-wrapped) — the `structured` kind's shape (inline / block ProseKit\n * JSON: `{ type, content }`). Mirrors {@link module:effect-forms/Field}'s and\n * {@link module:effect-forms/Constraints}'s own `SchemaAST.isObjects` struct\n * check. A `Schema.declare`d type (`UploadedDocument`, `Image`) has no\n * `Objects` AST node, so it is never caught here — the default-throw the\n * derivation relies on stays intact.\n */\nfunction isStructured(ast: SchemaAST.AST): boolean {\n return SchemaAST.isObjects(unwrapWrapperUnion(ast));\n}\n\n/** One field's classification: its {@link FieldKind}, plus `options` for `\"enum\"`. */\ninterface Classification {\n readonly kind: FieldKind;\n readonly options?: readonly string[];\n}\n\n/**\n * The scalar kinds classified purely by what a schema decodes, with no AST\n * inspection: array → boolean → number → date → id → text. `undefined` when\n * the schema accepts none of them, so {@link classify} can fall through to\n * its AST-based checks (`enum`, `structured`).\n */\nconst probeKind = (schema: Schema.Top): FieldKind | undefined => {\n if (decodes(schema, [])) return \"jsonArray\";\n if (decodes(schema, true)) return \"boolean\";\n if (decodes(schema, 42)) return \"number\";\n const date = probe(schema, \"2024-01-02T03:04:05.000Z\");\n if (date.ok && date.value instanceof Date) return \"date\";\n if (decodes(schema, PROBE_UUID) && !decodes(schema, \"not-a-uuid\")) return \"id\";\n if (decodes(schema, \"plain text\")) return \"text\";\n return undefined;\n};\n\n/**\n * Classify one field schema: by its AST shape first, then by what it accepts.\n * `enum` is checked before {@link probeKind} rather than after, since a\n * decode probe can't tell \"the literal set an enum accepts\" from any other\n * shape (worse, a numeric-literal enum whose set happens to include the `42`\n * probe value would otherwise misclassify as `number`) — reading the literal\n * set off the AST is unambiguous, and it's needed anyway for the renderer.\n * `structured` is checked last, after every probe has failed: an object\n * schema never decodes any of `probeKind`'s scalar probes, so there is no\n * real ordering hazard, but putting the broadest, AST-only check last keeps\n * every more specific kind first in line. A field that matches nothing\n * (`Schema.declare`d — `UploadedDocument`, `Image`) throws at module load so\n * the gap surfaces when the plan is declared, not on a live submission.\n */\nconst classify = (key: string, schema: Schema.Top): Classification => {\n const options = enumOptions(schema.ast);\n if (options !== undefined) return { kind: \"enum\", options };\n const probed = probeKind(schema);\n if (probed !== undefined) return { kind: probed };\n if (isStructured(schema.ast)) return { kind: \"structured\" };\n throw new Error(\n `Command.plan: field \"${key}\" matches no known kind (text/id/number/date/jsonArray/boolean/enum/structured) — a Schema.declare'd type needs an explicit form-level treatment before it can derive`,\n );\n};\n\n// ── plan ──────────────────────────────────────────────────────────────\n\n/** Minimal runtime shape of a command `Schema.Struct`. */\ninterface StructLike {\n readonly fields: Record<string, Schema.Top>;\n}\n\n/**\n * Read a create/update command struct pair into a {@link CommandPlan}.\n * Runs once at module load — probe cost is a handful of tiny decodes per\n * field, never per render or per request.\n */\nexport const plan = (create: StructLike, update: StructLike): CommandPlan => {\n const createFields = create.fields;\n const updateFields = update.fields;\n const keys: string[] = [];\n for (const key in updateFields) if (key !== \"id\") keys.push(key);\n for (const key in createFields) if (key !== \"id\" && !(key in updateFields)) keys.push(key);\n\n const fields = keys.map((key): FieldPlan => {\n const createField = createFields[key];\n const updateField = updateFields[key];\n const probeTarget = (createField ?? updateField) as Schema.Top;\n const { kind, options } = classify(key, probeTarget);\n return {\n key,\n kind,\n inCreate: createField !== undefined,\n createRequired: createField !== undefined && !decodes(createField, undefined),\n inUpdate: updateField !== undefined,\n updateClearable: updateField !== undefined && decodes(updateField, null),\n ...(options !== undefined ? { options } : {}),\n };\n });\n\n return { fields, clientId: \"id\" in createFields };\n};\n\n// ── Form-Input schema fields ──────────────────────────────────────────\n\n/**\n * Derive the all-string Form-Input schema fields for one mode — every value is\n * a string at the multipart boundary. Create-required fields get a min-length\n * check so blankness surfaces as an inline field error; the update `id` gets\n * the UUID check. Spread into `Schema.Struct({ ...Command.formInputFields(plan,\n * \"create\") })`, with `overrides` spread last for irregular fields.\n */\nexport const formInputFields = (\n commandPlan: CommandPlan,\n mode: \"create\" | \"update\",\n overrides: Readonly<Record<string, Schema.Top>> = {},\n): Record<string, Schema.Top> => {\n const fields: Record<string, Schema.Top> = {};\n if (mode === \"create\" && commandPlan.clientId) fields.id = Schema.optional(Schema.String);\n if (mode === \"update\") fields.id = Schema.String.check(Schema.isUUID());\n for (const field of commandPlan.fields) {\n if (mode === \"create\" ? !field.inCreate : !field.inUpdate) continue;\n fields[field.key] =\n mode === \"create\" && field.createRequired\n ? Schema.String.check(Schema.isMinLength(1))\n : Schema.optional(Schema.String);\n }\n return { ...fields, ...overrides };\n};\n\n/**\n * Blank string defaults for one mode's Form-Input shape. Client-id entities\n * override `id` at the call site (`{ ...blankDefaults(plan, \"create\"), id:\n * crypto.randomUUID() }`) so retries stay idempotent.\n */\nexport const blankDefaults = (\n commandPlan: CommandPlan,\n mode: \"create\" | \"update\",\n): Record<string, string> => {\n const defaults: Record<string, string> = {};\n if (mode === \"update\" || commandPlan.clientId) defaults.id = \"\";\n for (const field of commandPlan.fields) {\n if (mode === \"create\" ? !field.inCreate : !field.inUpdate) continue;\n defaults[field.key] = \"\";\n }\n return defaults;\n};\n\n// ── adapters ──────────────────────────────────────────────────────────\n\n/**\n * Parse a JSON-encoded row list (a contributor list) from a multipart form\n * field. A blank or absent field yields `undefined` (skip — leave the existing\n * list untouched); an empty JSON array (`\"[]\"`) clears the list. Rows keep\n * `id` / `creditedName` when present; `orderingPosition` falls back to the\n * row's array index. Throws a plain `Error` on a malformed payload — mapping\n * that onto a framework response is the caller's concern.\n */\nexport const jsonRowsFromField = (\n raw: string | undefined,\n label: string,\n):\n | {\n id?: string | undefined;\n agentId: string;\n creditedName?: string | undefined;\n orderingPosition: number;\n }[]\n | undefined => {\n if (raw === undefined || raw.trim() === \"\") return undefined;\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n throw new Error(`Invalid ${label} payload — expected JSON array`);\n }\n if (!Array.isArray(parsed)) {\n throw new Error(`Invalid ${label} payload — expected array`);\n }\n return parsed.map((row, index) => {\n if (typeof row !== \"object\" || row === null) {\n throw new Error(`Invalid ${label} entry at index ${index}`);\n }\n const r = row as Record<string, unknown>;\n if (typeof r.agentId !== \"string\") {\n throw new Error(`${label} entry at index ${index} missing agentId`);\n }\n return {\n id: typeof r.id === \"string\" ? r.id : undefined,\n agentId: r.agentId,\n creditedName: typeof r.creditedName === \"string\" ? r.creditedName : undefined,\n orderingPosition: typeof r.orderingPosition === \"number\" ? r.orderingPosition : index,\n };\n });\n};\n\n/** Coercion context for one field in one mode. */\ninterface CoerceContext {\n /** Required at create: emit the raw value's canonical form, never skip. */\n readonly required: boolean;\n /** Blank clears (`null`) rather than skips (`undefined`). */\n readonly clearable: boolean;\n /** Trim before the create-mode blank check (dates trim only at create). */\n readonly trimCreate: boolean;\n}\n\n/** Text fields: trim always; required create fields never skip. */\nconst coerceText = (ctx: CoerceContext, raw: string | undefined): unknown =>\n ctx.required ? (raw ?? \"\").trim() : ctx.clearable ? trimToNull(raw) : trimToUndefined(raw);\n\n/** Id fields: no trimming (pickers emit `\"\"` or a UUID); required create FKs pass through raw. */\nconst coerceId = (ctx: CoerceContext, raw: string | undefined): unknown =>\n ctx.required ? raw : ctx.clearable ? emptyToNull(raw) : emptyToUndefined(raw);\n\n/** Numeric text fields: blank clears on the clearable path, skips otherwise. */\nconst coerceNumber = (ctx: CoerceContext, raw: string | undefined): unknown =>\n ctx.clearable\n ? numberFromField(raw, { nullable: true })\n : numberFromField(raw, { nullable: false });\n\n/** Date fields stay encoded (`YYYY-MM-DD` strings); create trims, update passes through. */\nconst coerceDate = (ctx: CoerceContext, raw: string | undefined): unknown => {\n const value = ctx.trimCreate ? raw?.trim() : raw;\n return ctx.clearable ? emptyToNull(value) : emptyToUndefined(value);\n};\n\n/**\n * Boolean fields: a `<select>`'s value set, not a checkbox — the only truthy\n * raw value is the literal string `\"true\"`, everything else (`\"false\"`,\n * blank, absent) reads as `false`. Create defaults an absent/blank field to\n * `false` (never skips); update skips absent/blank unless clearable, in which\n * case it clears (`null`) instead — the create-defaults / update-skips\n * asymmetry the Content family already hand-writes.\n */\nconst coerceBoolean = (ctx: CoerceContext, raw: string | undefined): unknown => {\n const trimmed = raw?.trim();\n if (trimmed === undefined || trimmed === \"\") {\n return ctx.required ? false : ctx.clearable ? null : undefined;\n }\n return trimmed === \"true\";\n};\n\n/**\n * Parse a JSON-encoded structured document (inline / block ProseKit JSON)\n * from a multipart field. Blank or absent skips (`undefined`) or, on the\n * clearable path, clears (`null`); a present value is `JSON.parse`d and\n * passed through as-is — shape validation is the command's own decode's job,\n * exactly as {@link jsonRowsFromField} leaves row-shape validation to itself\n * rather than duplicating it here. `JSON.parse` throws a `SyntaxError` on\n * malformed JSON, same as {@link jsonRowsFromField} does on a malformed row\n * list — mapping that onto a framework response is the caller's concern.\n */\nconst structuredFromField = (raw: string | undefined, clearable: boolean): unknown => {\n const trimmed = raw?.trim();\n if (trimmed === undefined || trimmed === \"\") return clearable ? null : undefined;\n return JSON.parse(trimmed);\n};\n\n/** Build one field's {@link CoerceContext} for one mode. */\nconst coerceContextFor = (field: FieldPlan, mode: \"create\" | \"update\"): CoerceContext => ({\n required: mode === \"create\" && field.createRequired,\n clearable: mode === \"update\" && field.updateClearable,\n trimCreate: mode === \"create\",\n});\n\n/** The default coercion for one field in one mode. */\nconst coerce = (field: FieldPlan, mode: \"create\" | \"update\", raw: string | undefined): unknown => {\n const ctx = coerceContextFor(field, mode);\n switch (field.kind) {\n case \"text\":\n case \"enum\":\n return coerceText(ctx, raw);\n case \"id\":\n return coerceId(ctx, raw);\n case \"number\":\n return coerceNumber(ctx, raw);\n case \"date\":\n return coerceDate(ctx, raw);\n case \"jsonArray\":\n return jsonRowsFromField(raw, field.key);\n case \"boolean\":\n return coerceBoolean(ctx, raw);\n case \"structured\":\n return structuredFromField(raw, ctx.clearable);\n }\n};\n\n/**\n * Derive the create adapter: validated all-string input → encoded create\n * command payload. `overrides` replace the default per-field coercion for\n * genuinely irregular fields (e.g. a create-time fallback default).\n */\nexport const createAdapter =\n (commandPlan: CommandPlan, overrides: AdaptOverrides = {}) =>\n (input: FormInputRecord): Record<string, unknown> => {\n const out: Record<string, unknown> = {};\n if (commandPlan.clientId) out.id = trimToUndefined(input.id);\n for (const field of commandPlan.fields) {\n if (!field.inCreate) continue;\n const override = overrides[field.key];\n out[field.key] = override\n ? override(input[field.key])\n : coerce(field, \"create\", input[field.key]);\n }\n return out;\n };\n\n/**\n * Derive the update adapter: validated all-string input → encoded update\n * command payload (value sets, `null` clears a clearable field, `undefined`\n * skips). The required `id` passes through as-is — the command's canonical\n * decode brands it.\n */\nexport const updateAdapter =\n (commandPlan: CommandPlan, overrides: AdaptOverrides = {}) =>\n (input: FormInputRecord): Record<string, unknown> => {\n const out: Record<string, unknown> = { id: input.id };\n for (const field of commandPlan.fields) {\n if (!field.inUpdate) continue;\n const override = overrides[field.key];\n out[field.key] = override\n ? override(input[field.key])\n : coerce(field, \"update\", input[field.key]);\n }\n return out;\n };\n","/**\n * @copyright Thomas Foster\n *\n * HTML input constraints derived from an Effect Schema.\n *\n * Native validation attributes can be read (`required`, `minlength`, …)\n * off the schema so a form can apply them to its inputs for free, layering\n * browser-native validation under the schema-driven validation. This module\n * does the framework-neutral half: walk the schema AST and emit an\n * {@link InputConstraints} tree a UI can spread onto its `<input>`s.\n *\n * `required` comes from a struct field's optionality; `minlength` /\n * `maxlength` / `min` / `max` / `pattern` / `step` are derived from the\n * `representation` annotation Effect Schema's built-in checks carry\n * (`isMinLength`, `isBetween`, `isPattern`, …), keyed by its stable\n * `effect/schema/<check>` id. A check with no recognised representation id\n * (a bare `Schema.filter` predicate, a custom `.check()`) contributes\n * nothing; there is no attribute to guess at,\n * so the derivation stays silent rather than wrong. The walk descends into\n * nested structs and into a homogeneous array's item type (folding the\n * array's own optionality into the item's `required`); a fixed-shape tuple\n * with differently-typed elements has no single item schema to represent as\n * one constraint, so it derives only `required`. Like\n * {@link module:effect-forms/Field}'s `fromAst`, an `optional` / `NullOr`\n * union is unwrapped by taking its first non-`null`/`undefined` member —\n * scoped to that wrapping pattern, not general discriminated unions, whose\n * branches can't be flattened into one constraint either. The `overrides`\n * argument to {@link constraintsFromSchema} remains the seam for anything the\n * walk cannot infer (or should not — a check that's semantically stronger\n * than any HTML attribute).\n *\n * @module effect-forms/Constraints\n */\n\nimport type * as Schema from \"effect/Schema\";\nimport * as SchemaAST from \"effect/SchemaAST\";\nimport type * as SchemaRepresentation from \"effect/SchemaRepresentation\";\nimport type { FormPath } from \"./Issues.ts\";\n\n/** Native validation attributes for a single input. */\nexport interface InputConstraint {\n readonly required?: boolean;\n readonly min?: number | string;\n readonly max?: number | string;\n readonly minlength?: number;\n readonly maxlength?: number;\n readonly pattern?: string;\n readonly step?: number;\n}\n\n/** A nested tree of {@link InputConstraint}s mirroring the schema's shape. */\nexport interface InputConstraints {\n readonly [key: string]: InputConstraint | InputConstraints | undefined;\n}\n\n/** Whether a node in an {@link InputConstraints} tree is a leaf ({@link InputConstraint}) rather than a branch. */\nexport const isLeafConstraint = (\n value: InputConstraint | InputConstraints,\n): value is InputConstraint =>\n \"required\" in value ||\n \"min\" in value ||\n \"max\" in value ||\n \"minlength\" in value ||\n \"maxlength\" in value ||\n \"pattern\" in value ||\n \"step\" in value;\n\n/** Whether a property's type AST is optional (so the field is not required). */\nconst isOptional = (type: SchemaAST.AST): boolean => type.context?.isOptional === true;\n\n/**\n * Unwrap an `optional` / `NullOr` union the way {@link module:effect-forms/Field}'s\n * `fromAst` does: recurse into the first member that isn't a bare `undefined`\n * / `null` literal, so a wrapped struct / array / refined leaf still yields\n * its own shape instead of falling through to an empty constraint.\n */\nfunction unwrapOptional(type: SchemaAST.AST): SchemaAST.AST {\n if (!SchemaAST.isUnion(type)) return type;\n for (const member of type.types) {\n if (SchemaAST.isUndefined(member) || SchemaAST.isNull(member)) continue;\n return unwrapOptional(member);\n }\n return type;\n}\n\n/** Flatten a `Checks` array (recursing into `FilterGroup`s) into individual filters. */\nfunction flattenChecks(\n checks: SchemaAST.Checks | undefined,\n out: Array<SchemaAST.Filter<unknown>>,\n): void {\n if (!checks) return;\n for (const check of checks) {\n if (check._tag === \"FilterGroup\") {\n flattenChecks(check.checks as SchemaAST.Checks, out);\n } else {\n out.push(check as SchemaAST.Filter<unknown>);\n }\n }\n}\n\n/** A same-shape, mutable patch of {@link InputConstraint} fields. */\ntype ConstraintPatch = { -readonly [K in keyof InputConstraint]?: InputConstraint[K] };\n\n/**\n * The `representation.payload` shapes of the built-in checks that map onto a\n * native HTML attribute, keyed by the check's stable representation id.\n * Mirrors each check constructor in `effect/Schema` (e.g. `isMinLength`\n * writes `{ id: \"effect/schema/isMinLength\", payload: { minLength } }`).\n */\ninterface CheckPayloads {\n readonly \"effect/schema/isMinLength\": { readonly minLength: number };\n readonly \"effect/schema/isMaxLength\": { readonly maxLength: number };\n readonly \"effect/schema/isLengthBetween\": { readonly minimum: number; readonly maximum: number };\n readonly \"effect/schema/isPattern\": { readonly source: string; readonly flags: string };\n readonly \"effect/schema/isGreaterThan\": { readonly exclusiveMinimum: number };\n readonly \"effect/schema/isGreaterThanOrEqualTo\": { readonly minimum: number };\n readonly \"effect/schema/isLessThan\": { readonly exclusiveMaximum: number };\n readonly \"effect/schema/isLessThanOrEqualTo\": { readonly maximum: number };\n readonly \"effect/schema/isBetween\": { readonly minimum: number; readonly maximum: number };\n readonly \"effect/schema/isMultipleOf\": { readonly divisor: number };\n}\n\n/**\n * One constraint patch per recognised representation id — the built-in\n * checks that map onto a native HTML attribute. An id with no entry here\n * (an unannotated custom filter, or a built-in check with no HTML\n * equivalent) derives nothing. `isInt` isn't a plain patch: it only sets\n * `step` as a fallback when nothing more specific already did, so it's\n * handled separately in {@link constraintFromChecks}.\n */\nconst payloadPatches: {\n readonly [K in keyof CheckPayloads]: (payload: CheckPayloads[K]) => ConstraintPatch;\n} = {\n \"effect/schema/isMinLength\": (p) => ({ minlength: p.minLength }),\n \"effect/schema/isMaxLength\": (p) => ({ maxlength: p.maxLength }),\n \"effect/schema/isLengthBetween\": (p) => ({ minlength: p.minimum, maxlength: p.maximum }),\n \"effect/schema/isPattern\": (p) => ({ pattern: p.source }),\n \"effect/schema/isGreaterThan\": (p) => ({ min: p.exclusiveMinimum }),\n \"effect/schema/isGreaterThanOrEqualTo\": (p) => ({ min: p.minimum }),\n \"effect/schema/isLessThan\": (p) => ({ max: p.exclusiveMaximum }),\n \"effect/schema/isLessThanOrEqualTo\": (p) => ({ max: p.maximum }),\n \"effect/schema/isBetween\": (p) => ({ min: p.minimum, max: p.maximum }),\n \"effect/schema/isMultipleOf\": (p) => ({ step: p.divisor }),\n};\n\n/**\n * Look up and apply `payloadPatches[representation.id]`. The cast is sound:\n * each payload is authored by the same built-in check constructor its id\n * names, so an entry is never called with a mismatched payload shape.\n */\nfunction applyPayloadPatch(\n representation: SchemaRepresentation.RepresentationAnnotation,\n): ConstraintPatch | undefined {\n const patch = payloadPatches[representation.id as keyof CheckPayloads] as\n | ((payload: Schema.Json) => ConstraintPatch)\n | undefined;\n return patch?.(representation.payload);\n}\n\n/**\n * Derive an {@link InputConstraint}'s refinement attributes from the checks\n * attached to `outer` (the property's own type, e.g. the union wrapping an\n * optional field) and `inner` (the unwrapped leaf) — `inner`'s checks win on\n * conflict since they're the more specific, unwrapped node. A check whose\n * `representation` annotation has no recognised id (an unannotated custom\n * filter) is skipped: there is no attribute to derive from it.\n */\nfunction constraintFromChecks(outer: SchemaAST.AST, inner: SchemaAST.AST): InputConstraint {\n const filters: Array<SchemaAST.Filter<unknown>> = [];\n flattenChecks(outer.checks, filters);\n if (inner !== outer) flattenChecks(inner.checks, filters);\n\n let out: ConstraintPatch = {};\n let hasIntCheck = false;\n for (const filter of filters) {\n const representation = filter.annotations?.representation;\n if (!representation) continue;\n if (representation.id === \"effect/schema/isInt\") {\n hasIntCheck = true;\n continue;\n }\n out = { ...out, ...applyPayloadPatch(representation) };\n }\n if (hasIntCheck && out.step === undefined) out.step = 1;\n\n return out;\n}\n\n/**\n * Whether `ast` is a homogeneous array/list — `Schema.Array(item)` or\n * `Schema.NonEmptyArray(item)` — as opposed to a fixed-shape tuple with\n * differently-typed positional elements. Only a homogeneous array has a\n * single item schema to descend into; a tuple's elements each need their own\n * constraint, which this leaf-per-key tree can't represent, so it's left to\n * `overrides`.\n */\nfunction homogeneousItem(ast: SchemaAST.Arrays): SchemaAST.AST | undefined {\n if (ast.rest.length !== 1) return undefined;\n const [item] = ast.rest;\n if (ast.elements.length === 0) return item;\n if (ast.elements.length === 1 && ast.elements[0] === item) return item;\n return undefined;\n}\n\n/**\n * Derive the constraint (or nested tree) for one property/item type: a\n * struct descends into its properties, a homogeneous array descends into its\n * item type (the array's own length checks have no native equivalent for a\n * repeated field, so they're not derived) while folding the array's own\n * optionality into the item's `required`, and anything else is a leaf whose\n * `required` comes from optionality and whose refinement attributes come\n * from {@link constraintFromChecks}.\n */\nfunction constraintsForType(type: SchemaAST.AST): InputConstraint | InputConstraints {\n const required = !isOptional(type);\n const inner = unwrapOptional(type);\n if (SchemaAST.isObjects(inner)) {\n return constraintsForObjects(inner);\n }\n if (SchemaAST.isArrays(inner)) {\n const item = homogeneousItem(inner);\n if (!item) return { required };\n const itemConstraints = constraintsForType(item);\n return isLeafConstraint(itemConstraints)\n ? { ...itemConstraints, required: required && itemConstraints.required !== false }\n : itemConstraints;\n }\n return { required, ...constraintFromChecks(type, inner) };\n}\n\n/** Build the constraint tree for one object AST node. */\nfunction constraintsForObjects(ast: SchemaAST.Objects): InputConstraints {\n const out: Record<string, InputConstraint | InputConstraints> = {};\n for (const ps of ast.propertySignatures) {\n out[String(ps.name)] = constraintsForType(ps.type);\n }\n return out;\n}\n\n/** Deep-merge constraint overrides over a derived tree. */\nfunction mergeConstraints(base: InputConstraints, overrides: InputConstraints): InputConstraints {\n const out: Record<string, InputConstraint | InputConstraints | undefined> = { ...base };\n for (const key of Object.keys(overrides)) {\n const override = overrides[key];\n if (override === undefined) continue;\n const existing = out[key];\n if (existing !== undefined && !isLeafConstraint(existing) && !isLeafConstraint(override)) {\n out[key] = mergeConstraints(existing, override);\n } else if (existing !== undefined && isLeafConstraint(existing) && isLeafConstraint(override)) {\n out[key] = { ...existing, ...override };\n } else {\n out[key] = override;\n }\n }\n return out;\n}\n\n/**\n * Derive the {@link InputConstraints} for a struct schema. Non-struct schemas\n * yield an empty tree. `overrides` (deep-merged over the derived tree, and\n * winning on conflict) is the seam for anything the AST walk does not infer.\n */\nexport function constraintsFromSchema(\n schema: Schema.Top,\n overrides: InputConstraints = {},\n): InputConstraints {\n const ast = schema.ast;\n const base = SchemaAST.isObjects(ast) ? constraintsForObjects(ast) : {};\n return mergeConstraints(base, overrides);\n}\n\n/**\n * Read the {@link InputConstraint} leaf at `path` in an {@link InputConstraints}\n * tree, defaulting to `{}` when `path` has no derived constraints. Array\n * indices in `path` are skipped rather than descended into — the tree has no\n * per-item nodes to index into, since {@link constraintsForType} derives one\n * constraint (or branch) per *field*, shared by every item at that field. A\n * bare item path (`tags[0]`) resolves to that shared leaf; a path that\n * continues past the index into a struct item's own field (`items[0].label`)\n * skips the index and resolves straight to `label`'s derived constraint.\n */\nexport function constraintAt(constraints: InputConstraints, path: FormPath): InputConstraint {\n let node: InputConstraint | InputConstraints | undefined = constraints;\n for (const segment of path) {\n if (typeof segment === \"number\") continue;\n if (node === undefined || isLeafConstraint(node)) return {};\n node = node[segment];\n }\n return node !== undefined && isLeafConstraint(node) ? node : {};\n}\n","/**\n * @copyright Thomas Foster\n *\n * Structured parsing of an HTML form body into a plain object the schema can\n * decode.\n *\n * Browsers flatten structured data into `name=value` pairs using bracket /\n * dot path notation (`author.name`, `author[name]`, `tags[0]`, `tags[]`).\n * {@link formDataToObject} reverses that into a nested object / array tree —\n * the framework-neutral step that turns a form body into structured data, before handing it\n * to a validator. Coercion (strings → numbers / booleans / dates) is then the\n * schema's job: decode the result with a schema built from coercing leaves\n * (`Schema.FiniteFromString`, `Schema.BooleanFromString`, the {@link\n * module:effect-forms/Coerce} helpers, …).\n *\n * `File` values pass through untouched; repeated bare keys collapse into an\n * array. The parser is total and never throws.\n *\n * @module effect-forms/FormData\n */\n\n/** Anything that can be parsed into a structured form object. */\nexport type FormBodySource =\n | FormData\n | URLSearchParams\n | Iterable<readonly [string, FormDataEntryValue | string]>;\n\ntype Container = Record<string, unknown> | unknown[];\n\n/**\n * Split a flat field name into its path tokens. Supports dot notation\n * (`a.b`), bracket notation (`a[b]`, `a[0]`), and the trailing append form\n * (`a[]`, represented by an empty-string token). `\"a[b][0]\"` → `[\"a\",\"b\",\"0\"]`;\n * `\"a.b[]\"` → `[\"a\",\"b\",\"\"]`.\n */\nexport function parseFieldPath(name: string): string[] {\n const tokens: string[] = [];\n let buffer = \"\";\n let inBracket = false;\n for (const char of name) {\n if (char === \"[\") {\n if (buffer !== \"\") tokens.push(buffer);\n buffer = \"\";\n inBracket = true;\n } else if (char === \"]\") {\n tokens.push(buffer);\n buffer = \"\";\n inBracket = false;\n } else if (char === \".\" && !inBracket) {\n if (buffer !== \"\") tokens.push(buffer);\n buffer = \"\";\n } else {\n buffer += char;\n }\n }\n if (buffer !== \"\") tokens.push(buffer);\n // A leading empty token can appear for names like `[0]`; drop it.\n return tokens.length > 1 && tokens[0] === \"\" ? tokens.slice(1) : tokens;\n}\n\nconst isIndexToken = (token: string): boolean => token === \"\" || /^\\d+$/.test(token);\n\n/** Create the container a token should live in: array for index/append tokens. */\nconst makeContainer = (nextToken: string): Container => (isIndexToken(nextToken) ? [] : {});\n\nconst setOnContainer = (container: Container, token: string, value: unknown): void => {\n if (Array.isArray(container)) {\n if (token === \"\") container.push(value);\n else container[Number(token)] = value;\n } else {\n (container as Record<string, unknown>)[token] = value;\n }\n};\n\nconst getFromContainer = (container: Container, token: string): unknown =>\n Array.isArray(container)\n ? container[Number(token)]\n : (container as Record<string, unknown>)[token];\n\n/** Assign `value` deep into `root` along `tokens`, creating containers as needed. */\nfunction assign(root: Container, tokens: string[], value: unknown): void {\n let node: Container = root;\n for (let i = 0; i < tokens.length - 1; i++) {\n const token = tokens[i];\n const nextToken = tokens[i + 1];\n let child = token === \"\" ? undefined : getFromContainer(node, token);\n if (child === undefined || typeof child !== \"object\" || child === null) {\n child = makeContainer(nextToken);\n setOnContainer(node, token, child);\n }\n node = child as Container;\n }\n const last = tokens[tokens.length - 1];\n // A repeated bare key (no brackets) collapses into an array.\n if (last !== \"\" && !Array.isArray(node)) {\n const existing = getFromContainer(node, last);\n if (existing !== undefined) {\n const arr = Array.isArray(existing) ? existing : [existing];\n arr.push(value);\n setOnContainer(node, last, arr);\n return;\n }\n }\n setOnContainer(node, last, value);\n}\n\n/** Normalise a source into `[name, value]` entries. */\nfunction* entriesOf(source: FormBodySource): Generator<readonly [string, unknown]> {\n if (\n typeof (source as Iterable<unknown>)[Symbol.iterator] === \"function\" &&\n !(source instanceof FormData) &&\n !(source instanceof URLSearchParams)\n ) {\n yield* source as Iterable<readonly [string, unknown]>;\n return;\n }\n for (const entry of (source as FormData | URLSearchParams).entries()) yield entry;\n}\n\n/**\n * Parse a form body into a nested object / array tree. Field names use dot or\n * bracket path notation (see {@link parseFieldPath}); repeated bare keys\n * become arrays; `File` values pass through. The result is ready to hand to\n * `Schema.decodeUnknown` with a schema whose leaves coerce the string inputs.\n */\nexport function formDataToObject(source: FormBodySource): Record<string, unknown> {\n const root: Record<string, unknown> = {};\n for (const [name, value] of entriesOf(source)) {\n const tokens = parseFieldPath(name);\n if (tokens.length === 0) continue;\n assign(root, tokens, value);\n }\n return root;\n}\n\n/** Read and parse a `Request`'s form body. Errors (e.g. wrong content-type) reject. */\nexport async function requestToObject(request: Request): Promise<Record<string, unknown>> {\n const formData = await request.formData();\n return formDataToObject(formData);\n}\n","/**\n * @copyright Thomas Foster\n *\n * Nested get / set along a {@link FormPath}.\n *\n * A form's data is a tree, and the reactive bindings address it by path:\n * `[\"author\", \"name\"]`, `[\"tags\", 0]`. This module reads and writes a value\n * at such a path — {@link getAt} descends, {@link setAt} returns a new tree\n * with the value replaced (structural sharing, never a mutation) so a rune /\n * atom store can diff cheaply. It is the framework-neutral half of the\n * reactive field bindings (the Svelte store leans on it for\n * `setValue` and the array operations).\n *\n * Paths are {@link FormPath}s — the same array-of-segments the {@link\n * module:effect-forms/Errors} tree and {@link module:effect-forms/Issues}\n * walker already speak — so string keys address object properties and number\n * segments address array indices. {@link toString} / {@link fromString}\n * convert to and from the flat `author.name` / `tags[0]` notation the HTML\n * body parser ({@link module:effect-forms/FormData}) uses.\n *\n * @module effect-forms/Path\n */\n\nimport { parseFieldPath } from \"./FormData.ts\";\nimport type { FormPath } from \"./Issues.ts\";\n\n/**\n * Read the value at `path`. Returns `undefined` if any segment is missing or\n * traverses a non-object. The empty path returns the object itself.\n */\nexport function getAt(obj: unknown, path: FormPath): unknown {\n let current = obj;\n for (const segment of path) {\n if (current === null || typeof current !== \"object\") return undefined;\n current = (current as Record<string | number, unknown>)[segment];\n }\n return current;\n}\n\n/**\n * Return a new tree with the value at `path` replaced by `value`. Objects and\n * arrays along the path are cloned (structural sharing elsewhere); missing\n * containers are created as arrays for numeric segments and objects otherwise.\n * The empty path returns `value`. Pure — `obj` is never mutated.\n */\nexport function setAt<T>(obj: T, path: FormPath, value: unknown): T {\n if (path.length === 0) return value as T;\n\n const [head, ...rest] = path;\n const clone = (\n Array.isArray(obj) ? [...(obj as unknown[])] : { ...(obj as Record<string, unknown>) }\n ) as Record<string | number, unknown>;\n\n const child = clone[head];\n clone[head] =\n rest.length === 0\n ? value\n : setAt(\n child === null || typeof child !== \"object\"\n ? typeof rest[0] === \"number\"\n ? []\n : {}\n : child,\n rest,\n value,\n );\n\n return clone as T;\n}\n\n/** Whether `path` is `root` or nested beneath it. */\nexport function isUnder(path: FormPath, root: FormPath): boolean {\n if (path.length < root.length) return false;\n for (let i = 0; i < root.length; i++) {\n if (path[i] !== root[i]) return false;\n }\n return true;\n}\n\n/**\n * Render a {@link FormPath} as flat field-name notation: string segments join\n * with `.` and number segments become `[n]` (`[\"tags\", 0]` → `\"tags[0]\"`).\n * The inverse of {@link fromString}.\n */\nexport function toString(path: FormPath): string {\n let out = \"\";\n for (const segment of path) {\n if (typeof segment === \"number\") out += `[${segment}]`;\n else out += out === \"\" ? segment : `.${segment}`;\n }\n return out;\n}\n\n/**\n * Parse flat field-name notation into a {@link FormPath}: integer tokens become\n * number segments (array indices), everything else stays a string. The inverse\n * of {@link toString}.\n */\nexport function fromString(name: string): FormPath {\n return parseFieldPath(name).map((token) => (/^\\d+$/.test(token) ? Number(token) : token));\n}\n\n/**\n * The deep-key type: every valid {@link toString} path into `T`, as a union of\n * string literals (`\"author.name\"`, `\"tags[0]\"`, `\"tags[0].label\"`, …). This is\n * the type-checked counterpart of a hand-written {@link FormPath} — a typo'd\n * segment or a path into a field that doesn't exist is a compile error. Bounded\n * to a fixed recursion depth ({@link Prev}'s length) so a struct with cycles\n * (there shouldn't be any — form data is JSON-shaped) can't blow up inference.\n *\n * Used by {@link module:effect-forms-svelte/FormStore}'s `field(path)` — see\n * the trade-off recorded in `docs/decisions/` for why this was chosen over the\n * core's (now-removed) opaque `FieldRef`.\n */\nexport type FieldPath<T, D extends number = 8> = T extends object\n ? [D] extends [never]\n ? never\n : {\n [K in Extract<keyof T, string>]: `${K}${PathSuffix<T[K], Prev[D]>}`;\n }[Extract<keyof T, string>]\n : never;\n\n/** Recursion-depth countdown used by {@link FieldPath} / {@link PathValue}. */\ntype Prev = [never, 0, 1, 2, 3, 4, 5, 6, 7];\n\n/**\n * The continuation after a key: nothing, an array index (the bracket closes\n * immediately — `[0]`, not `[0.label]` — then {@link PathSuffix} recurses on\n * the element type for whatever comes after), or `.key`.\n */\ntype PathSuffix<T, D extends number> = [D] extends [never]\n ? \"\"\n : T extends ReadonlyArray<infer E>\n ? \"\" | `[${number}]${PathSuffix<E, Prev[D]>}`\n : T extends object\n ?\n | \"\"\n | { [K in Extract<keyof T, string>]: `.${K}${PathSuffix<T[K], Prev[D]>}` }[Extract<\n keyof T,\n string\n >]\n : \"\";\n\n/** The base key of a single dot-segment (`\"tags[0]\"` → `\"tags\"`). */\ntype SegmentBase<S extends string> = S extends `${infer Base}[${string}` ? Base : S;\n\n/** The bracket indices of a single dot-segment (`\"tags[0][1]\"` → `[\"0\", \"1\"]`), untyped past presence. */\ntype SegmentIndices<S extends string> = S extends `${string}[${infer Idx}]${infer Rest}`\n ? [Idx, ...SegmentIndicesRest<Rest>]\n : [];\n\n/** Continuation of {@link SegmentIndices} once the leading (non-bracket) prefix has been consumed. */\ntype SegmentIndicesRest<S extends string> = S extends `[${infer Idx}]${infer Rest}`\n ? [Idx, ...SegmentIndicesRest<Rest>]\n : [];\n\n/** Step through an array type once per entry in `Idxs`. */\ntype ApplyIndices<T, Idxs extends readonly unknown[]> = Idxs extends [unknown, ...infer Rest]\n ? T extends ReadonlyArray<infer E>\n ? ApplyIndices<E, Rest>\n : never\n : T;\n\n/** Resolve a single dot-segment (base key plus any bracket indices) against `T`. */\ntype ResolveSegment<T, S extends string> =\n SegmentBase<S> extends keyof T ? ApplyIndices<T[SegmentBase<S>], SegmentIndices<S>> : never;\n\n/**\n * The value type at a {@link FieldPath} `P` into `T` — the leaf type `field(path)`\n * resolves to. `PathValue<{ tags: string[] }, \"tags[0]\">` is `string`.\n */\nexport type PathValue<T, P extends string> = P extends `${infer Head}.${infer Rest}`\n ? PathValue<ResolveSegment<T, Head>, Rest>\n : ResolveSegment<T, P>;\n\n/**\n * Maps an array index that existed before an index-shifting mutation to where\n * it lives afterwards, or to `null` when the item at that index no longer\n * exists (its per-index state should be dropped). Built by {@link removeAt} /\n * {@link insertAt} / {@link swapAt} / {@link moveAt} / {@link replaceAt}, and\n * consumed by {@link remapIndex} / {@link remapKeyedRecord} and\n * `Errors.remapIndices` to keep per-index state (touched flags, error trees)\n * in sync with the row it was recorded against.\n */\nexport type IndexMap = (index: number) => number | null;\n\n/** The {@link IndexMap} for removing the item at `index`: shifts later indices down by one. */\nexport function removeAt(index: number): IndexMap {\n return (i) => (i === index ? null : i > index ? i - 1 : i);\n}\n\n/** The {@link IndexMap} for inserting an item at `index`: shifts `index` and later up by one. */\nexport function insertAt(index: number): IndexMap {\n return (i) => (i >= index ? i + 1 : i);\n}\n\n/** The {@link IndexMap} for swapping the items at `a` and `b`. */\nexport function swapAt(a: number, b: number): IndexMap {\n return (i) => (i === a ? b : i === b ? a : i);\n}\n\n/** The {@link IndexMap} for moving the item at `from` to `to`, shifting the items between. */\nexport function moveAt(from: number, to: number): IndexMap {\n return (i) => {\n if (i === from) return to;\n if (from < to) return i > from && i <= to ? i - 1 : i;\n return i >= to && i < from ? i + 1 : i;\n };\n}\n\n/** The {@link IndexMap} for replacing the item at `index` in place: drops only that index's state. */\nexport function replaceAt(index: number): IndexMap {\n return (i) => (i === index ? null : i);\n}\n\n/** The {@link IndexMap} for clearing every item in the array: drops all per-index state. */\nexport const clearAll: IndexMap = () => null;\n\n/**\n * Remap `path`'s index segment immediately under `arrayPath` through `map`.\n * Paths outside `arrayPath`, and `arrayPath` itself (a whole-array message),\n * pass through unchanged; a path whose index segment maps to `null` is\n * dropped (returns `null`) — its item no longer exists. Pure.\n */\nexport function remapIndex(path: FormPath, arrayPath: FormPath, map: IndexMap): FormPath | null {\n if (!isUnder(path, arrayPath) || path.length === arrayPath.length) return path;\n const segment = path[arrayPath.length];\n if (typeof segment !== \"number\") return path;\n const mapped = map(segment);\n if (mapped === null) return null;\n if (mapped === segment) return path;\n return [...path.slice(0, arrayPath.length), mapped, ...path.slice(arrayPath.length + 1)];\n}\n\n/**\n * Remap every entry of a flat, path-keyed record (a {@link toString} key per\n * entry — e.g. touched flags) through {@link remapIndex}. Entries whose path\n * maps to `null` are dropped. Pure.\n */\nexport function remapKeyedRecord<T>(\n record: Record<string, T>,\n arrayPath: FormPath,\n map: IndexMap,\n): Record<string, T> {\n const out: Record<string, T> = {};\n for (const key of Object.keys(record)) {\n const remapped = remapIndex(fromString(key), arrayPath, map);\n if (remapped !== null) out[toString(remapped)] = record[key] as T;\n }\n return out;\n}\n","/**\n * @copyright Thomas Foster\n *\n * The nested form-error tree and its operations.\n *\n * {@link FormErrors} is a nested error tree so a UI can read\n * `errors.author.name` or `errors.tags[0]` directly. The representation is:\n *\n * - a **leaf** field's messages are a `string[]` keyed by the field name\n * (`{ title: [\"Required\"] }`);\n * - a **branch** (nested object / array) is a nested `FormErrors`\n * (`{ author: { name: [\"Required\"] } }`); array elements are keyed by their\n * stringified index (`{ tags: { \"0\": [\"Too short\"] } }`);\n * - a message attached to a **branch itself** (a cross-field or\n * whole-array message) lives under that branch's `_errors` key.\n *\n * The tree is plain JSON — it serialises across the SSR boundary unchanged —\n * and the operations here ({@link issuesToErrors}, {@link flattenErrors},\n * {@link setError}, {@link mergeErrors}, …) are pure and return new trees.\n *\n * @module effect-forms/Errors\n */\n\nimport type { FormIssue, FormPath } from \"./Issues.ts\";\nimport { type IndexMap, remapIndex } from \"./Path.ts\";\n\n/** The root key under which a branch's own (non-field) messages are stored. */\nexport const ROOT_ERROR_KEY = \"_errors\";\n\n/**\n * A nested tree of validation messages. Leaves are `string[]`; branches are\n * nested {@link FormErrors}; a branch's own messages live under\n * {@link ROOT_ERROR_KEY}. Always JSON-serialisable.\n */\nexport interface FormErrors {\n readonly [ROOT_ERROR_KEY]?: readonly string[];\n readonly [key: string]: FormErrors | readonly string[] | undefined;\n}\n\n/**\n * A {@link FormErrors} tree typed to the shape of `A`, so fields are accessed\n * by name with type-safety: for `A = { name: string; author: { bio: string } }`,\n * `errors.name` is `readonly string[] | undefined` and `errors.author?.bio`\n * likewise. A branch's own (cross-field) messages live under `_errors`. The\n * runtime value is an ordinary {@link FormErrors} — this only refines the type.\n */\nexport type TypedFormErrors<A> = [NonNullable<A>] extends [ReadonlyArray<infer E>]\n ? {\n readonly [index: number]: TypedFormErrors<E> | undefined;\n readonly _errors?: readonly string[];\n }\n : [NonNullable<A>] extends [object]\n ? { readonly [K in keyof A]?: TypedFormErrors<A[K]> } & { readonly _errors?: readonly string[] }\n : readonly string[];\n\n/** Mutable mirror of {@link FormErrors} used while building a tree. */\ntype MutableNode = { [key: string]: string[] | MutableNode | undefined };\n\nconst isMessageList = (value: unknown): value is readonly string[] =>\n Array.isArray(value) && value.every((v) => typeof v === \"string\");\n\nconst ownErrors = (node: MutableNode): string[] => {\n const existing = node[ROOT_ERROR_KEY];\n if (isMessageList(existing)) return existing;\n const created: string[] = [];\n node[ROOT_ERROR_KEY] = created;\n return created;\n};\n\n/**\n * If `node[key]` is a leaf's message list, convert it in place into a branch\n * carrying those same messages as its own {@link ROOT_ERROR_KEY} (a path used\n * as a leaf is now needed as a branch too) — a no-op when `node[key]` is\n * already a branch or absent. Shared by {@link insert} and {@link setLeaf}'s\n * path-descent, the one piece of their branch-walking that's identical.\n */\nconst promoteLeafToBranch = (node: MutableNode, key: string): void => {\n const existing = node[key];\n if (isMessageList(existing)) node[key] = { [ROOT_ERROR_KEY]: existing };\n};\n\n/**\n * Insert one message at `path` into a mutable error tree. A leaf becomes a\n * `string[]`; if the same path is later used as a branch the existing list is\n * preserved under {@link ROOT_ERROR_KEY}; if a branch later receives its own\n * message it lands under {@link ROOT_ERROR_KEY}. The empty path targets the\n * tree root's {@link ROOT_ERROR_KEY}.\n */\nconst insert = (root: MutableNode, path: FormPath, message: string): void => {\n if (path.length === 0) {\n ownErrors(root).push(message);\n return;\n }\n\n let node = root;\n for (let i = 0; i < path.length - 1; i++) {\n const key = String(path[i]);\n if (node[key] === undefined) node[key] = {};\n else promoteLeafToBranch(node, key);\n node = node[key] as MutableNode;\n }\n\n const last = String(path[path.length - 1]);\n const existing = node[last];\n if (existing === undefined) {\n node[last] = [message];\n } else if (isMessageList(existing)) {\n existing.push(message);\n } else {\n // The leaf key is already a branch — attach to its own `_errors`.\n ownErrors(existing).push(message);\n }\n};\n\n/** Build a nested {@link FormErrors} tree from a flat list of {@link FormIssue}s. */\nexport function issuesToErrors(issues: ReadonlyArray<FormIssue>): FormErrors {\n const root: MutableNode = {};\n for (const issue of issues) insert(root, issue.path, issue.message);\n return root;\n}\n\n/**\n * Flatten a {@link FormErrors} tree back into a list of {@link FormIssue}s, in\n * depth-first order. The inverse of {@link issuesToErrors} (modulo message\n * ordering within a single field).\n */\nexport function flattenErrors(errors: FormErrors): FormIssue[] {\n const out: FormIssue[] = [];\n\n const walk = (node: FormErrors, path: Array<string | number>): void => {\n for (const key of Object.keys(node)) {\n const value = node[key];\n if (value === undefined) continue;\n if (key === ROOT_ERROR_KEY) {\n for (const message of value as readonly string[]) out.push({ path, message });\n continue;\n }\n const segment: string | number = /^\\d+$/.test(key) ? Number(key) : key;\n if (isMessageList(value)) {\n for (const message of value) out.push({ path: [...path, segment], message });\n } else {\n walk(value, [...path, segment]);\n }\n }\n };\n\n walk(errors, []);\n return out;\n}\n\n/** Whether the tree carries any message anywhere. */\nexport function hasErrors(errors: FormErrors): boolean {\n return flattenErrors(errors).length > 0;\n}\n\n/**\n * Read the messages attached directly to `path` (a leaf's list, or a branch's\n * own {@link ROOT_ERROR_KEY}). Returns `undefined` when the path has no direct\n * messages.\n */\nexport function getError(errors: FormErrors, path: FormPath): readonly string[] | undefined {\n let node: FormErrors | readonly string[] | undefined = errors;\n for (const segment of path) {\n if (node === undefined || isMessageList(node)) return undefined;\n node = node[String(segment)];\n }\n if (node === undefined) return undefined;\n if (isMessageList(node)) return node;\n return node[ROOT_ERROR_KEY];\n}\n\n/** Return a new tree with `message` added at `path`. Pure. */\nexport function setError(errors: FormErrors, path: FormPath, message: string): FormErrors {\n const next = structuredClone(errors) as unknown as MutableNode;\n insert(next, path, message);\n return next;\n}\n\n/** Combine two error trees into one (left then right). Pure. */\nexport function mergeErrors(a: FormErrors, b: FormErrors): FormErrors {\n return issuesToErrors([...flattenErrors(a), ...flattenErrors(b)]);\n}\n\n/** The empty error tree. */\nexport const noErrors: FormErrors = {};\n\n/**\n * Remap the array-index segments of every message under `arrayPath` through\n * `map` (see {@link module:effect-forms/Path.IndexMap}), so an error recorded\n * against a row follows that row through a remove / insert / swap / move.\n * Messages whose index maps to `null` are dropped. Pure.\n */\nexport function remapIndices(errors: FormErrors, arrayPath: FormPath, map: IndexMap): FormErrors {\n const remapped: FormIssue[] = [];\n for (const issue of flattenErrors(errors)) {\n const path = remapIndex(issue.path, arrayPath, map);\n if (path !== null) remapped.push({ path, message: issue.message });\n }\n return issuesToErrors(remapped);\n}\n\n/**\n * Return a new tree with the messages *directly at* `path` replaced by\n * `messages` (removing the key when `messages` is empty), leaving every other\n * path — including children of a branch `path` — untouched. Unlike\n * {@link setError} (which appends one message), this is the \"this field's\n * validator just ran, here is its complete result\" operation a per-field\n * validator needs: it can clear a field back to valid without disturbing\n * sibling or nested messages. Pure.\n */\nexport function replaceAt(\n errors: FormErrors,\n path: FormPath,\n messages: readonly string[],\n): FormErrors {\n const next = structuredClone(errors) as unknown as MutableNode;\n setLeaf(next, path, messages);\n return next;\n}\n\nconst setLeaf = (root: MutableNode, path: FormPath, messages: readonly string[]): void => {\n if (path.length === 0) {\n setOwnMessages(root, messages);\n return;\n }\n const parent = descendClearing(root, path, messages);\n if (parent === undefined) return; // an absent branch on the clearing path — nothing to clear\n setLeafMessages(parent, String(path[path.length - 1]), messages);\n};\n\n/** Set or clear a node's own {@link ROOT_ERROR_KEY} messages. */\nconst setOwnMessages = (node: MutableNode, messages: readonly string[]): void => {\n if (messages.length === 0) delete node[ROOT_ERROR_KEY];\n else node[ROOT_ERROR_KEY] = [...messages];\n};\n\n/**\n * Walk to `path`'s parent branch, creating branches as needed. When\n * `messages` is empty (a clear, not a set) a missing branch means there is\n * nothing to clear — descent stops early and returns `undefined` rather than\n * creating empty branches just to immediately no-op inside them.\n */\nconst descendClearing = (\n root: MutableNode,\n path: FormPath,\n messages: readonly string[],\n): MutableNode | undefined => {\n let node = root;\n for (let i = 0; i < path.length - 1; i++) {\n const key = String(path[i]);\n if (node[key] === undefined) {\n if (messages.length === 0) return undefined;\n node[key] = {};\n } else {\n promoteLeafToBranch(node, key);\n }\n node = node[key] as MutableNode;\n }\n return node;\n};\n\n/** Set or clear `node[key]`'s messages — a leaf's list, or (if it's already a branch) its own {@link ROOT_ERROR_KEY}. */\nconst setLeafMessages = (node: MutableNode, key: string, messages: readonly string[]): void => {\n const existing = node[key];\n if (existing === undefined) {\n if (messages.length > 0) node[key] = [...messages];\n return;\n }\n if (isMessageList(existing)) {\n if (messages.length === 0) delete node[key];\n else node[key] = [...messages];\n return;\n }\n // Already a branch (has nested children) — replace its own messages,\n // preserving the children.\n if (messages.length === 0) delete existing[ROOT_ERROR_KEY];\n else existing[ROOT_ERROR_KEY] = [...messages];\n};\n\n/**\n * Where a message in a {@link FormErrors} tree came from. `\"server\"` messages\n * come from the last submission response; `\"client\"` messages come from\n * browser-side validation (schema re-run, per-field validators, client-run\n * `refineEffect` refinements). Kept as parallel trees (see {@link\n * SourcedErrors}) rather than tagging each message, so a UI can style sources\n * differently and client revalidation can clear only its own tree, leaving\n * server-reported failures in place until their field actually changes.\n */\nexport type ErrorSource = \"client\" | \"server\";\n\n/** Parallel error trees, one per {@link ErrorSource}, plus their {@link mergeSourced} view. */\nexport interface SourcedErrors {\n readonly client: FormErrors;\n readonly server: FormErrors;\n}\n\n/** Both source trees empty. */\nexport const emptySourced: SourcedErrors = { client: noErrors, server: noErrors };\n\n/** Combine both source trees into the single tree a UI reads (server first, then client). */\nexport function mergeSourced(sourced: SourcedErrors): FormErrors {\n return mergeErrors(sourced.server, sourced.client);\n}\n\n/**\n * Return new {@link SourcedErrors} with `source`'s tree updated at `path` via\n * {@link replaceAt} (the other source's tree is untouched). Pure.\n */\nexport function setSourceAt(\n sourced: SourcedErrors,\n source: ErrorSource,\n path: FormPath,\n messages: readonly string[],\n): SourcedErrors {\n return { ...sourced, [source]: replaceAt(sourced[source], path, messages) };\n}\n\n/** Clear `source`'s messages at `path` (and nowhere else). Shorthand for {@link setSourceAt} with `[]`. */\nexport function clearSourceAt(\n sourced: SourcedErrors,\n source: ErrorSource,\n path: FormPath,\n): SourcedErrors {\n return setSourceAt(sourced, source, path, []);\n}\n","/**\n * @copyright Thomas Foster\n *\n * Field definitions for the {@link module:effect-forms/FormBuilder}.\n *\n * A {@link FormBuilder} composes a form one field at a time. Each field is\n * either a **scalar** {@link FieldDef} (bound to a leaf schema) or an\n * **array** {@link ArrayFieldDef} (bound to an item schema — the field is a\n * list of that item). This module is the small vocabulary the builder is made\n * of: the two field shapes, their guards, the type-level projections that turn\n * a record of fields into the form's encoded / decoded data types, and the\n * default-value derivation used to seed a blank form (or a freshly-appended\n * array item).\n *\n * Defaults are *encoded* — an HTML form holds strings, so a scalar seeds to\n * `\"\"`, an array to `[]`, and a nested struct recurses. Coercion back to the\n * decoded type is the schema's job at validate time (see\n * {@link module:effect-forms/Coerce}).\n *\n * @module effect-forms/Field\n */\n\nimport type * as Schema from \"effect/Schema\";\nimport * as SchemaAST from \"effect/SchemaAST\";\nimport type { FormPath } from \"./Issues.ts\";\n\n/** A scalar field: a key bound to a leaf (or nested struct) schema. */\nexport interface FieldDef<K extends string, S extends Schema.Top> {\n readonly _tag: \"field\";\n readonly key: K;\n readonly schema: S;\n}\n\n/** An array field: a key bound to an item schema; the field is a list of items. */\nexport interface ArrayFieldDef<K extends string, S extends Schema.Top> {\n readonly _tag: \"array\";\n readonly key: K;\n readonly itemSchema: S;\n}\n\n/** Either field shape, with the key / schema types erased. */\nexport type AnyFieldDef = FieldDef<string, Schema.Top> | ArrayFieldDef<string, Schema.Top>;\n\n/** A record of fields, keyed by field name — the builder's accumulated shape. */\nexport type FieldsRecord = Record<string, AnyFieldDef>;\n\n/** Whether `def` is an {@link ArrayFieldDef}. */\nexport const isArrayFieldDef = (def: AnyFieldDef): def is ArrayFieldDef<string, Schema.Top> =>\n def._tag === \"array\";\n\n/** Whether `def` is a scalar {@link FieldDef}. */\nexport const isFieldDef = (def: AnyFieldDef): def is FieldDef<string, Schema.Top> =>\n def._tag === \"field\";\n\n/** Construct a scalar {@link FieldDef}. */\nexport const makeField = <K extends string, S extends Schema.Top>(\n key: K,\n schema: S,\n): FieldDef<K, S> => ({ _tag: \"field\", key, schema });\n\n/** Construct an {@link ArrayFieldDef}. */\nexport const makeArrayField = <K extends string, S extends Schema.Top>(\n key: K,\n itemSchema: S,\n): ArrayFieldDef<K, S> => ({ _tag: \"array\", key, itemSchema });\n\n/** The encoded (form-input) data type for a record of fields. */\nexport type EncodedFromFields<T extends FieldsRecord> = {\n readonly [K in keyof T]: T[K] extends FieldDef<string, infer S>\n ? S[\"Encoded\"]\n : T[K] extends ArrayFieldDef<string, infer S>\n ? ReadonlyArray<S[\"Encoded\"]>\n : never;\n};\n\n/** The decoded (validated) data type for a record of fields. */\nexport type DecodedFromFields<T extends FieldsRecord> = {\n readonly [K in keyof T]: T[K] extends FieldDef<string, infer S>\n ? S[\"Type\"]\n : T[K] extends ArrayFieldDef<string, infer S>\n ? ReadonlyArray<S[\"Type\"]>\n : never;\n};\n\n/**\n * Derive a blank *encoded* default from a schema AST: a struct recurses into\n * its properties, an array seeds to `[]`, and any scalar seeds to `\"\"` (an\n * HTML input's empty value). Conservative by design — a value that will not\n * decode cleanly is still a valid *starting* value the user edits.\n */\nexport function defaultValue(schema: Schema.Top): unknown {\n return fromAst(schema.ast);\n}\n\n/**\n * Unwrap a union to its first structured (struct / array) member — an\n * `optional` / `NullOr` wrapper (`Struct | undefined` / `Struct | null`)\n * still resolves to the wrapped struct or array's AST rather than a scalar\n * fallback. Non-unions, and unions with no structured member, pass through.\n */\nfunction unwrapToStructured(ast: SchemaAST.AST): SchemaAST.AST {\n if (!SchemaAST.isUnion(ast)) return ast;\n for (const member of ast.types) {\n const inner = unwrapToStructured(member);\n if (SchemaAST.isObjects(inner) || SchemaAST.isArrays(inner)) return inner;\n }\n return ast;\n}\n\nfunction fromAst(ast: SchemaAST.AST): unknown {\n const unwrapped = unwrapToStructured(ast);\n if (SchemaAST.isObjects(unwrapped)) {\n const out: Record<string, unknown> = {};\n for (const ps of unwrapped.propertySignatures) out[String(ps.name)] = fromAst(ps.type);\n return out;\n }\n if (SchemaAST.isArrays(unwrapped)) return [];\n return \"\";\n}\n\n/** The item AST of an {@link SchemaAST.Arrays} node: the rest (spread) type, or the first tuple element. */\nfunction arrayElementAst(ast: SchemaAST.Arrays): SchemaAST.AST | undefined {\n return ast.rest[0] ?? ast.elements[0];\n}\n\n/** Descend one array-index path segment from an (already-unwrapped) array AST. */\nfunction stepIntoArray(ast: SchemaAST.AST): SchemaAST.AST | undefined {\n if (!SchemaAST.isArrays(ast)) return undefined;\n const item = arrayElementAst(ast);\n return item === undefined ? undefined : unwrapToStructured(item);\n}\n\n/** Descend one struct-property path segment from an (already-unwrapped) struct AST. */\nfunction stepIntoStruct(ast: SchemaAST.AST, key: string): SchemaAST.AST | undefined {\n if (!SchemaAST.isObjects(ast)) return undefined;\n const ps = ast.propertySignatures.find((p) => String(p.name) === key);\n return ps === undefined ? undefined : unwrapToStructured(ps.type);\n}\n\n/**\n * Walk `schema`'s AST along `path` — through struct properties and array\n * elements alike — and return the AST found there, or `undefined` if `path`\n * doesn't resolve (a missing property, or a non-array indexed). Unlike a\n * {@link FieldsRecord} lookup, this works for any nesting depth and for\n * schemas built directly with `Form.make` (no builder involved).\n */\nexport function schemaAt(schema: Schema.Top, path: FormPath): SchemaAST.AST | undefined {\n let ast: SchemaAST.AST | undefined = unwrapToStructured(schema.ast);\n for (const segment of path) {\n if (ast === undefined) return undefined;\n ast = typeof segment === \"number\" ? stepIntoArray(ast) : stepIntoStruct(ast, segment);\n }\n return ast;\n}\n\n/**\n * Derive a blank encoded item for the array field at `path` (any nesting\n * depth) by walking `schema`'s AST there — the nested-array counterpart to\n * {@link defaultValue}. Returns `\"\"` when `path` doesn't resolve to an array.\n */\nexport function defaultItemAt(schema: Schema.Top, path: FormPath): unknown {\n const ast = schemaAt(schema, path);\n if (ast === undefined || !SchemaAST.isArrays(ast)) return \"\";\n const item = arrayElementAst(ast);\n return item === undefined ? \"\" : fromAst(item);\n}\n\n/** Seed a blank encoded value for every field: `[]` for arrays, `\"\"` otherwise. */\nexport function defaultEncodedValues(fields: FieldsRecord): Record<string, unknown> {\n const out: Record<string, unknown> = {};\n for (const [key, def] of Object.entries(fields)) {\n out[key] = isArrayFieldDef(def) ? [] : defaultValue(def.schema);\n }\n return out;\n}\n","/**\n * @copyright Thomas Foster\n *\n * Form issues — the flat, path-addressed representation of a single\n * validation failure, plus the walker that turns an Effect Schema issue\n * tree into a list of them.\n *\n * An Effect Schema decode failure is a recursive {@link SchemaIssue.Issue}\n * tree: `Pointer` nodes carry path segments, `Composite` / `AnyOf` group\n * sibling failures, `Filter` / `Encoding` wrap a single inner failure, and\n * the leaves (`InvalidType`, `InvalidValue`, `MissingKey`, …) describe the\n * actual problem. {@link schemaIssuesToFormIssues} flattens that tree into\n * one {@link FormIssue} per leaf, accumulating the `Pointer.path` segments\n * into a `FormPath`. This is the framework-neutral\n * flattened error list and the same walk the repo's JSON:API materialiser\n * performs — here it stays UI-shaped (`path` + `message`) rather than\n * JSON:API-pointer-shaped.\n *\n * @module effect-forms/Issues\n */\n\nimport type * as Schema from \"effect/Schema\";\nimport * as SchemaIssue from \"effect/SchemaIssue\";\n\n/**\n * A path into the form's data. String segments address object keys; number\n * segments address array indices. The empty path addresses the form root\n * (a whole-form / cross-field message).\n */\nexport type FormPath = ReadonlyArray<string | number>;\n\n/** One validation failure: where it happened ({@link FormPath}) and why. */\nexport interface FormIssue {\n readonly path: FormPath;\n readonly message: string;\n}\n\n/**\n * Render one terminal issue leaf into a human-readable message. The default\n * defers to the issue's own `toString`, which Effect Schema renders into a\n * readable sentence (e.g. `Expected string, got 1`). Override it to localise\n * or to map specific leaf `_tag`s to custom copy.\n */\nexport type LeafFormatter = (issue: SchemaIssue.Issue) => string;\n\n/** The default leaf formatter — Effect Schema's own rendering of the leaf. */\nexport const defaultLeafFormatter: LeafFormatter = (issue) => String(issue);\n\n/**\n * Normalise a `Pointer.path` segment into a {@link FormPath} segment: integer\n * keys become numbers (array indices), everything else becomes a string.\n */\nconst normaliseSegment = (segment: PropertyKey): string | number => {\n if (typeof segment === \"number\") return segment;\n if (typeof segment === \"symbol\") return segment.toString();\n return /^\\d+$/.test(segment) ? Number(segment) : segment;\n};\n\n/**\n * Walk an Effect Schema issue tree, emitting one {@link FormIssue} per leaf\n * failure. Path segments accumulate through `Pointer` nodes; `Composite` and\n * `AnyOf` fan out to siblings; `Filter` / `Encoding` are transparent\n * wrappers. An `AnyOf` with no recorded member failures (a bare union\n * mismatch) is itself a leaf.\n */\nexport function schemaIssuesToFormIssues(\n issue: SchemaIssue.Issue,\n format: LeafFormatter = defaultLeafFormatter,\n): FormIssue[] {\n const out: FormIssue[] = [];\n\n const walk = (current: SchemaIssue.Issue, path: Array<string | number>): void => {\n switch (current._tag) {\n case \"Pointer\":\n walk(current.issue, [...path, ...current.path.map(normaliseSegment)]);\n return;\n case \"Composite\":\n for (const child of current.issues) walk(child, path);\n return;\n case \"AnyOf\":\n if (current.issues.length === 0) {\n out.push({ path, message: format(current) });\n return;\n }\n for (const child of current.issues) walk(child, path);\n return;\n case \"Filter\":\n case \"Encoding\":\n walk(current.issue, path);\n return;\n default:\n out.push({ path, message: format(current) });\n return;\n }\n };\n\n walk(issue, []);\n return out;\n}\n\n/**\n * Normalise a filter predicate's {@link Schema.FilterOutput} into a flat list of\n * {@link FormIssue}s (empty on success). Shared by whole-form refinements\n * ({@link module:effect-forms/FormBuilder}) and per-field validators\n * ({@link module:effect-forms/Validate}) so both fold into the same nested\n * error tree as schema-decode failures.\n */\nexport function filterOutputToFormIssues(output: Schema.FilterOutput): FormIssue[] {\n if (output === undefined || output === true) return [];\n if (output === false) return [{ path: [], message: \"Invalid value\" }];\n if (Array.isArray(output)) return output.flatMap(filterIssueToFormIssues);\n return filterIssueToFormIssues(output as Schema.FilterIssue);\n}\n\nfunction filterIssueToFormIssues(issue: Schema.FilterIssue): FormIssue[] {\n if (typeof issue === \"string\") return [{ path: [], message: issue }];\n if (\"path\" in issue && \"issue\" in issue) {\n const prefix = issue.path.map((s) => (typeof s === \"symbol\" ? s.toString() : s));\n const inner =\n typeof issue.issue === \"string\"\n ? [{ path: [], message: issue.issue }]\n : schemaIssuesToFormIssues(issue.issue);\n return inner.map((i) => ({ path: [...prefix, ...i.path], message: i.message }));\n }\n return schemaIssuesToFormIssues(issue);\n}\n","/**\n * @copyright Thomas Foster\n *\n * Compose a form schema one field at a time, with cross-field refinements.\n *\n * {@link make} (aliased {@link empty}) starts an empty builder;\n * {@link FormBuilder.addField} adds a scalar or array field, {@link\n * FormBuilder.merge} folds another builder in, and {@link FormBuilder.refine} /\n * {@link FormBuilder.refineEffect} attach cross-field validations. The point is\n * incremental composition — assemble a large form from small, reusable\n * field-group builders — plus a home for whole-form rules (`password ===\n * confirmPassword`) that a single field schema can't express.\n *\n * {@link buildSchema} collapses the accumulated fields into an ordinary\n * `Schema.Struct` (array fields become `Schema.Array(item)`) and applies every\n * *synchronous* refinement as a struct-level `check`, so the result decodes,\n * derives constraints, and validates exactly like a hand-written schema — hand\n * it straight to {@link module:effect-forms/Form}'s `make`. *Asynchronous*\n * refinements can't be schema checks (Effect Schema has no effectful filter),\n * so they're carried on the builder and run by the Effect-returning validate\n * path — {@link asyncRefinements} exposes them and {@link runAsyncRefinements}\n * runs them into a {@link FormIssue} list.\n *\n * @module effect-forms/FormBuilder\n */\n\nimport * as Effect from \"effect/Effect\";\nimport * as Schema from \"effect/Schema\";\nimport type {\n AnyFieldDef,\n ArrayFieldDef,\n DecodedFromFields,\n EncodedFromFields,\n FieldDef,\n FieldsRecord,\n} from \"./Field.ts\";\nimport { isArrayFieldDef, isFieldDef, makeField } from \"./Field.ts\";\nimport type { FormIssue } from \"./Issues.ts\";\nimport { filterOutputToFormIssues } from \"./Issues.ts\";\n\n/** Brand for a {@link FormBuilder}. */\nexport const TypeId: unique symbol = Symbol.for(\"@thomasfosterau/effect-forms/FormBuilder\");\nexport type TypeId = typeof TypeId;\n\n/** A synchronous cross-field refinement — becomes a struct-level schema check. */\ninterface SyncRefinement {\n readonly _tag: \"sync\";\n readonly fn: (values: unknown) => Schema.FilterOutput;\n}\n\n/** An asynchronous cross-field refinement — run by the Effect validate path. */\ninterface AsyncRefinement {\n readonly _tag: \"async\";\n readonly fn: (values: unknown) => Effect.Effect<Schema.FilterOutput, never, unknown>;\n}\n\ntype Refinement = SyncRefinement | AsyncRefinement;\n\n/**\n * A form assembled field by field. `TFields` accumulates the field record;\n * `R` accumulates the schemas' decoding-service requirements. Immutable — every\n * method returns a new builder.\n */\nexport interface FormBuilder<TFields extends FieldsRecord, R> {\n readonly [TypeId]: TypeId;\n readonly fields: TFields;\n readonly refinements: ReadonlyArray<Refinement>;\n readonly _R?: R;\n\n /** Add a scalar field from a {@link FieldDef}. */\n addField<K extends string, S extends Schema.Top>(\n field: FieldDef<K, S>,\n ): FormBuilder<TFields & { readonly [key in K]: FieldDef<K, S> }, R | S[\"DecodingServices\"]>;\n /** Add an array field from an {@link ArrayFieldDef}. */\n addField<K extends string, S extends Schema.Top>(\n field: ArrayFieldDef<K, S>,\n ): FormBuilder<TFields & { readonly [key in K]: ArrayFieldDef<K, S> }, R | S[\"DecodingServices\"]>;\n /** Add a scalar field from a key and schema. */\n addField<K extends string, S extends Schema.Top>(\n key: K,\n schema: S,\n ): FormBuilder<TFields & { readonly [key in K]: FieldDef<K, S> }, R | S[\"DecodingServices\"]>;\n\n /** Fold another builder's fields and refinements into this one. */\n merge<TFields2 extends FieldsRecord, R2>(\n other: FormBuilder<TFields2, R2>,\n ): FormBuilder<TFields & TFields2, R | R2>;\n\n /**\n * Attach a synchronous whole-form validation. The predicate sees the decoded\n * values and returns a {@link Schema.FilterOutput} (`undefined` / `true` to\n * pass, a message / `{ path, issue }` / list to fail).\n */\n refine(\n predicate: (values: DecodedFromFields<TFields>) => Schema.FilterOutput,\n ): FormBuilder<TFields, R>;\n\n /** Attach an asynchronous whole-form validation (run by the validate path). */\n refineEffect<RD>(\n predicate: (\n values: DecodedFromFields<TFields>,\n ) => Effect.Effect<Schema.FilterOutput, never, RD>,\n ): FormBuilder<TFields, R | RD>;\n}\n\nconst proto = {\n [TypeId]: TypeId,\n addField(\n this: FormBuilder<FieldsRecord, unknown>,\n keyOrField: string | AnyFieldDef,\n schema?: Schema.Top,\n ): FormBuilder<FieldsRecord, unknown> {\n const field = typeof keyOrField === \"string\" ? makeField(keyOrField, schema!) : keyOrField;\n return build({ ...this.fields, [field.key]: field }, this.refinements);\n },\n merge(\n this: FormBuilder<FieldsRecord, unknown>,\n other: FormBuilder<FieldsRecord, unknown>,\n ): FormBuilder<FieldsRecord, unknown> {\n return build({ ...this.fields, ...other.fields }, [...this.refinements, ...other.refinements]);\n },\n refine(\n this: FormBuilder<FieldsRecord, unknown>,\n predicate: (values: unknown) => Schema.FilterOutput,\n ): FormBuilder<FieldsRecord, unknown> {\n return build(this.fields, [...this.refinements, { _tag: \"sync\", fn: predicate }]);\n },\n refineEffect(\n this: FormBuilder<FieldsRecord, unknown>,\n predicate: (values: unknown) => Effect.Effect<Schema.FilterOutput, never, unknown>,\n ): FormBuilder<FieldsRecord, unknown> {\n return build(this.fields, [...this.refinements, { _tag: \"async\", fn: predicate }]);\n },\n};\n\nfunction build(\n fields: FieldsRecord,\n refinements: ReadonlyArray<Refinement>,\n): FormBuilder<FieldsRecord, unknown> {\n const self = Object.create(proto);\n self.fields = fields;\n self.refinements = refinements;\n return self;\n}\n\n/** Whether `u` is a {@link FormBuilder}. */\nexport const isFormBuilder = (u: unknown): u is FormBuilder<FieldsRecord, unknown> =>\n typeof u === \"object\" && u !== null && TypeId in u;\n\n/** The empty builder — the starting point for {@link FormBuilder.addField}. */\nexport const make: FormBuilder<Record<never, never>, never> = build({}, []) as never;\n\n/** Alias of {@link make} — the empty builder. */\nexport const empty = make;\n\n/**\n * Collapse a builder into an Effect Schema: a `Schema.Struct` of the fields\n * (array fields as `Schema.Array(item)`) with every synchronous refinement\n * applied as a struct-level check. Ready for {@link module:effect-forms/Form}.\n */\nexport function buildSchema<TFields extends FieldsRecord, R>(\n self: FormBuilder<TFields, R>,\n): Schema.Codec<DecodedFromFields<TFields>, EncodedFromFields<TFields>, R> {\n const structFields: Record<string, Schema.Top> = {};\n for (const [key, def] of Object.entries(self.fields)) {\n if (isArrayFieldDef(def)) structFields[key] = Schema.Array(def.itemSchema);\n else if (isFieldDef(def)) structFields[key] = def.schema;\n }\n\n let schema: Schema.Top = Schema.Struct(structFields);\n for (const refinement of self.refinements) {\n if (refinement._tag === \"sync\") schema = schema.check(Schema.makeFilter(refinement.fn));\n }\n\n return schema as unknown as Schema.Codec<\n DecodedFromFields<TFields>,\n EncodedFromFields<TFields>,\n R\n >;\n}\n\n/** The asynchronous refinements carried on a builder, as bare predicates. */\nexport function asyncRefinements<TFields extends FieldsRecord, R>(\n self: FormBuilder<TFields, R>,\n): ReadonlyArray<\n (values: DecodedFromFields<TFields>) => Effect.Effect<Schema.FilterOutput, never, R>\n> {\n return self.refinements\n .filter((r): r is AsyncRefinement => r._tag === \"async\")\n .map((r) => r.fn as never);\n}\n\n// {@link filterOutputToFormIssues} moved to {@link module:effect-forms/Issues}\n// (shared with per-field validators); re-exported here for existing callers.\nexport { filterOutputToFormIssues };\n\n/**\n * Run every asynchronous refinement on `self` against `values` and collect\n * their failures as {@link FormIssue}s (empty when all pass). Runs them\n * concurrently; requirements propagate on the `R` channel.\n */\nexport function runAsyncRefinements<TFields extends FieldsRecord, R>(\n self: FormBuilder<TFields, R>,\n values: DecodedFromFields<TFields>,\n): Effect.Effect<ReadonlyArray<FormIssue>, never, R> {\n const refinements = asyncRefinements(self);\n if (refinements.length === 0) return Effect.succeed([]);\n return Effect.forEach(refinements, (fn) => fn(values), { concurrency: \"unbounded\" }).pipe(\n Effect.map((outputs) => outputs.flatMap(filterOutputToFormIssues)),\n );\n}\n","/**\n * @copyright Thomas Foster\n *\n * {@link FormState} — the serialisable snapshot of a form.\n *\n * This is the single object a\n * server produces (validate a submission, or seed an empty form) and hands to\n * the client to hydrate from. It is plain JSON so it survives the SSR → client\n * boundary, and {@link FormStateSchema} gives it an Effect Schema so it can be\n * decoded back on arrival.\n *\n * @module effect-forms/State\n */\n\nimport * as Schema from \"effect/Schema\";\nimport type { InputConstraints } from \"./Constraints.ts\";\nimport { type FormErrors, hasErrors, noErrors, setError } from \"./Errors.ts\";\nimport type { FormPath } from \"./Issues.ts\";\n\n/**\n * A form snapshot.\n *\n * - `id` distinguishes multiple forms on one page.\n * - `valid` is whether the last validation succeeded.\n * - `posted` is whether this snapshot came from a submission (vs. a seeded\n * empty form) — drives \"show errors only after submit\" UIs.\n * - `data` is the current values (typed output on success; posted values\n * merged over defaults on failure, so the form re-renders what the user\n * typed).\n * - `errors` is the nested {@link FormErrors} tree.\n * - `message` is an optional status payload (a free-form status payload).\n * - `constraints` is the optional derived {@link InputConstraints} tree.\n */\nexport interface FormState<A, Message = unknown> {\n readonly id: string;\n readonly valid: boolean;\n readonly posted: boolean;\n readonly data: A;\n readonly errors: FormErrors;\n readonly message?: Message | undefined;\n readonly constraints?: InputConstraints | undefined;\n}\n\n/** Options for {@link make}. */\nexport interface MakeFormStateOptions<Message> {\n readonly id?: string;\n readonly valid?: boolean;\n readonly posted?: boolean;\n readonly errors?: FormErrors;\n readonly message?: Message;\n readonly constraints?: InputConstraints;\n}\n\n/** Build a {@link FormState} from data plus overrides. `valid` defaults to \"no errors\". */\nexport function make<A, Message = unknown>(\n data: A,\n options: MakeFormStateOptions<Message> = {},\n): FormState<A, Message> {\n const errors = options.errors ?? noErrors;\n return {\n id: options.id ?? \"default\",\n valid: options.valid ?? !hasErrors(errors),\n posted: options.posted ?? false,\n data,\n errors,\n ...(options.message !== undefined ? { message: options.message } : {}),\n ...(options.constraints !== undefined ? { constraints: options.constraints } : {}),\n };\n}\n\n/** Return a new state carrying `message` (and not otherwise changed). */\nexport function withMessage<A, Message>(\n state: FormState<A, Message>,\n message: Message,\n): FormState<A, Message> {\n return { ...state, message };\n}\n\n/**\n * Return a new state with `message` added at `path` and `valid` forced to\n * `false` — for attaching a\n * server-side validation failure to a specific field after the schema passed.\n */\nexport function withError<A, Message>(\n state: FormState<A, Message>,\n path: FormPath,\n message: string,\n): FormState<A, Message> {\n return { ...state, valid: false, errors: setError(state.errors, path, message) };\n}\n\n/** Whether the state is valid. */\nexport const isValid = <A, Message>(state: FormState<A, Message>): boolean => state.valid;\n\n/** Effect Schema describing the JSON shape of {@link FormState} for transport. */\nexport function FormStateSchema<DataSchema extends Schema.Top>(data: DataSchema) {\n return Schema.Struct({\n id: Schema.String,\n valid: Schema.Boolean,\n posted: Schema.Boolean,\n data,\n errors: Schema.Record(Schema.String, Schema.Unknown),\n message: Schema.optional(Schema.Unknown),\n constraints: Schema.optional(Schema.Record(Schema.String, Schema.Unknown)),\n });\n}\n","/**\n * @copyright Thomas Foster\n *\n * {@link make} — the core entry point: bind an Effect Schema to a form and\n * get back a validator and an empty-state factory.\n *\n * This is the framework-neutral validate-and-seed entry point,\n * expressed as a small object bound to one schema:\n *\n * - `validate(input)` parses an HTML form body (or a plain object) and decodes\n * it through the schema, returning a {@link FormState} — valid with the\n * decoded data, or invalid with the nested {@link FormErrors} and the posted\n * values preserved so the form re-renders what the user typed. It is an\n * `Effect`, so a schema requiring decoding services composes naturally and\n * the caller stays on the typed error channel — there is none; validation\n * failures live in the returned state, not the error channel.\n * - `empty()` seeds an unposted, invalid-by-default form from the supplied\n * defaults — what a `load` returns to render a blank create form.\n *\n * Coercion (strings → numbers / booleans / dates) is the schema's job: build\n * the schema from coercing leaves (`Schema.FiniteFromString`, the\n * {@link module:effect-forms/Coerce} helpers, …) so a multipart body decodes\n * cleanly.\n *\n * @module effect-forms/Form\n */\n\nimport * as Effect from \"effect/Effect\";\nimport type * as Schema from \"effect/Schema\";\nimport * as SchemaParser from \"effect/SchemaParser\";\nimport { constraintsFromSchema, type InputConstraints } from \"./Constraints.ts\";\nimport { defaultEncodedValues } from \"./Field.ts\";\nimport { issuesToErrors } from \"./Errors.ts\";\nimport { buildSchema, type FormBuilder, runAsyncRefinements } from \"./FormBuilder.ts\";\nimport type { DecodedFromFields, EncodedFromFields, FieldsRecord } from \"./Field.ts\";\nimport { formDataToObject, requestToObject } from \"./FormData.ts\";\nimport { type LeafFormatter, schemaIssuesToFormIssues } from \"./Issues.ts\";\nimport { type FormState, make as makeFormState, type MakeFormStateOptions } from \"./State.ts\";\n\n/** Everything {@link Form.validate} accepts. `null` / `undefined` mean \"no submission\". */\nexport type FormInput =\n | FormData\n | URLSearchParams\n | Request\n | Record<string, unknown>\n | null\n | undefined;\n\n/** Options for {@link make}. */\nexport interface MakeFormOptions<S extends Schema.Top> {\n /** Distinguishes multiple forms on a page. Defaults to `\"default\"`. */\n readonly id?: string;\n /** The blank-form values — what {@link Form.empty} seeds and the merge base on failure. */\n readonly defaults: S[\"Type\"];\n /** Override the per-leaf message rendering. */\n readonly leafFormatter?: LeafFormatter;\n /** Constraint overrides deep-merged over the AST-derived tree. */\n readonly constraints?: InputConstraints;\n /** Derive {@link InputConstraints} from the schema AST (default `true`). */\n readonly deriveConstraints?: boolean;\n}\n\n/** A schema bound to a form: a validator plus an empty-state factory. */\nexport interface Form<S extends Schema.Top, Message = unknown> {\n readonly schema: S;\n readonly id: string;\n readonly constraints: InputConstraints;\n /** Seed a blank, unposted form from the defaults. */\n empty(overrides?: MakeFormStateOptions<Message>): FormState<S[\"Type\"], Message>;\n /** Parse a form body (no decode) into a structured object. */\n parse(input: FormData | URLSearchParams | Record<string, unknown>): Record<string, unknown>;\n /**\n * Validate a submission into a {@link FormState}. Never fails on the error\n * channel — schema failures become `errors` on the returned (invalid) state.\n */\n validate(\n input: FormInput,\n ): Effect.Effect<FormState<S[\"Type\"], Message>, never, S[\"DecodingServices\"]>;\n}\n\nconst toStructured = (input: FormInput): Effect.Effect<Record<string, unknown> | null> => {\n if (input === null || input === undefined) return Effect.succeed(null);\n if (input instanceof Request) return Effect.promise(() => requestToObject(input));\n if (input instanceof FormData || input instanceof URLSearchParams) {\n return Effect.succeed(formDataToObject(input));\n }\n return Effect.succeed(input as Record<string, unknown>);\n};\n\n/**\n * Bind `schema` to a form. See the module docs for the contract. The returned\n * {@link Form} is stateless and reusable across requests.\n */\nexport function make<S extends Schema.Top, Message = unknown>(\n schema: S,\n options: MakeFormOptions<S>,\n): Form<S, Message> {\n const id = options.id ?? \"default\";\n const { defaults, leafFormatter } = options;\n const constraints =\n options.deriveConstraints === false\n ? (options.constraints ?? {})\n : constraintsFromSchema(schema, options.constraints ?? {});\n // `errors: \"all\"` collects every field failure (collect-all) rather\n // than stopping at the first, so the whole form lights up at once.\n const decode = SchemaParser.decodeUnknownEffect(schema, { errors: \"all\" });\n\n const empty: Form<S, Message>[\"empty\"] = (overrides = {}) =>\n makeFormState<S[\"Type\"], Message>(defaults, {\n id,\n valid: false,\n posted: false,\n constraints,\n ...overrides,\n });\n\n const parse: Form<S, Message>[\"parse\"] = (input) =>\n input instanceof FormData || input instanceof URLSearchParams\n ? formDataToObject(input)\n : (input as Record<string, unknown>);\n\n const validate: Form<S, Message>[\"validate\"] = (input) =>\n toStructured(input).pipe(\n Effect.flatMap((object) => {\n if (object === null) return Effect.succeed(empty());\n return decode(object).pipe(\n Effect.matchEffect({\n onSuccess: (data) =>\n Effect.succeed(\n makeFormState<S[\"Type\"], Message>(data as S[\"Type\"], {\n id,\n valid: true,\n posted: true,\n constraints,\n }),\n ),\n onFailure: (issue) =>\n Effect.succeed(\n makeFormState<S[\"Type\"], Message>(\n { ...(defaults as object), ...object } as S[\"Type\"],\n {\n id,\n valid: false,\n posted: true,\n constraints,\n errors: issuesToErrors(schemaIssuesToFormIssues(issue, leafFormatter)),\n },\n ),\n ),\n }),\n );\n }),\n );\n\n return { schema, id, constraints, empty, parse, validate };\n}\n\n/** Options for {@link fromBuilder}. Like {@link MakeFormOptions} but `defaults` is optional. */\nexport interface FromBuilderOptions<TFields extends FieldsRecord> {\n /** Distinguishes multiple forms on a page. Defaults to `\"default\"`. */\n readonly id?: string;\n /** Blank-form values. Defaults to a schema-derived encoded blank per field. */\n readonly defaults?: EncodedFromFields<TFields>;\n /** Override the per-leaf message rendering. */\n readonly leafFormatter?: LeafFormatter;\n /** Constraint overrides deep-merged over the AST-derived tree. */\n readonly constraints?: InputConstraints;\n /** Derive {@link InputConstraints} from the schema AST (default `true`). */\n readonly deriveConstraints?: boolean;\n}\n\n/**\n * Bind a {@link FormBuilder} to a {@link Form}. Collapses the builder to a\n * schema (see {@link buildSchema}), then behaves like {@link make} — except its\n * `validate` also runs the builder's *asynchronous* refinements after a\n * successful decode, folding any failures into the same nested error tree. When\n * `defaults` is omitted it is derived from the fields (blank encoded values).\n */\nexport function fromBuilder<TFields extends FieldsRecord, R, Message = unknown>(\n builder: FormBuilder<TFields, R>,\n options: FromBuilderOptions<TFields> = {},\n): Form<Schema.Codec<DecodedFromFields<TFields>, EncodedFromFields<TFields>, R>, Message> {\n const schema = buildSchema(builder);\n const defaults = (options.defaults ??\n defaultEncodedValues(builder.fields)) as EncodedFromFields<TFields>;\n const base = make<typeof schema, Message>(schema, { ...options, defaults });\n\n const decode = SchemaParser.decodeUnknownEffect(schema, { errors: \"all\" });\n\n const validate: Form<typeof schema, Message>[\"validate\"] = (input) =>\n toStructured(input).pipe(\n Effect.flatMap((object) => {\n if (object === null) return Effect.succeed(base.empty());\n const posted = { ...(defaults as object), ...object } as DecodedFromFields<TFields>;\n return decode(object).pipe(\n Effect.matchEffect({\n onSuccess: (data) =>\n runAsyncRefinements(builder, data as DecodedFromFields<TFields>).pipe(\n Effect.map((issues) =>\n issues.length === 0\n ? makeFormState<DecodedFromFields<TFields>, Message>(\n data as DecodedFromFields<TFields>,\n { id: base.id, valid: true, posted: true, constraints: base.constraints },\n )\n : makeFormState<DecodedFromFields<TFields>, Message>(posted, {\n id: base.id,\n valid: false,\n posted: true,\n constraints: base.constraints,\n errors: issuesToErrors(issues),\n }),\n ),\n ),\n onFailure: (issue) =>\n Effect.succeed(\n makeFormState<DecodedFromFields<TFields>, Message>(posted, {\n id: base.id,\n valid: false,\n posted: true,\n constraints: base.constraints,\n errors: issuesToErrors(schemaIssuesToFormIssues(issue, options.leafFormatter)),\n }),\n ),\n }),\n );\n }),\n );\n\n return { ...base, validate };\n}\n","/**\n * @copyright Thomas Foster\n *\n * When a form validates (and, optionally, auto-submits).\n *\n * A reactive form has to decide *when* to run validation as the user types.\n * The three modes mirror the common form-library vocabulary:\n *\n * - **`onSubmit`** (the default) — validate only when the form is submitted (or\n * validation is triggered explicitly). The quietest mode.\n * - **`onBlur`** — validate a field when it loses focus.\n * - **`onChange`** — validate on every change, optionally `debounce`d.\n *\n * `onBlur` / `onChange` may also `autoSubmit`, turning the form into a\n * live-saving surface (a settings panel, a filter bar). This module is the\n * framework-neutral half: {@link parse} normalises the loose {@link FormMode}\n * a caller supplies into a fully-resolved {@link ParsedMode} the reactive\n * store drives from. The store owns the actual scheduling.\n *\n * A separate `revalidate` dimension governs what happens *after a submit*: an\n * `onSubmit`-mode form is otherwise silent until the next submit, which\n * leaves a failed post's errors frozen even after the user fixes the\n * offending field. `revalidate` says which trigger (`\"onChange\"` /\n * `\"onBlur\"` — independent of the primary `validation` trigger) re-validates\n * once the form has been posted at least once; `\"never\"` keeps the classic\n * frozen-until-resubmit behaviour.\n *\n * @module effect-forms/Mode\n */\n\nimport * as Duration from \"effect/Duration\";\n\n/** What re-validates a posted form as the user keeps editing. See {@link ParsedMode.revalidate}. */\nexport type RevalidateMode = \"onChange\" | \"onBlur\" | \"never\";\n\n/**\n * How a form decides when to validate, and whether it auto-submits.\n *\n * - `onSubmit` (the default) cannot auto-submit or debounce.\n * - `onBlur` may auto-submit; debounce is not meaningful.\n * - `onChange` may auto-submit and may debounce.\n *\n * `revalidate` is independent of `validation` and applies to every mode —\n * see the module docs.\n */\nexport type FormMode = (\n | { readonly validation?: \"onSubmit\"; readonly autoSubmit?: false; readonly debounce?: never }\n | { readonly validation: \"onBlur\"; readonly autoSubmit?: boolean; readonly debounce?: never }\n | {\n readonly validation: \"onChange\";\n readonly debounce?: Duration.Input;\n readonly autoSubmit?: boolean;\n }\n) & { readonly revalidate?: RevalidateMode };\n\n/** The fully-resolved form of a {@link FormMode} — every field decided. */\nexport interface ParsedMode {\n readonly validation: \"onSubmit\" | \"onBlur\" | \"onChange\";\n /** Debounce in milliseconds, or `null` for no debounce. */\n readonly debounce: number | null;\n readonly autoSubmit: boolean;\n /** What re-validates the form once it has been posted at least once. Defaults to `\"onChange\"`. */\n readonly revalidate: RevalidateMode;\n}\n\n/**\n * Normalise a {@link FormMode} into a {@link ParsedMode}. An absent mode is\n * `onSubmit`. `debounce` is resolved to milliseconds and only applies in\n * `onChange`; `autoSubmit` is only honoured for `onBlur` / `onChange`;\n * `revalidate` defaults to `\"onChange\"` (TanStack's / RHF's default\n * post-submit behaviour) regardless of the primary `validation` mode.\n */\nexport function parse(mode?: FormMode): ParsedMode {\n const validation = mode?.validation ?? \"onSubmit\";\n const revalidate = mode?.revalidate ?? \"onChange\";\n\n if (validation === \"onBlur\") {\n return {\n validation: \"onBlur\",\n debounce: null,\n autoSubmit: mode?.autoSubmit === true,\n revalidate,\n };\n }\n\n if (validation === \"onChange\") {\n const debounce = mode?.debounce === undefined ? null : Duration.toMillis(mode.debounce);\n return { validation: \"onChange\", debounce, autoSubmit: mode?.autoSubmit === true, revalidate };\n }\n\n return { validation: \"onSubmit\", debounce: null, autoSubmit: false, revalidate };\n}\n","/**\n * @copyright Thomas Foster\n *\n * {@link FormActionResult} — the framework-neutral outcome of a form\n * submission handler.\n *\n * SvelteKit's `ActionResult` (`success` / `failure` / `redirect` / `error`) is\n * Svelte-specific; this is the same idea expressed as a plain tagged union so\n * a server handler in any framework can describe what happened, and a client\n * adapter can interpret it uniformly. A Svelte adapter maps this onto\n * SvelteKit's `ActionResult`; a fetch client reads the JSON shape directly.\n *\n * @module effect-forms/Result\n */\n\nimport type { FormState } from \"./State.ts\";\n\n/** The submission validated and the command ran; carries the resulting state. */\nexport interface FormSuccess<A, Message> {\n readonly _tag: \"Success\";\n readonly status: number;\n readonly state: FormState<A, Message>;\n}\n\n/** The submission was rejected (validation or a user-fixable command failure). */\nexport interface FormFailure<A, Message> {\n readonly _tag: \"Failure\";\n readonly status: number;\n readonly state: FormState<A, Message>;\n}\n\n/** The handler asks the client to navigate elsewhere (post-success redirect). */\nexport interface FormRedirect {\n readonly _tag: \"Redirect\";\n readonly status: number;\n readonly location: string;\n}\n\n/** An unexpected (non-user-fixable) error: surface it, don't bind it to fields. */\nexport interface FormErrorResult {\n readonly _tag: \"Error\";\n readonly status: number;\n readonly message: string;\n}\n\n/** The outcome of a form submission. */\nexport type FormActionResult<A, Message = unknown> =\n | FormSuccess<A, Message>\n | FormFailure<A, Message>\n | FormRedirect\n | FormErrorResult;\n\n/**\n * The data a server form action returns to the client on a non-redirect\n * outcome — the wire contract a client adapter applies back to its store. A\n * validation failure carries the {@link FormState} (`form`); an unexpected\n * error carries a root `message`.\n */\nexport interface FormActionData<A = unknown, Message = unknown> {\n /** The form state (nested errors + posted values) for the client to apply. */\n readonly form?: FormState<A, Message>;\n /** A root-level message for an unexpected (non-field) failure. */\n readonly message?: string;\n}\n\n/** Construct a {@link FormSuccess} (default status 200). */\nexport const success = <A, Message>(\n state: FormState<A, Message>,\n status = 200,\n): FormActionResult<A, Message> => ({ _tag: \"Success\", status, state });\n\n/** Construct a {@link FormFailure} (default status 400). */\nexport const failure = <A, Message>(\n state: FormState<A, Message>,\n status = 400,\n): FormActionResult<A, Message> => ({ _tag: \"Failure\", status, state });\n\n/** Construct a {@link FormRedirect} (default status 303). */\nexport const redirect = <A, Message>(\n location: string,\n status = 303,\n): FormActionResult<A, Message> => ({ _tag: \"Redirect\", status, location });\n\n/** Construct a {@link FormErrorResult} (default status 500). */\nexport const errorResult = <A, Message>(\n message: string,\n status = 500,\n): FormActionResult<A, Message> => ({ _tag: \"Error\", status, message });\n","/**\n * @copyright Thomas Foster\n *\n * Low-level validation helpers — decode a value through a schema and get back\n * the {@link FormErrors} tree (or the list of {@link FormIssue}s) instead of a\n * raised failure. `Form.make` is the high-level entry; these are for ad\n * hoc field- or value-level validation (e.g. a Svelte client validating a\n * single field on blur).\n *\n * The second half of the module is per-field validators: {@link\n * SyncFieldValidator} / {@link AsyncFieldValidator} (bundled as {@link\n * FieldValidators}) are the framework-neutral shape a reactive store attaches\n * to one field, mirroring TanStack Form's `validators.onChange(Async)` /\n * `onBlur(Async)`. {@link runSyncFieldValidator} runs one synchronously;\n * {@link runAsyncFieldValidator} builds the debounced Effect an async one\n * runs as — the store is responsible for forking it into a fiber per field\n * and interrupting the previous fiber on every new run (see that function's\n * docs for why that alone gives debounce + \"latest wins\" cancellation).\n *\n * @module effect-forms/Validate\n */\n\nimport * as Duration from \"effect/Duration\";\nimport * as Effect from \"effect/Effect\";\nimport type * as Schema from \"effect/Schema\";\nimport * as SchemaParser from \"effect/SchemaParser\";\nimport { type FormErrors, issuesToErrors } from \"./Errors.ts\";\nimport {\n filterOutputToFormIssues,\n type FormIssue,\n type LeafFormatter,\n schemaIssuesToFormIssues,\n} from \"./Issues.ts\";\n\n/** The outcome of validating a value against a schema. */\nexport type ValidationResult<A> =\n | { readonly valid: true; readonly data: A }\n | {\n readonly valid: false;\n readonly errors: FormErrors;\n readonly issues: ReadonlyArray<FormIssue>;\n };\n\n/**\n * Decode `input` through `schema`, returning a {@link ValidationResult} on the\n * success channel (decode failures become `valid: false`, not an Effect\n * failure). Decoding-service requirements propagate on the `R` channel.\n */\nexport function validateValue<S extends Schema.Top>(\n schema: S,\n input: unknown,\n format?: LeafFormatter,\n): Effect.Effect<ValidationResult<S[\"Type\"]>, never, S[\"DecodingServices\"]> {\n return SchemaParser.decodeUnknownEffect(schema, { errors: \"all\" })(input).pipe(\n Effect.matchEffect({\n onSuccess: (data): Effect.Effect<ValidationResult<S[\"Type\"]>> =>\n Effect.succeed({ valid: true, data }),\n onFailure: (issue): Effect.Effect<ValidationResult<S[\"Type\"]>> => {\n const issues = schemaIssuesToFormIssues(issue, format);\n return Effect.succeed({ valid: false, errors: issuesToErrors(issues), issues });\n },\n }),\n );\n}\n\n/**\n * Synchronous {@link validateValue} for schemas with no decoding-service\n * requirements (`R = never`) and no async decoding — the common case for plain\n * form schemas. {@link validateValue} never fails on the error channel, so\n * running it with {@link Effect.runSync} is total.\n */\nexport function validateValueSync<S extends Schema.Top>(\n schema: S,\n input: unknown,\n format?: LeafFormatter,\n): ValidationResult<S[\"Type\"]> {\n // `validateValue` never fails on the error channel; the cast drops the\n // decoding-service requirement, which the caller asserts is `never` (the\n // common case for plain form schemas — a service-requiring schema must use\n // the async {@link validateValue}).\n return Effect.runSync(\n validateValue(schema, input, format) as Effect.Effect<ValidationResult<S[\"Type\"]>>,\n );\n}\n\n/**\n * A synchronous per-field validator — TanStack Form's `validators.onChange` /\n * `onBlur` shape. Sees the field's decoded value and returns a {@link\n * Schema.FilterOutput} (`undefined` / `true` to pass, a message / issue /\n * list to fail), the same vocabulary a schema `check` or a {@link\n * module:effect-forms/FormBuilder} `refine` predicate uses.\n */\nexport type SyncFieldValidator<A> = (value: A) => Schema.FilterOutput;\n\n/**\n * An asynchronous per-field validator — TanStack Form's `onChangeAsync` /\n * `onBlurAsync`. An Effect (not a `Promise`) so its `R` channel can demand\n * services (an API client, a cache) the way a {@link\n * module:effect-forms/FormBuilder} `refineEffect` refinement does; a caller\n * running this client-side supplies `R` via a `Layer` / runtime, or keeps it\n * `never` for a plain `fetch`-based check.\n */\nexport type AsyncFieldValidator<A, R = never> = (\n value: A,\n) => Effect.Effect<Schema.FilterOutput, never, R>;\n\n/**\n * The validators one field declares, mirroring TanStack Form's per-field\n * `validators` option. `asyncDebounceMs` (default `0`, meaning no debounce)\n * governs both async variants; see {@link runAsyncFieldValidator} for how the\n * debounce and cancellation actually work.\n */\nexport interface FieldValidators<A, R = never> {\n readonly onChange?: SyncFieldValidator<A>;\n readonly onBlur?: SyncFieldValidator<A>;\n readonly onChangeAsync?: AsyncFieldValidator<A, R>;\n readonly onBlurAsync?: AsyncFieldValidator<A, R>;\n readonly asyncDebounceMs?: number;\n}\n\n/**\n * Run a {@link SyncFieldValidator}, folding its {@link Schema.FilterOutput}\n * into {@link FormIssue}s (empty on success). Total — a sync field validator\n * cannot fail the Effect error channel.\n */\nexport function runSyncFieldValidator<A>(\n validator: SyncFieldValidator<A>,\n value: A,\n): ReadonlyArray<FormIssue> {\n return filterOutputToFormIssues(validator(value));\n}\n\n/**\n * Build the Effect an {@link AsyncFieldValidator} run is: sleep `debounceMs`\n * (a no-op at `0`, the default), then run `validator` and fold its output\n * into {@link FormIssue}s.\n *\n * The debounce is a plain {@link Effect.sleep}, so it rides Effect's `Clock`\n * — deterministic and instantly-advanceable under `TestClock` in tests, real\n * time otherwise (no `setTimeout` bookkeeping for a caller to manage).\n * \"Latest wins\" falls out of ordinary fiber interruption: a caller re-running\n * this on every keystroke forks a fresh fiber per call and interrupts the\n * previous one before forking the next — interrupting mid-sleep skips the\n * validator entirely (a true debounce, not just a discarded stale result),\n * and interrupting mid-validator aborts whatever the validator was doing\n * (e.g. an in-flight `fetch` wrapped as an Effect).\n */\nexport function runAsyncFieldValidator<A, R>(\n validator: AsyncFieldValidator<A, R>,\n value: A,\n debounceMs = 0,\n): Effect.Effect<ReadonlyArray<FormIssue>, never, R> {\n return Effect.gen(function* () {\n if (debounceMs > 0) yield* Effect.sleep(Duration.millis(debounceMs));\n const output = yield* validator(value);\n return filterOutputToFormIssues(output);\n });\n}\n\n/** Which trigger a {@link FieldValidators} sync/async pair reacts to. */\nexport type FieldTrigger = \"change\" | \"blur\";\n\n/** The validator(s) (if any) that apply for one field trigger — see {@link resolveFieldTrigger}. */\nexport interface ResolvedFieldTrigger<A, R = never> {\n readonly sync: SyncFieldValidator<A> | undefined;\n readonly async: AsyncFieldValidator<A, R> | undefined;\n readonly asyncDebounceMs: number;\n}\n\n/**\n * Pick `validators`' sync/async pair for `trigger` (TanStack's `onChange` /\n * `onBlur` vs `onChangeAsync` / `onBlurAsync`). A reactive store calls this\n * once per trigger instead of repeating the trigger ternary at each call\n * site — the pure decision half of what {@link module:effect-forms-svelte/FormStore}'s\n * field-trigger dispatch runs.\n */\nexport function resolveFieldTrigger<A, R = never>(\n validators: FieldValidators<A, R> | undefined,\n trigger: FieldTrigger,\n): ResolvedFieldTrigger<A, R> {\n return {\n sync: trigger === \"change\" ? validators?.onChange : validators?.onBlur,\n async: trigger === \"change\" ? validators?.onChangeAsync : validators?.onBlurAsync,\n asyncDebounceMs: validators?.asyncDebounceMs ?? 0,\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["replaceAt","filterOutputToFormIssues","make","issuesFromFilterOutput","make","makeFormState","filterOutputToFormIssues"],"sources":["../src/Coerce.ts","../src/Command.ts","../src/Constraints.ts","../src/FormData.ts","../src/Path.ts","../src/Errors.ts","../src/Field.ts","../src/Issues.ts","../src/FormBuilder.ts","../src/State.ts","../src/Form.ts","../src/Mode.ts","../src/Result.ts","../src/Validate.ts"],"sourcesContent":["/**\n * Tri-state coercers for the HTML-form boundary.\n *\n * An HTML form submits every value as a string, and an absent optional field\n * arrives as `undefined` (or an empty string). Mapping that onto a\n * value / `null` / `undefined` update contract — where a value **sets**, `null`\n * **clears** a nullable field, and `undefined` **skips** (carry-forward) — is\n * the same boundary discipline the host app applies, lifted here so any\n * consumer of the core gets it without a framework dependency.\n *\n * These are plain, total functions: they never throw and never reach for a\n * framework's `error()` helper (validation failures belong on the schema, not\n * in a coercer).\n *\n * @copyright Thomas Foster\n * @module effect-forms/Coerce\n */\n\n/** Empty string / `undefined` → `undefined`; otherwise the value (skip semantics). */\nexport function emptyToUndefined<T>(value: T | \"\" | undefined): T | undefined {\n return value === \"\" || value === undefined ? undefined : value;\n}\n\n/**\n * `undefined` stays `undefined` (skip); empty string / `null` → `null`\n * (clear a nullable field); otherwise the value (set). The three-state coercer\n * for nullable update fields.\n */\nexport function emptyToNull<T>(value: T | \"\" | null | undefined): T | null | undefined {\n if (value === undefined) return undefined;\n if (value === \"\" || value === null) return null;\n return value;\n}\n\n/** Trim, then {@link emptyToUndefined}: whitespace-only collapses to `undefined` (skip). */\nexport function trimToUndefined(value: string | undefined): string | undefined {\n return emptyToUndefined(value?.trim());\n}\n\n/** Trim, then {@link emptyToNull}: whitespace-only / blank clears (`null`). */\nexport function trimToNull(value: string | undefined): string | null | undefined {\n return emptyToNull(value?.trim());\n}\n\n/**\n * Map a numeric text field onto the value / `null` / `undefined` contract.\n * Blank clears on the nullable path and skips otherwise; a present value\n * parses with `Number` (`NaN` for non-numeric input — validate downstream).\n */\nexport function numberFromField(\n raw: string | undefined,\n options: { nullable: false },\n): number | undefined;\nexport function numberFromField(\n raw: string | undefined,\n options: { nullable: true },\n): number | null | undefined;\nexport function numberFromField(\n raw: string | undefined,\n { nullable }: { nullable: boolean },\n): number | null | undefined {\n const coerced = nullable ? emptyToNull(raw) : emptyToUndefined(raw);\n return typeof coerced === \"string\" ? Number(coerced) : coerced;\n}\n\n/**\n * Interpret a checkbox field. An HTML checkbox submits its `value` (default\n * `\"on\"`) only when checked and omits the field entirely when unchecked, so a\n * present field is `true` and an absent one is `false`. The truthy strings\n * `\"on\"` / `\"true\"` / `\"1\"` / `\"yes\"` all read as `true`; an explicit\n * `\"false\"` / `\"0\"` / `\"off\"` / `\"no\"` reads as `false`.\n */\nexport function booleanFromCheckbox(raw: string | undefined): boolean {\n if (raw === undefined) return false;\n const normalised = raw.trim().toLowerCase();\n return !(\n normalised === \"\" ||\n normalised === \"false\" ||\n normalised === \"0\" ||\n normalised === \"off\" ||\n normalised === \"no\"\n );\n}\n","/**\n * Command-struct introspection and form derivation.\n *\n * A host app's write surface is a pair of flat command `Schema.Struct`s per\n * entity — a create struct (required fields bare, the rest `optional`) and an\n * update struct (keyed by a required `id`, every field `optional`, clearable\n * fields `optional(NullOr(...))` carrying the value / `null` / `undefined`\n * tri-state). This module reads that pair into a plain-data {@link CommandPlan}\n * and derives the three per-entity form artefacts that were previously\n * hand-written per entity: the all-string Form-Input schema fields, the blank\n * defaults, and the tri-state adapters that map a validated multipart input\n * onto the encoded command payload.\n *\n * Classification leads with behavioural decode probes — date codecs are\n * transformations and branded ids erase to `String`, so \"what does this\n * schema accept\" is the only robust signal for those (the same approach the\n * host app's model walkers use). Two kinds fall back to AST matching instead,\n * because no decode probe can name what they are: `enum`'s literal option set\n * (needed anyway for the renderer, not just the classification) and\n * `structured`'s \"this is a nested object, not a scalar\" shape. Neither\n * shadows a probe-classified kind — see {@link classify}.\n *\n * The derived adapters emit the **encoded** command payload (dates stay\n * `YYYY-MM-DD` strings, ids stay plain strings) — the command's canonical\n * decode downstream owns branding and validation. Genuinely irregular fields\n * (a create-time default, an asymmetric coercion) stay expressible via the\n * per-field {@link AdaptOverrides} escape hatch instead of forcing ejection.\n *\n * @copyright Thomas Foster\n * @module effect-forms/Command\n */\n\nimport * as Schema from \"effect/Schema\";\nimport * as SchemaAST from \"effect/SchemaAST\";\nimport {\n emptyToNull,\n emptyToUndefined,\n numberFromField,\n trimToNull,\n trimToUndefined,\n} from \"./Coerce.ts\";\n\n/** How a command field renders and coerces at the form boundary. */\nexport type FieldKind =\n | \"text\"\n | \"id\"\n | \"number\"\n | \"date\"\n | \"jsonArray\"\n | \"boolean\"\n | \"enum\"\n | \"structured\";\n\n/** One command field's derived plan, as plain data. */\nexport interface FieldPlan {\n readonly key: string;\n readonly kind: FieldKind;\n /** Present on the create struct. */\n readonly inCreate: boolean;\n /** Bare (non-optional) on the create struct. */\n readonly createRequired: boolean;\n /** Present on the update struct. */\n readonly inUpdate: boolean;\n /** `optional(NullOr(...))` on the update struct — blank clears (`null`). */\n readonly updateClearable: boolean;\n /**\n * The field's literal option values, read off the AST — present only when\n * `kind` is `\"enum\"`. In declaration order, stringified (a `<select>`'s\n * option values are always strings at the form boundary, whatever the\n * decoded literal's own type).\n */\n readonly options?: readonly string[];\n}\n\n/** The derived plan for one entity's create/update command pair. */\nexport interface CommandPlan {\n /** Every field except `id`, in update-struct declaration order (create-only fields appended). */\n readonly fields: readonly FieldPlan[];\n /** The create struct carries an optional client-generated `id` (idempotent retries). */\n readonly clientId: boolean;\n}\n\n/** Per-field adapter overrides — the escape hatch for genuinely irregular coercion. */\nexport type AdaptOverrides = Readonly<Record<string, (raw: string | undefined) => unknown>>;\n\n/** A validated all-string multipart input, as the Form-Input schemas produce it. */\nexport type FormInputRecord = Readonly<Record<string, string | undefined>>;\n\n// ── probes ────────────────────────────────────────────────────────────\n\n/**\n * Run one decode probe: whether the schema accepts the input, plus the decoded\n * value for instance checks (the date probe needs to see a `Date` come out,\n * not just a successful decode).\n */\nconst probe = (\n schema: Schema.Top,\n input: unknown,\n): { readonly ok: boolean; readonly value?: unknown } => {\n try {\n return { ok: true, value: Schema.decodeUnknownSync(schema as Schema.Codec<unknown>)(input) };\n } catch {\n return { ok: false };\n }\n};\n\n/** True when a schema decodes the given input without throwing. */\nconst decodes = (schema: Schema.Top, input: unknown): boolean => probe(schema, input).ok;\n\n/** A syntactically valid UUID no other field kind accepts as non-text. */\nconst PROBE_UUID = \"9f8c1c2e-4b3a-4c5d-8e6f-0a1b2c3d4e5f\";\n\n/**\n * Peel exactly the `optional` / `NullOr` wrapper layers off a property's type\n * AST, stopping at the first union that isn't itself a pure wrapper. A wrapper\n * union carries exactly one non-`null`/`undefined` member (the wrapped type);\n * a union with zero or several such members is a real value-level union (an\n * `enum` field's own literal set, say) rather than another layer to peel, so\n * the loop stops there. Unlike {@link module:effect-forms/Constraints}'s\n * `unwrapOptional` (which only ever needs the *first* real member), this\n * walks every wrapper layer and preserves a multi-member union intact —\n * `enumOptions` below needs the full literal set, not just one branch of it.\n */\nfunction unwrapWrapperUnion(ast: SchemaAST.AST): SchemaAST.AST {\n let current = ast;\n while (SchemaAST.isUnion(current)) {\n const real = current.types.filter((t) => !SchemaAST.isUndefined(t) && !SchemaAST.isNull(t));\n if (real.length !== 1 || real.length === current.types.length) break;\n current = real[0];\n }\n return current;\n}\n\n/**\n * The literal option values of a field shaped like `Schema.Literal(...)` or\n * `Schema.Literals([...])` (optionally `optional` / `NullOr`-wrapped) —\n * `undefined` when the field isn't literal-shaped. Stringified: a `<select>`'s\n * option values are strings at the form boundary regardless of the literal's\n * own type.\n */\nfunction enumOptions(ast: SchemaAST.AST): readonly string[] | undefined {\n const inner = unwrapWrapperUnion(ast);\n if (SchemaAST.isLiteral(inner)) return [String(inner.literal)];\n if (SchemaAST.isUnion(inner)) {\n const literals = inner.types.filter(SchemaAST.isLiteral);\n if (literals.length === inner.types.length && literals.length > 0) {\n return literals.map((literal) => String(literal.literal));\n }\n }\n return undefined;\n}\n\n/**\n * Whether a field is itself an object/struct schema (optionally `optional` /\n * `NullOr`-wrapped) — the `structured` kind's shape (inline / block ProseKit\n * JSON: `{ type, content }`). Mirrors {@link module:effect-forms/Field}'s and\n * {@link module:effect-forms/Constraints}'s own `SchemaAST.isObjects` struct\n * check. A `Schema.declare`d type (`UploadedDocument`, `Image`) has no\n * `Objects` AST node, so it is never caught here — the default-throw the\n * derivation relies on stays intact.\n */\nfunction isStructured(ast: SchemaAST.AST): boolean {\n return SchemaAST.isObjects(unwrapWrapperUnion(ast));\n}\n\n/** One field's classification: its {@link FieldKind}, plus `options` for `\"enum\"`. */\ninterface Classification {\n readonly kind: FieldKind;\n readonly options?: readonly string[];\n}\n\n/**\n * The scalar kinds classified purely by what a schema decodes, with no AST\n * inspection: array → boolean → number → date → id → text. `undefined` when\n * the schema accepts none of them, so {@link classify} can fall through to\n * its AST-based checks (`enum`, `structured`).\n */\nconst probeKind = (schema: Schema.Top): FieldKind | undefined => {\n if (decodes(schema, [])) return \"jsonArray\";\n if (decodes(schema, true)) return \"boolean\";\n if (decodes(schema, 42)) return \"number\";\n const date = probe(schema, \"2024-01-02T03:04:05.000Z\");\n if (date.ok && date.value instanceof Date) return \"date\";\n if (decodes(schema, PROBE_UUID) && !decodes(schema, \"not-a-uuid\")) return \"id\";\n if (decodes(schema, \"plain text\")) return \"text\";\n return undefined;\n};\n\n/**\n * Classify one field schema: by its AST shape first, then by what it accepts.\n * `enum` is checked before {@link probeKind} rather than after, since a\n * decode probe can't tell \"the literal set an enum accepts\" from any other\n * shape (worse, a numeric-literal enum whose set happens to include the `42`\n * probe value would otherwise misclassify as `number`) — reading the literal\n * set off the AST is unambiguous, and it's needed anyway for the renderer.\n * `structured` is checked last, after every probe has failed: an object\n * schema never decodes any of `probeKind`'s scalar probes, so there is no\n * real ordering hazard, but putting the broadest, AST-only check last keeps\n * every more specific kind first in line. A field that matches nothing\n * (`Schema.declare`d — `UploadedDocument`, `Image`) throws at module load so\n * the gap surfaces when the plan is declared, not on a live submission.\n */\nconst classify = (key: string, schema: Schema.Top): Classification => {\n const options = enumOptions(schema.ast);\n if (options !== undefined) return { kind: \"enum\", options };\n const probed = probeKind(schema);\n if (probed !== undefined) return { kind: probed };\n if (isStructured(schema.ast)) return { kind: \"structured\" };\n throw new Error(\n `Command.plan: field \"${key}\" matches no known kind (text/id/number/date/jsonArray/boolean/enum/structured) — a Schema.declare'd type needs an explicit form-level treatment before it can derive`,\n );\n};\n\n// ── plan ──────────────────────────────────────────────────────────────\n\n/** Minimal runtime shape of a command `Schema.Struct`. */\ninterface StructLike {\n readonly fields: Record<string, Schema.Top>;\n}\n\n/**\n * Read a create/update command struct pair into a {@link CommandPlan}.\n * Runs once at module load — probe cost is a handful of tiny decodes per\n * field, never per render or per request.\n */\nexport const plan = (create: StructLike, update: StructLike): CommandPlan => {\n const createFields = create.fields;\n const updateFields = update.fields;\n const keys: string[] = [];\n for (const key in updateFields) if (key !== \"id\") keys.push(key);\n for (const key in createFields) if (key !== \"id\" && !(key in updateFields)) keys.push(key);\n\n const fields = keys.map((key): FieldPlan => {\n const createField = createFields[key];\n const updateField = updateFields[key];\n const probeTarget = (createField ?? updateField) as Schema.Top;\n const { kind, options } = classify(key, probeTarget);\n return {\n key,\n kind,\n inCreate: createField !== undefined,\n createRequired: createField !== undefined && !decodes(createField, undefined),\n inUpdate: updateField !== undefined,\n updateClearable: updateField !== undefined && decodes(updateField, null),\n ...(options !== undefined ? { options } : {}),\n };\n });\n\n return { fields, clientId: \"id\" in createFields };\n};\n\n// ── Form-Input schema fields ──────────────────────────────────────────\n\n/**\n * Derive the all-string Form-Input schema fields for one mode — every value is\n * a string at the multipart boundary. Create-required fields get a min-length\n * check so blankness surfaces as an inline field error; the update `id` gets\n * the UUID check. Spread into `Schema.Struct({ ...Command.formInputFields(plan,\n * \"create\") })`, with `overrides` spread last for irregular fields.\n */\nexport const formInputFields = (\n commandPlan: CommandPlan,\n mode: \"create\" | \"update\",\n overrides: Readonly<Record<string, Schema.Top>> = {},\n): Record<string, Schema.Top> => {\n const fields: Record<string, Schema.Top> = {};\n if (mode === \"create\" && commandPlan.clientId) fields.id = Schema.optional(Schema.String);\n if (mode === \"update\") fields.id = Schema.String.check(Schema.isUUID());\n for (const field of commandPlan.fields) {\n if (mode === \"create\" ? !field.inCreate : !field.inUpdate) continue;\n fields[field.key] =\n mode === \"create\" && field.createRequired\n ? Schema.String.check(Schema.isMinLength(1))\n : Schema.optional(Schema.String);\n }\n return { ...fields, ...overrides };\n};\n\n/**\n * Blank string defaults for one mode's Form-Input shape. Client-id entities\n * override `id` at the call site (`{ ...blankDefaults(plan, \"create\"), id:\n * crypto.randomUUID() }`) so retries stay idempotent.\n */\nexport const blankDefaults = (\n commandPlan: CommandPlan,\n mode: \"create\" | \"update\",\n): Record<string, string> => {\n const defaults: Record<string, string> = {};\n if (mode === \"update\" || commandPlan.clientId) defaults.id = \"\";\n for (const field of commandPlan.fields) {\n if (mode === \"create\" ? !field.inCreate : !field.inUpdate) continue;\n defaults[field.key] = \"\";\n }\n return defaults;\n};\n\n// ── adapters ──────────────────────────────────────────────────────────\n\n/**\n * Parse a JSON-encoded row list (a contributor list) from a multipart form\n * field. A blank or absent field yields `undefined` (skip — leave the existing\n * list untouched); an empty JSON array (`\"[]\"`) clears the list. Rows keep\n * `id` / `creditedName` when present; `orderingPosition` falls back to the\n * row's array index. Throws a plain `Error` on a malformed payload — mapping\n * that onto a framework response is the caller's concern.\n */\nexport const jsonRowsFromField = (\n raw: string | undefined,\n label: string,\n):\n | {\n id?: string | undefined;\n agentId: string;\n creditedName?: string | undefined;\n orderingPosition: number;\n }[]\n | undefined => {\n if (raw === undefined || raw.trim() === \"\") return undefined;\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n throw new Error(`Invalid ${label} payload — expected JSON array`);\n }\n if (!Array.isArray(parsed)) {\n throw new Error(`Invalid ${label} payload — expected array`);\n }\n return parsed.map((row, index) => {\n if (typeof row !== \"object\" || row === null) {\n throw new Error(`Invalid ${label} entry at index ${index}`);\n }\n const r = row as Record<string, unknown>;\n if (typeof r.agentId !== \"string\") {\n throw new Error(`${label} entry at index ${index} missing agentId`);\n }\n return {\n id: typeof r.id === \"string\" ? r.id : undefined,\n agentId: r.agentId,\n creditedName: typeof r.creditedName === \"string\" ? r.creditedName : undefined,\n orderingPosition: typeof r.orderingPosition === \"number\" ? r.orderingPosition : index,\n };\n });\n};\n\n/** Coercion context for one field in one mode. */\ninterface CoerceContext {\n /** Required at create: emit the raw value's canonical form, never skip. */\n readonly required: boolean;\n /** Blank clears (`null`) rather than skips (`undefined`). */\n readonly clearable: boolean;\n /** Trim before the create-mode blank check (dates trim only at create). */\n readonly trimCreate: boolean;\n}\n\n/** Text fields: trim always; required create fields never skip. */\nconst coerceText = (ctx: CoerceContext, raw: string | undefined): unknown =>\n ctx.required ? (raw ?? \"\").trim() : ctx.clearable ? trimToNull(raw) : trimToUndefined(raw);\n\n/** Id fields: no trimming (pickers emit `\"\"` or a UUID); required create FKs pass through raw. */\nconst coerceId = (ctx: CoerceContext, raw: string | undefined): unknown =>\n ctx.required ? raw : ctx.clearable ? emptyToNull(raw) : emptyToUndefined(raw);\n\n/** Numeric text fields: blank clears on the clearable path, skips otherwise. */\nconst coerceNumber = (ctx: CoerceContext, raw: string | undefined): unknown =>\n ctx.clearable\n ? numberFromField(raw, { nullable: true })\n : numberFromField(raw, { nullable: false });\n\n/** Date fields stay encoded (`YYYY-MM-DD` strings); create trims, update passes through. */\nconst coerceDate = (ctx: CoerceContext, raw: string | undefined): unknown => {\n const value = ctx.trimCreate ? raw?.trim() : raw;\n return ctx.clearable ? emptyToNull(value) : emptyToUndefined(value);\n};\n\n/**\n * Boolean fields: a `<select>`'s value set, not a checkbox — the only truthy\n * raw value is the literal string `\"true\"`, everything else (`\"false\"`,\n * blank, absent) reads as `false`. Create defaults an absent/blank field to\n * `false` (never skips); update skips absent/blank unless clearable, in which\n * case it clears (`null`) instead — the create-defaults / update-skips\n * asymmetry the Content family already hand-writes.\n */\nconst coerceBoolean = (ctx: CoerceContext, raw: string | undefined): unknown => {\n const trimmed = raw?.trim();\n if (trimmed === undefined || trimmed === \"\") {\n return ctx.required ? false : ctx.clearable ? null : undefined;\n }\n return trimmed === \"true\";\n};\n\n/**\n * Parse a JSON-encoded structured document (inline / block ProseKit JSON)\n * from a multipart field. Blank or absent skips (`undefined`) or, on the\n * clearable path, clears (`null`); a present value is `JSON.parse`d and\n * passed through as-is — shape validation is the command's own decode's job,\n * exactly as {@link jsonRowsFromField} leaves row-shape validation to itself\n * rather than duplicating it here. `JSON.parse` throws a `SyntaxError` on\n * malformed JSON, same as {@link jsonRowsFromField} does on a malformed row\n * list — mapping that onto a framework response is the caller's concern.\n */\nconst structuredFromField = (raw: string | undefined, clearable: boolean): unknown => {\n const trimmed = raw?.trim();\n if (trimmed === undefined || trimmed === \"\") return clearable ? null : undefined;\n return JSON.parse(trimmed);\n};\n\n/** Build one field's {@link CoerceContext} for one mode. */\nconst coerceContextFor = (field: FieldPlan, mode: \"create\" | \"update\"): CoerceContext => ({\n required: mode === \"create\" && field.createRequired,\n clearable: mode === \"update\" && field.updateClearable,\n trimCreate: mode === \"create\",\n});\n\n/** The default coercion for one field in one mode. */\nconst coerce = (field: FieldPlan, mode: \"create\" | \"update\", raw: string | undefined): unknown => {\n const ctx = coerceContextFor(field, mode);\n switch (field.kind) {\n case \"text\":\n case \"enum\":\n return coerceText(ctx, raw);\n case \"id\":\n return coerceId(ctx, raw);\n case \"number\":\n return coerceNumber(ctx, raw);\n case \"date\":\n return coerceDate(ctx, raw);\n case \"jsonArray\":\n return jsonRowsFromField(raw, field.key);\n case \"boolean\":\n return coerceBoolean(ctx, raw);\n case \"structured\":\n return structuredFromField(raw, ctx.clearable);\n }\n};\n\n/**\n * Derive the create adapter: validated all-string input → encoded create\n * command payload. `overrides` replace the default per-field coercion for\n * genuinely irregular fields (e.g. a create-time fallback default).\n */\nexport const createAdapter =\n (commandPlan: CommandPlan, overrides: AdaptOverrides = {}) =>\n (input: FormInputRecord): Record<string, unknown> => {\n const out: Record<string, unknown> = {};\n if (commandPlan.clientId) out.id = trimToUndefined(input.id);\n for (const field of commandPlan.fields) {\n if (!field.inCreate) continue;\n const override = overrides[field.key];\n out[field.key] = override\n ? override(input[field.key])\n : coerce(field, \"create\", input[field.key]);\n }\n return out;\n };\n\n/**\n * Derive the update adapter: validated all-string input → encoded update\n * command payload (value sets, `null` clears a clearable field, `undefined`\n * skips). The required `id` passes through as-is — the command's canonical\n * decode brands it.\n */\nexport const updateAdapter =\n (commandPlan: CommandPlan, overrides: AdaptOverrides = {}) =>\n (input: FormInputRecord): Record<string, unknown> => {\n const out: Record<string, unknown> = { id: input.id };\n for (const field of commandPlan.fields) {\n if (!field.inUpdate) continue;\n const override = overrides[field.key];\n out[field.key] = override\n ? override(input[field.key])\n : coerce(field, \"update\", input[field.key]);\n }\n return out;\n };\n","/**\n * HTML input constraints derived from an Effect Schema.\n *\n * Native validation attributes can be read (`required`, `minlength`, …)\n * off the schema so a form can apply them to its inputs for free, layering\n * browser-native validation under the schema-driven validation. This module\n * does the framework-neutral half: walk the schema AST and emit an\n * {@link InputConstraints} tree a UI can spread onto its `<input>`s.\n *\n * `required` comes from a struct field's optionality; `minlength` /\n * `maxlength` / `min` / `max` / `pattern` / `step` are derived from the\n * `representation` annotation Effect Schema's built-in checks carry\n * (`isMinLength`, `isBetween`, `isPattern`, …), keyed by its stable\n * `effect/schema/<check>` id. A check with no recognised representation id\n * (a bare `Schema.filter` predicate, a custom `.check()`) contributes\n * nothing; there is no attribute to guess at,\n * so the derivation stays silent rather than wrong. The walk descends into\n * nested structs and into a homogeneous array's item type (folding the\n * array's own optionality into the item's `required`); a fixed-shape tuple\n * with differently-typed elements has no single item schema to represent as\n * one constraint, so it derives only `required`. Like\n * {@link module:effect-forms/Field}'s `fromAst`, an `optional` / `NullOr`\n * union is unwrapped by taking its first non-`null`/`undefined` member —\n * scoped to that wrapping pattern, not general discriminated unions, whose\n * branches can't be flattened into one constraint either. The `overrides`\n * argument to {@link constraintsFromSchema} remains the seam for anything the\n * walk cannot infer (or should not — a check that's semantically stronger\n * than any HTML attribute).\n *\n * @copyright Thomas Foster\n * @module effect-forms/Constraints\n */\n\nimport type * as Schema from \"effect/Schema\";\nimport * as SchemaAST from \"effect/SchemaAST\";\nimport type * as SchemaRepresentation from \"effect/SchemaRepresentation\";\nimport type { FormPath } from \"./Issues.ts\";\n\n/** Native validation attributes for a single input. */\nexport interface InputConstraint {\n readonly required?: boolean;\n readonly min?: number | string;\n readonly max?: number | string;\n readonly minlength?: number;\n readonly maxlength?: number;\n readonly pattern?: string;\n readonly step?: number;\n}\n\n/** A nested tree of {@link InputConstraint}s mirroring the schema's shape. */\nexport interface InputConstraints {\n readonly [key: string]: InputConstraint | InputConstraints | undefined;\n}\n\n/** Whether a node in an {@link InputConstraints} tree is a leaf ({@link InputConstraint}) rather than a branch. */\nexport const isLeafConstraint = (\n value: InputConstraint | InputConstraints,\n): value is InputConstraint =>\n \"required\" in value ||\n \"min\" in value ||\n \"max\" in value ||\n \"minlength\" in value ||\n \"maxlength\" in value ||\n \"pattern\" in value ||\n \"step\" in value;\n\n/** Whether a property's type AST is optional (so the field is not required). */\nconst isOptional = (type: SchemaAST.AST): boolean => type.context?.isOptional === true;\n\n/**\n * Unwrap an `optional` / `NullOr` union the way {@link module:effect-forms/Field}'s\n * `fromAst` does: recurse into the first member that isn't a bare `undefined`\n * / `null` literal, so a wrapped struct / array / refined leaf still yields\n * its own shape instead of falling through to an empty constraint.\n */\nfunction unwrapOptional(type: SchemaAST.AST): SchemaAST.AST {\n if (!SchemaAST.isUnion(type)) return type;\n for (const member of type.types) {\n if (SchemaAST.isUndefined(member) || SchemaAST.isNull(member)) continue;\n return unwrapOptional(member);\n }\n return type;\n}\n\n/** Flatten a `Checks` array (recursing into `FilterGroup`s) into individual filters. */\nfunction flattenChecks(\n checks: SchemaAST.Checks | undefined,\n out: Array<SchemaAST.Filter<unknown>>,\n): void {\n if (!checks) return;\n for (const check of checks) {\n if (check._tag === \"FilterGroup\") {\n flattenChecks(check.checks as SchemaAST.Checks, out);\n } else {\n out.push(check as SchemaAST.Filter<unknown>);\n }\n }\n}\n\n/** A same-shape, mutable patch of {@link InputConstraint} fields. */\ntype ConstraintPatch = { -readonly [K in keyof InputConstraint]?: InputConstraint[K] };\n\n/**\n * The `representation.payload` shapes of the built-in checks that map onto a\n * native HTML attribute, keyed by the check's stable representation id.\n * Mirrors each check constructor in `effect/Schema` (e.g. `isMinLength`\n * writes `{ id: \"effect/schema/isMinLength\", payload: { minLength } }`).\n */\ninterface CheckPayloads {\n readonly \"effect/schema/isMinLength\": { readonly minLength: number };\n readonly \"effect/schema/isMaxLength\": { readonly maxLength: number };\n readonly \"effect/schema/isBetweenLength\": { readonly minimum: number; readonly maximum: number };\n readonly \"effect/schema/isPattern\": { readonly source: string; readonly flags: string };\n readonly \"effect/schema/isGreaterThan\": { readonly exclusiveMinimum: number };\n readonly \"effect/schema/isGreaterThanOrEqualTo\": { readonly minimum: number };\n readonly \"effect/schema/isLessThan\": { readonly exclusiveMaximum: number };\n readonly \"effect/schema/isLessThanOrEqualTo\": { readonly maximum: number };\n readonly \"effect/schema/isBetween\": { readonly minimum: number; readonly maximum: number };\n readonly \"effect/schema/isMultipleOf\": { readonly divisor: number };\n}\n\n/**\n * One constraint patch per recognised representation id — the built-in\n * checks that map onto a native HTML attribute. An id with no entry here\n * (an unannotated custom filter, or a built-in check with no HTML\n * equivalent) derives nothing. `isInt` isn't a plain patch: it only sets\n * `step` as a fallback when nothing more specific already did, so it's\n * handled separately in {@link constraintFromChecks}.\n */\nconst payloadPatches: {\n readonly [K in keyof CheckPayloads]: (payload: CheckPayloads[K]) => ConstraintPatch;\n} = {\n \"effect/schema/isMinLength\": (p) => ({ minlength: p.minLength }),\n \"effect/schema/isMaxLength\": (p) => ({ maxlength: p.maxLength }),\n \"effect/schema/isBetweenLength\": (p) => ({ minlength: p.minimum, maxlength: p.maximum }),\n \"effect/schema/isPattern\": (p) => ({ pattern: p.source }),\n \"effect/schema/isGreaterThan\": (p) => ({ min: p.exclusiveMinimum }),\n \"effect/schema/isGreaterThanOrEqualTo\": (p) => ({ min: p.minimum }),\n \"effect/schema/isLessThan\": (p) => ({ max: p.exclusiveMaximum }),\n \"effect/schema/isLessThanOrEqualTo\": (p) => ({ max: p.maximum }),\n \"effect/schema/isBetween\": (p) => ({ min: p.minimum, max: p.maximum }),\n \"effect/schema/isMultipleOf\": (p) => ({ step: p.divisor }),\n};\n\n/**\n * Look up and apply `payloadPatches[representation.id]`. The cast is sound:\n * each payload is authored by the same built-in check constructor its id\n * names, so an entry is never called with a mismatched payload shape.\n */\nfunction applyPayloadPatch(\n representation: SchemaRepresentation.RepresentationAnnotation,\n): ConstraintPatch | undefined {\n const patch = payloadPatches[representation.id as keyof CheckPayloads] as\n | ((payload: Schema.Json) => ConstraintPatch)\n | undefined;\n return patch?.(representation.payload);\n}\n\n/**\n * Derive an {@link InputConstraint}'s refinement attributes from the checks\n * attached to `outer` (the property's own type, e.g. the union wrapping an\n * optional field) and `inner` (the unwrapped leaf) — `inner`'s checks win on\n * conflict since they're the more specific, unwrapped node. A check whose\n * `representation` annotation has no recognised id (an unannotated custom\n * filter) is skipped: there is no attribute to derive from it.\n */\nfunction constraintFromChecks(outer: SchemaAST.AST, inner: SchemaAST.AST): InputConstraint {\n const filters: Array<SchemaAST.Filter<unknown>> = [];\n flattenChecks(outer.checks, filters);\n if (inner !== outer) flattenChecks(inner.checks, filters);\n\n let out: ConstraintPatch = {};\n let hasIntCheck = false;\n for (const filter of filters) {\n const representation = filter.annotations?.representation;\n if (!representation) continue;\n if (representation.id === \"effect/schema/isInt\") {\n hasIntCheck = true;\n continue;\n }\n out = { ...out, ...applyPayloadPatch(representation) };\n }\n if (hasIntCheck && out.step === undefined) out.step = 1;\n\n return out;\n}\n\n/**\n * Whether `ast` is a homogeneous array/list — `Schema.Array(item)` or\n * `Schema.NonEmptyArray(item)` — as opposed to a fixed-shape tuple with\n * differently-typed positional elements. Only a homogeneous array has a\n * single item schema to descend into; a tuple's elements each need their own\n * constraint, which this leaf-per-key tree can't represent, so it's left to\n * `overrides`.\n */\nfunction homogeneousItem(ast: SchemaAST.Arrays): SchemaAST.AST | undefined {\n if (ast.rest.length !== 1) return undefined;\n const [item] = ast.rest;\n if (ast.elements.length === 0) return item;\n if (ast.elements.length === 1 && ast.elements[0] === item) return item;\n return undefined;\n}\n\n/**\n * Derive the constraint (or nested tree) for one property/item type: a\n * struct descends into its properties, a homogeneous array descends into its\n * item type (the array's own length checks have no native equivalent for a\n * repeated field, so they're not derived) while folding the array's own\n * optionality into the item's `required`, and anything else is a leaf whose\n * `required` comes from optionality and whose refinement attributes come\n * from {@link constraintFromChecks}.\n */\nfunction constraintsForType(type: SchemaAST.AST): InputConstraint | InputConstraints {\n const required = !isOptional(type);\n const inner = unwrapOptional(type);\n if (SchemaAST.isObjects(inner)) {\n return constraintsForObjects(inner);\n }\n if (SchemaAST.isArrays(inner)) {\n const item = homogeneousItem(inner);\n if (!item) return { required };\n const itemConstraints = constraintsForType(item);\n return isLeafConstraint(itemConstraints)\n ? { ...itemConstraints, required: required && itemConstraints.required !== false }\n : itemConstraints;\n }\n return { required, ...constraintFromChecks(type, inner) };\n}\n\n/** Build the constraint tree for one object AST node. */\nfunction constraintsForObjects(ast: SchemaAST.Objects): InputConstraints {\n const out: Record<string, InputConstraint | InputConstraints> = {};\n for (const ps of ast.propertySignatures) {\n out[String(ps.name)] = constraintsForType(ps.type);\n }\n return out;\n}\n\n/** Deep-merge constraint overrides over a derived tree. */\nfunction mergeConstraints(base: InputConstraints, overrides: InputConstraints): InputConstraints {\n const out: Record<string, InputConstraint | InputConstraints | undefined> = { ...base };\n for (const key of Object.keys(overrides)) {\n const override = overrides[key];\n if (override === undefined) continue;\n const existing = out[key];\n if (existing !== undefined && !isLeafConstraint(existing) && !isLeafConstraint(override)) {\n out[key] = mergeConstraints(existing, override);\n } else if (existing !== undefined && isLeafConstraint(existing) && isLeafConstraint(override)) {\n out[key] = { ...existing, ...override };\n } else {\n out[key] = override;\n }\n }\n return out;\n}\n\n/**\n * Derive the {@link InputConstraints} for a struct schema. Non-struct schemas\n * yield an empty tree. `overrides` (deep-merged over the derived tree, and\n * winning on conflict) is the seam for anything the AST walk does not infer.\n */\nexport function constraintsFromSchema(\n schema: Schema.Top,\n overrides: InputConstraints = {},\n): InputConstraints {\n const ast = schema.ast;\n const base = SchemaAST.isObjects(ast) ? constraintsForObjects(ast) : {};\n return mergeConstraints(base, overrides);\n}\n\n/**\n * Read the {@link InputConstraint} leaf at `path` in an {@link InputConstraints}\n * tree, defaulting to `{}` when `path` has no derived constraints. Array\n * indices in `path` are skipped rather than descended into — the tree has no\n * per-item nodes to index into, since {@link constraintsForType} derives one\n * constraint (or branch) per *field*, shared by every item at that field. A\n * bare item path (`tags[0]`) resolves to that shared leaf; a path that\n * continues past the index into a struct item's own field (`items[0].label`)\n * skips the index and resolves straight to `label`'s derived constraint.\n */\nexport function constraintAt(constraints: InputConstraints, path: FormPath): InputConstraint {\n let node: InputConstraint | InputConstraints | undefined = constraints;\n for (const segment of path) {\n if (typeof segment === \"number\") continue;\n if (node === undefined || isLeafConstraint(node)) return {};\n node = node[segment];\n }\n return node !== undefined && isLeafConstraint(node) ? node : {};\n}\n","/**\n * Structured parsing of an HTML form body into a plain object the schema can\n * decode.\n *\n * Browsers flatten structured data into `name=value` pairs using bracket /\n * dot path notation (`author.name`, `author[name]`, `tags[0]`, `tags[]`).\n * {@link formDataToObject} reverses that into a nested object / array tree —\n * the framework-neutral step that turns a form body into structured data, before handing it\n * to a validator. Coercion (strings → numbers / booleans / dates) is then the\n * schema's job: decode the result with a schema built from coercing leaves\n * (`Schema.FiniteFromString`, `Schema.BooleanFromString`, the {@link\n * module:effect-forms/Coerce} helpers, …).\n *\n * `File` values pass through untouched; repeated bare keys collapse into an\n * array. The parser is total and never throws.\n *\n * @copyright Thomas Foster\n * @module effect-forms/FormData\n */\n\n/** Anything that can be parsed into a structured form object. */\nexport type FormBodySource =\n | FormData\n | URLSearchParams\n | Iterable<readonly [string, FormDataEntryValue | string]>;\n\ntype Container = Record<string, unknown> | unknown[];\n\n/**\n * Split a flat field name into its path tokens. Supports dot notation\n * (`a.b`), bracket notation (`a[b]`, `a[0]`), and the trailing append form\n * (`a[]`, represented by an empty-string token). `\"a[b][0]\"` → `[\"a\",\"b\",\"0\"]`;\n * `\"a.b[]\"` → `[\"a\",\"b\",\"\"]`.\n */\nexport function parseFieldPath(name: string): string[] {\n const tokens: string[] = [];\n let buffer = \"\";\n let inBracket = false;\n for (const char of name) {\n if (char === \"[\") {\n if (buffer !== \"\") tokens.push(buffer);\n buffer = \"\";\n inBracket = true;\n } else if (char === \"]\") {\n tokens.push(buffer);\n buffer = \"\";\n inBracket = false;\n } else if (char === \".\" && !inBracket) {\n if (buffer !== \"\") tokens.push(buffer);\n buffer = \"\";\n } else {\n buffer += char;\n }\n }\n if (buffer !== \"\") tokens.push(buffer);\n // A leading empty token can appear for names like `[0]`; drop it.\n return tokens.length > 1 && tokens[0] === \"\" ? tokens.slice(1) : tokens;\n}\n\nconst isIndexToken = (token: string): boolean => token === \"\" || /^\\d+$/.test(token);\n\n/** Create the container a token should live in: array for index/append tokens. */\nconst makeContainer = (nextToken: string): Container => (isIndexToken(nextToken) ? [] : {});\n\nconst setOnContainer = (container: Container, token: string, value: unknown): void => {\n if (Array.isArray(container)) {\n if (token === \"\") container.push(value);\n else container[Number(token)] = value;\n } else {\n (container as Record<string, unknown>)[token] = value;\n }\n};\n\nconst getFromContainer = (container: Container, token: string): unknown =>\n Array.isArray(container)\n ? container[Number(token)]\n : (container as Record<string, unknown>)[token];\n\n/** Assign `value` deep into `root` along `tokens`, creating containers as needed. */\nfunction assign(root: Container, tokens: string[], value: unknown): void {\n let node: Container = root;\n for (let i = 0; i < tokens.length - 1; i++) {\n const token = tokens[i];\n const nextToken = tokens[i + 1];\n let child = token === \"\" ? undefined : getFromContainer(node, token);\n if (child === undefined || typeof child !== \"object\" || child === null) {\n child = makeContainer(nextToken);\n setOnContainer(node, token, child);\n }\n node = child as Container;\n }\n const last = tokens[tokens.length - 1];\n // A repeated bare key (no brackets) collapses into an array.\n if (last !== \"\" && !Array.isArray(node)) {\n const existing = getFromContainer(node, last);\n if (existing !== undefined) {\n const arr = Array.isArray(existing) ? existing : [existing];\n arr.push(value);\n setOnContainer(node, last, arr);\n return;\n }\n }\n setOnContainer(node, last, value);\n}\n\n/** Normalise a source into `[name, value]` entries. */\nfunction* entriesOf(source: FormBodySource): Generator<readonly [string, unknown]> {\n if (\n typeof (source as Iterable<unknown>)[Symbol.iterator] === \"function\" &&\n !(source instanceof FormData) &&\n !(source instanceof URLSearchParams)\n ) {\n yield* source as Iterable<readonly [string, unknown]>;\n return;\n }\n for (const entry of (source as FormData | URLSearchParams).entries()) yield entry;\n}\n\n/**\n * Parse a form body into a nested object / array tree. Field names use dot or\n * bracket path notation (see {@link parseFieldPath}); repeated bare keys\n * become arrays; `File` values pass through. The result is ready to hand to\n * `Schema.decodeUnknown` with a schema whose leaves coerce the string inputs.\n */\nexport function formDataToObject(source: FormBodySource): Record<string, unknown> {\n const root: Record<string, unknown> = {};\n for (const [name, value] of entriesOf(source)) {\n const tokens = parseFieldPath(name);\n if (tokens.length === 0) continue;\n assign(root, tokens, value);\n }\n return root;\n}\n\n/** Read and parse a `Request`'s form body. Errors (e.g. wrong content-type) reject. */\nexport async function requestToObject(request: Request): Promise<Record<string, unknown>> {\n const formData = await request.formData();\n return formDataToObject(formData);\n}\n","/**\n * Nested get / set along a {@link FormPath}.\n *\n * A form's data is a tree, and the reactive bindings address it by path:\n * `[\"author\", \"name\"]`, `[\"tags\", 0]`. This module reads and writes a value\n * at such a path — {@link getAt} descends, {@link setAt} returns a new tree\n * with the value replaced (structural sharing, never a mutation) so a rune /\n * atom store can diff cheaply. It is the framework-neutral half of the\n * reactive field bindings (the Svelte store leans on it for\n * `setValue` and the array operations).\n *\n * Paths are {@link FormPath}s — the same array-of-segments the {@link\n * module:effect-forms/Errors} tree and {@link module:effect-forms/Issues}\n * walker already speak — so string keys address object properties and number\n * segments address array indices. {@link toString} / {@link fromString}\n * convert to and from the flat `author.name` / `tags[0]` notation the HTML\n * body parser ({@link module:effect-forms/FormData}) uses.\n *\n * @copyright Thomas Foster\n * @module effect-forms/Path\n */\n\nimport { parseFieldPath } from \"./FormData.ts\";\nimport type { FormPath } from \"./Issues.ts\";\n\n/**\n * Read the value at `path`. Returns `undefined` if any segment is missing or\n * traverses a non-object. The empty path returns the object itself.\n */\nexport function getAt(obj: unknown, path: FormPath): unknown {\n let current = obj;\n for (const segment of path) {\n if (current === null || typeof current !== \"object\") return undefined;\n current = (current as Record<string | number, unknown>)[segment];\n }\n return current;\n}\n\n/**\n * Return a new tree with the value at `path` replaced by `value`. Objects and\n * arrays along the path are cloned (structural sharing elsewhere); missing\n * containers are created as arrays for numeric segments and objects otherwise.\n * The empty path returns `value`. Pure — `obj` is never mutated.\n */\nexport function setAt<T>(obj: T, path: FormPath, value: unknown): T {\n if (path.length === 0) return value as T;\n\n const [head, ...rest] = path;\n const clone = (\n Array.isArray(obj) ? [...(obj as unknown[])] : { ...(obj as Record<string, unknown>) }\n ) as Record<string | number, unknown>;\n\n const child = clone[head];\n clone[head] =\n rest.length === 0\n ? value\n : setAt(\n child === null || typeof child !== \"object\"\n ? typeof rest[0] === \"number\"\n ? []\n : {}\n : child,\n rest,\n value,\n );\n\n return clone as T;\n}\n\n/** Whether `path` is `root` or nested beneath it. */\nexport function isUnder(path: FormPath, root: FormPath): boolean {\n if (path.length < root.length) return false;\n for (let i = 0; i < root.length; i++) {\n if (path[i] !== root[i]) return false;\n }\n return true;\n}\n\n/**\n * Render a {@link FormPath} as flat field-name notation: string segments join\n * with `.` and number segments become `[n]` (`[\"tags\", 0]` → `\"tags[0]\"`).\n * The inverse of {@link fromString}.\n */\nexport function toString(path: FormPath): string {\n let out = \"\";\n for (const segment of path) {\n if (typeof segment === \"number\") out += `[${segment}]`;\n else out += out === \"\" ? segment : `.${segment}`;\n }\n return out;\n}\n\n/**\n * Parse flat field-name notation into a {@link FormPath}: integer tokens become\n * number segments (array indices), everything else stays a string. The inverse\n * of {@link toString}.\n */\nexport function fromString(name: string): FormPath {\n return parseFieldPath(name).map((token) => (/^\\d+$/.test(token) ? Number(token) : token));\n}\n\n/**\n * The deep-key type: every valid {@link toString} path into `T`, as a union of\n * string literals (`\"author.name\"`, `\"tags[0]\"`, `\"tags[0].label\"`, …). This is\n * the type-checked counterpart of a hand-written {@link FormPath} — a typo'd\n * segment or a path into a field that doesn't exist is a compile error. Bounded\n * to a fixed recursion depth ({@link Prev}'s length) so a struct with cycles\n * (there shouldn't be any — form data is JSON-shaped) can't blow up inference.\n *\n * Used by {@link module:effect-forms-svelte/FormStore}'s `field(path)` — see\n * the trade-off recorded in `docs/decisions/` for why this was chosen over the\n * core's (now-removed) opaque `FieldRef`.\n */\nexport type FieldPath<T, D extends number = 8> = T extends object\n ? [D] extends [never]\n ? never\n : {\n [K in Extract<keyof T, string>]: `${K}${PathSuffix<T[K], Prev[D]>}`;\n }[Extract<keyof T, string>]\n : never;\n\n/** Recursion-depth countdown used by {@link FieldPath} / {@link PathValue}. */\ntype Prev = [never, 0, 1, 2, 3, 4, 5, 6, 7];\n\n/**\n * The continuation after a key: nothing, an array index (the bracket closes\n * immediately — `[0]`, not `[0.label]` — then {@link PathSuffix} recurses on\n * the element type for whatever comes after), or `.key`.\n */\ntype PathSuffix<T, D extends number> = [D] extends [never]\n ? \"\"\n : T extends ReadonlyArray<infer E>\n ? \"\" | `[${number}]${PathSuffix<E, Prev[D]>}`\n : T extends object\n ?\n | \"\"\n | { [K in Extract<keyof T, string>]: `.${K}${PathSuffix<T[K], Prev[D]>}` }[Extract<\n keyof T,\n string\n >]\n : \"\";\n\n/** The base key of a single dot-segment (`\"tags[0]\"` → `\"tags\"`). */\ntype SegmentBase<S extends string> = S extends `${infer Base}[${string}` ? Base : S;\n\n/** The bracket indices of a single dot-segment (`\"tags[0][1]\"` → `[\"0\", \"1\"]`), untyped past presence. */\ntype SegmentIndices<S extends string> = S extends `${string}[${infer Idx}]${infer Rest}`\n ? [Idx, ...SegmentIndicesRest<Rest>]\n : [];\n\n/** Continuation of {@link SegmentIndices} once the leading (non-bracket) prefix has been consumed. */\ntype SegmentIndicesRest<S extends string> = S extends `[${infer Idx}]${infer Rest}`\n ? [Idx, ...SegmentIndicesRest<Rest>]\n : [];\n\n/** Step through an array type once per entry in `Idxs`. */\ntype ApplyIndices<T, Idxs extends readonly unknown[]> = Idxs extends [unknown, ...infer Rest]\n ? T extends ReadonlyArray<infer E>\n ? ApplyIndices<E, Rest>\n : never\n : T;\n\n/** Resolve a single dot-segment (base key plus any bracket indices) against `T`. */\ntype ResolveSegment<T, S extends string> =\n SegmentBase<S> extends keyof T ? ApplyIndices<T[SegmentBase<S>], SegmentIndices<S>> : never;\n\n/**\n * The value type at a {@link FieldPath} `P` into `T` — the leaf type `field(path)`\n * resolves to. `PathValue<{ tags: string[] }, \"tags[0]\">` is `string`.\n */\nexport type PathValue<T, P extends string> = P extends `${infer Head}.${infer Rest}`\n ? PathValue<ResolveSegment<T, Head>, Rest>\n : ResolveSegment<T, P>;\n\n/**\n * Maps an array index that existed before an index-shifting mutation to where\n * it lives afterwards, or to `null` when the item at that index no longer\n * exists (its per-index state should be dropped). Built by {@link removeAt} /\n * {@link insertAt} / {@link swapAt} / {@link moveAt} / {@link replaceAt}, and\n * consumed by {@link remapIndex} / {@link remapKeyedRecord} and\n * `Errors.remapIndices` to keep per-index state (touched flags, error trees)\n * in sync with the row it was recorded against.\n */\nexport type IndexMap = (index: number) => number | null;\n\n/** The {@link IndexMap} for removing the item at `index`: shifts later indices down by one. */\nexport function removeAt(index: number): IndexMap {\n return (i) => (i === index ? null : i > index ? i - 1 : i);\n}\n\n/** The {@link IndexMap} for inserting an item at `index`: shifts `index` and later up by one. */\nexport function insertAt(index: number): IndexMap {\n return (i) => (i >= index ? i + 1 : i);\n}\n\n/** The {@link IndexMap} for swapping the items at `a` and `b`. */\nexport function swapAt(a: number, b: number): IndexMap {\n return (i) => (i === a ? b : i === b ? a : i);\n}\n\n/** The {@link IndexMap} for moving the item at `from` to `to`, shifting the items between. */\nexport function moveAt(from: number, to: number): IndexMap {\n return (i) => {\n if (i === from) return to;\n if (from < to) return i > from && i <= to ? i - 1 : i;\n return i >= to && i < from ? i + 1 : i;\n };\n}\n\n/** The {@link IndexMap} for replacing the item at `index` in place: drops only that index's state. */\nexport function replaceAt(index: number): IndexMap {\n return (i) => (i === index ? null : i);\n}\n\n/** The {@link IndexMap} for clearing every item in the array: drops all per-index state. */\nexport const clearAll: IndexMap = () => null;\n\n/**\n * Remap `path`'s index segment immediately under `arrayPath` through `map`.\n * Paths outside `arrayPath`, and `arrayPath` itself (a whole-array message),\n * pass through unchanged; a path whose index segment maps to `null` is\n * dropped (returns `null`) — its item no longer exists. Pure.\n */\nexport function remapIndex(path: FormPath, arrayPath: FormPath, map: IndexMap): FormPath | null {\n if (!isUnder(path, arrayPath) || path.length === arrayPath.length) return path;\n const segment = path[arrayPath.length];\n if (typeof segment !== \"number\") return path;\n const mapped = map(segment);\n if (mapped === null) return null;\n if (mapped === segment) return path;\n return [...path.slice(0, arrayPath.length), mapped, ...path.slice(arrayPath.length + 1)];\n}\n\n/**\n * Remap every entry of a flat, path-keyed record (a {@link toString} key per\n * entry — e.g. touched flags) through {@link remapIndex}. Entries whose path\n * maps to `null` are dropped. Pure.\n */\nexport function remapKeyedRecord<T>(\n record: Record<string, T>,\n arrayPath: FormPath,\n map: IndexMap,\n): Record<string, T> {\n const out: Record<string, T> = {};\n for (const key of Object.keys(record)) {\n const remapped = remapIndex(fromString(key), arrayPath, map);\n if (remapped !== null) out[toString(remapped)] = record[key] as T;\n }\n return out;\n}\n","/**\n * The nested form-error tree and its operations.\n *\n * {@link FormErrors} is a nested error tree so a UI can read\n * `errors.author.name` or `errors.tags[0]` directly. The representation is:\n *\n * - a **leaf** field's messages are a `string[]` keyed by the field name\n * (`{ title: [\"Required\"] }`);\n * - a **branch** (nested object / array) is a nested `FormErrors`\n * (`{ author: { name: [\"Required\"] } }`); array elements are keyed by their\n * stringified index (`{ tags: { \"0\": [\"Too short\"] } }`);\n * - a message attached to a **branch itself** (a cross-field or\n * whole-array message) lives under that branch's `_errors` key.\n *\n * The tree is plain JSON — it serialises across the SSR boundary unchanged —\n * and the operations here ({@link issuesToErrors}, {@link flattenErrors},\n * {@link setError}, {@link mergeErrors}, …) are pure and return new trees.\n *\n * @copyright Thomas Foster\n * @module effect-forms/Errors\n */\n\nimport type { FormIssue, FormPath } from \"./Issues.ts\";\nimport { type IndexMap, remapIndex } from \"./Path.ts\";\n\n/** The root key under which a branch's own (non-field) messages are stored. */\nexport const ROOT_ERROR_KEY = \"_errors\";\n\n/**\n * A nested tree of validation messages. Leaves are `string[]`; branches are\n * nested {@link FormErrors}; a branch's own messages live under\n * {@link ROOT_ERROR_KEY}. Always JSON-serialisable.\n */\nexport interface FormErrors {\n readonly [ROOT_ERROR_KEY]?: readonly string[];\n readonly [key: string]: FormErrors | readonly string[] | undefined;\n}\n\n/**\n * A {@link FormErrors} tree typed to the shape of `A`, so fields are accessed\n * by name with type-safety: for `A = { name: string; author: { bio: string } }`,\n * `errors.name` is `readonly string[] | undefined` and `errors.author?.bio`\n * likewise. A branch's own (cross-field) messages live under `_errors`. The\n * runtime value is an ordinary {@link FormErrors} — this only refines the type.\n */\nexport type TypedFormErrors<A> = [NonNullable<A>] extends [ReadonlyArray<infer E>]\n ? {\n readonly [index: number]: TypedFormErrors<E> | undefined;\n readonly _errors?: readonly string[];\n }\n : [NonNullable<A>] extends [object]\n ? { readonly [K in keyof A]?: TypedFormErrors<A[K]> } & { readonly _errors?: readonly string[] }\n : readonly string[];\n\n/** Mutable mirror of {@link FormErrors} used while building a tree. */\ntype MutableNode = { [key: string]: string[] | MutableNode | undefined };\n\nconst isMessageList = (value: unknown): value is readonly string[] =>\n Array.isArray(value) && value.every((v) => typeof v === \"string\");\n\nconst ownErrors = (node: MutableNode): string[] => {\n const existing = node[ROOT_ERROR_KEY];\n if (isMessageList(existing)) return existing;\n const created: string[] = [];\n node[ROOT_ERROR_KEY] = created;\n return created;\n};\n\n/**\n * If `node[key]` is a leaf's message list, convert it in place into a branch\n * carrying those same messages as its own {@link ROOT_ERROR_KEY} (a path used\n * as a leaf is now needed as a branch too) — a no-op when `node[key]` is\n * already a branch or absent. Shared by {@link insert} and {@link setLeaf}'s\n * path-descent, the one piece of their branch-walking that's identical.\n */\nconst promoteLeafToBranch = (node: MutableNode, key: string): void => {\n const existing = node[key];\n if (isMessageList(existing)) node[key] = { [ROOT_ERROR_KEY]: existing };\n};\n\n/**\n * Insert one message at `path` into a mutable error tree. A leaf becomes a\n * `string[]`; if the same path is later used as a branch the existing list is\n * preserved under {@link ROOT_ERROR_KEY}; if a branch later receives its own\n * message it lands under {@link ROOT_ERROR_KEY}. The empty path targets the\n * tree root's {@link ROOT_ERROR_KEY}.\n */\nconst insert = (root: MutableNode, path: FormPath, message: string): void => {\n if (path.length === 0) {\n ownErrors(root).push(message);\n return;\n }\n\n let node = root;\n for (let i = 0; i < path.length - 1; i++) {\n const key = String(path[i]);\n if (node[key] === undefined) node[key] = {};\n else promoteLeafToBranch(node, key);\n node = node[key] as MutableNode;\n }\n\n const last = String(path[path.length - 1]);\n const existing = node[last];\n if (existing === undefined) {\n node[last] = [message];\n } else if (isMessageList(existing)) {\n existing.push(message);\n } else {\n // The leaf key is already a branch — attach to its own `_errors`.\n ownErrors(existing).push(message);\n }\n};\n\n/** Build a nested {@link FormErrors} tree from a flat list of {@link FormIssue}s. */\nexport function issuesToErrors(issues: ReadonlyArray<FormIssue>): FormErrors {\n const root: MutableNode = {};\n for (const issue of issues) insert(root, issue.path, issue.message);\n return root;\n}\n\n/**\n * Flatten a {@link FormErrors} tree back into a list of {@link FormIssue}s, in\n * depth-first order. The inverse of {@link issuesToErrors} (modulo message\n * ordering within a single field).\n */\nexport function flattenErrors(errors: FormErrors): FormIssue[] {\n const out: FormIssue[] = [];\n\n const walk = (node: FormErrors, path: Array<string | number>): void => {\n for (const key of Object.keys(node)) {\n const value = node[key];\n if (value === undefined) continue;\n if (key === ROOT_ERROR_KEY) {\n for (const message of value as readonly string[]) out.push({ path, message });\n continue;\n }\n const segment: string | number = /^\\d+$/.test(key) ? Number(key) : key;\n if (isMessageList(value)) {\n for (const message of value) out.push({ path: [...path, segment], message });\n } else {\n walk(value, [...path, segment]);\n }\n }\n };\n\n walk(errors, []);\n return out;\n}\n\n/** Whether the tree carries any message anywhere. */\nexport function hasErrors(errors: FormErrors): boolean {\n return flattenErrors(errors).length > 0;\n}\n\n/**\n * Read the messages attached directly to `path` (a leaf's list, or a branch's\n * own {@link ROOT_ERROR_KEY}). Returns `undefined` when the path has no direct\n * messages.\n */\nexport function getError(errors: FormErrors, path: FormPath): readonly string[] | undefined {\n let node: FormErrors | readonly string[] | undefined = errors;\n for (const segment of path) {\n if (node === undefined || isMessageList(node)) return undefined;\n node = node[String(segment)];\n }\n if (node === undefined) return undefined;\n if (isMessageList(node)) return node;\n return node[ROOT_ERROR_KEY];\n}\n\n/** Return a new tree with `message` added at `path`. Pure. */\nexport function setError(errors: FormErrors, path: FormPath, message: string): FormErrors {\n const next = structuredClone(errors) as unknown as MutableNode;\n insert(next, path, message);\n return next;\n}\n\n/** Combine two error trees into one (left then right). Pure. */\nexport function mergeErrors(a: FormErrors, b: FormErrors): FormErrors {\n return issuesToErrors([...flattenErrors(a), ...flattenErrors(b)]);\n}\n\n/** The empty error tree. */\nexport const noErrors: FormErrors = {};\n\n/**\n * Remap the array-index segments of every message under `arrayPath` through\n * `map` (see {@link module:effect-forms/Path.IndexMap}), so an error recorded\n * against a row follows that row through a remove / insert / swap / move.\n * Messages whose index maps to `null` are dropped. Pure.\n */\nexport function remapIndices(errors: FormErrors, arrayPath: FormPath, map: IndexMap): FormErrors {\n const remapped: FormIssue[] = [];\n for (const issue of flattenErrors(errors)) {\n const path = remapIndex(issue.path, arrayPath, map);\n if (path !== null) remapped.push({ path, message: issue.message });\n }\n return issuesToErrors(remapped);\n}\n\n/**\n * Return a new tree with the messages *directly at* `path` replaced by\n * `messages` (removing the key when `messages` is empty), leaving every other\n * path — including children of a branch `path` — untouched. Unlike\n * {@link setError} (which appends one message), this is the \"this field's\n * validator just ran, here is its complete result\" operation a per-field\n * validator needs: it can clear a field back to valid without disturbing\n * sibling or nested messages. Pure.\n */\nexport function replaceAt(\n errors: FormErrors,\n path: FormPath,\n messages: readonly string[],\n): FormErrors {\n const next = structuredClone(errors) as unknown as MutableNode;\n setLeaf(next, path, messages);\n return next;\n}\n\nconst setLeaf = (root: MutableNode, path: FormPath, messages: readonly string[]): void => {\n if (path.length === 0) {\n setOwnMessages(root, messages);\n return;\n }\n const parent = descendClearing(root, path, messages);\n if (parent === undefined) return; // an absent branch on the clearing path — nothing to clear\n setLeafMessages(parent, String(path[path.length - 1]), messages);\n};\n\n/** Set or clear a node's own {@link ROOT_ERROR_KEY} messages. */\nconst setOwnMessages = (node: MutableNode, messages: readonly string[]): void => {\n if (messages.length === 0) delete node[ROOT_ERROR_KEY];\n else node[ROOT_ERROR_KEY] = [...messages];\n};\n\n/**\n * Walk to `path`'s parent branch, creating branches as needed. When\n * `messages` is empty (a clear, not a set) a missing branch means there is\n * nothing to clear — descent stops early and returns `undefined` rather than\n * creating empty branches just to immediately no-op inside them.\n */\nconst descendClearing = (\n root: MutableNode,\n path: FormPath,\n messages: readonly string[],\n): MutableNode | undefined => {\n let node = root;\n for (let i = 0; i < path.length - 1; i++) {\n const key = String(path[i]);\n if (node[key] === undefined) {\n if (messages.length === 0) return undefined;\n node[key] = {};\n } else {\n promoteLeafToBranch(node, key);\n }\n node = node[key] as MutableNode;\n }\n return node;\n};\n\n/** Set or clear `node[key]`'s messages — a leaf's list, or (if it's already a branch) its own {@link ROOT_ERROR_KEY}. */\nconst setLeafMessages = (node: MutableNode, key: string, messages: readonly string[]): void => {\n const existing = node[key];\n if (existing === undefined) {\n if (messages.length > 0) node[key] = [...messages];\n return;\n }\n if (isMessageList(existing)) {\n if (messages.length === 0) delete node[key];\n else node[key] = [...messages];\n return;\n }\n // Already a branch (has nested children) — replace its own messages,\n // preserving the children.\n if (messages.length === 0) delete existing[ROOT_ERROR_KEY];\n else existing[ROOT_ERROR_KEY] = [...messages];\n};\n\n/**\n * Where a message in a {@link FormErrors} tree came from. `\"server\"` messages\n * come from the last submission response; `\"client\"` messages come from\n * browser-side validation (schema re-run, per-field validators, client-run\n * `refineEffect` refinements). Kept as parallel trees (see {@link\n * SourcedErrors}) rather than tagging each message, so a UI can style sources\n * differently and client revalidation can clear only its own tree, leaving\n * server-reported failures in place until their field actually changes.\n */\nexport type ErrorSource = \"client\" | \"server\";\n\n/** Parallel error trees, one per {@link ErrorSource}, plus their {@link mergeSourced} view. */\nexport interface SourcedErrors {\n readonly client: FormErrors;\n readonly server: FormErrors;\n}\n\n/** Both source trees empty. */\nexport const emptySourced: SourcedErrors = { client: noErrors, server: noErrors };\n\n/** Combine both source trees into the single tree a UI reads (server first, then client). */\nexport function mergeSourced(sourced: SourcedErrors): FormErrors {\n return mergeErrors(sourced.server, sourced.client);\n}\n\n/**\n * Return new {@link SourcedErrors} with `source`'s tree updated at `path` via\n * {@link replaceAt} (the other source's tree is untouched). Pure.\n */\nexport function setSourceAt(\n sourced: SourcedErrors,\n source: ErrorSource,\n path: FormPath,\n messages: readonly string[],\n): SourcedErrors {\n return { ...sourced, [source]: replaceAt(sourced[source], path, messages) };\n}\n\n/** Clear `source`'s messages at `path` (and nowhere else). Shorthand for {@link setSourceAt} with `[]`. */\nexport function clearSourceAt(\n sourced: SourcedErrors,\n source: ErrorSource,\n path: FormPath,\n): SourcedErrors {\n return setSourceAt(sourced, source, path, []);\n}\n","/**\n * Field definitions for the {@link module:effect-forms/FormBuilder}.\n *\n * A {@link FormBuilder} composes a form one field at a time. Each field is\n * either a **scalar** {@link FieldDef} (bound to a leaf schema) or an\n * **array** {@link ArrayFieldDef} (bound to an item schema — the field is a\n * list of that item). This module is the small vocabulary the builder is made\n * of: the two field shapes, their guards, the type-level projections that turn\n * a record of fields into the form's encoded / decoded data types, and the\n * default-value derivation used to seed a blank form (or a freshly-appended\n * array item).\n *\n * Defaults are *encoded* — an HTML form holds strings, so a scalar seeds to\n * `\"\"`, an array to `[]`, and a nested struct recurses. Coercion back to the\n * decoded type is the schema's job at validate time (see\n * {@link module:effect-forms/Coerce}).\n *\n * @copyright Thomas Foster\n * @module effect-forms/Field\n */\n\nimport type * as Schema from \"effect/Schema\";\nimport * as SchemaAST from \"effect/SchemaAST\";\nimport type { FormPath } from \"./Issues.ts\";\n\n/** A scalar field: a key bound to a leaf (or nested struct) schema. */\nexport interface FieldDef<K extends string, S extends Schema.Top> {\n readonly _tag: \"field\";\n readonly key: K;\n readonly schema: S;\n}\n\n/** An array field: a key bound to an item schema; the field is a list of items. */\nexport interface ArrayFieldDef<K extends string, S extends Schema.Top> {\n readonly _tag: \"array\";\n readonly key: K;\n readonly itemSchema: S;\n}\n\n/** Either field shape, with the key / schema types erased. */\nexport type AnyFieldDef = FieldDef<string, Schema.Top> | ArrayFieldDef<string, Schema.Top>;\n\n/** A record of fields, keyed by field name — the builder's accumulated shape. */\nexport type FieldsRecord = Record<string, AnyFieldDef>;\n\n/** Whether `def` is an {@link ArrayFieldDef}. */\nexport const isArrayFieldDef = (def: AnyFieldDef): def is ArrayFieldDef<string, Schema.Top> =>\n def._tag === \"array\";\n\n/** Whether `def` is a scalar {@link FieldDef}. */\nexport const isFieldDef = (def: AnyFieldDef): def is FieldDef<string, Schema.Top> =>\n def._tag === \"field\";\n\n/** Construct a scalar {@link FieldDef}. */\nexport const makeField = <K extends string, S extends Schema.Top>(\n key: K,\n schema: S,\n): FieldDef<K, S> => ({ _tag: \"field\", key, schema });\n\n/** Construct an {@link ArrayFieldDef}. */\nexport const makeArrayField = <K extends string, S extends Schema.Top>(\n key: K,\n itemSchema: S,\n): ArrayFieldDef<K, S> => ({ _tag: \"array\", key, itemSchema });\n\n/** The encoded (form-input) data type for a record of fields. */\nexport type EncodedFromFields<T extends FieldsRecord> = {\n readonly [K in keyof T]: T[K] extends FieldDef<string, infer S>\n ? S[\"Encoded\"]\n : T[K] extends ArrayFieldDef<string, infer S>\n ? ReadonlyArray<S[\"Encoded\"]>\n : never;\n};\n\n/** The decoded (validated) data type for a record of fields. */\nexport type DecodedFromFields<T extends FieldsRecord> = {\n readonly [K in keyof T]: T[K] extends FieldDef<string, infer S>\n ? S[\"Type\"]\n : T[K] extends ArrayFieldDef<string, infer S>\n ? ReadonlyArray<S[\"Type\"]>\n : never;\n};\n\n/**\n * Derive a blank *encoded* default from a schema AST: a struct recurses into\n * its properties, an array seeds to `[]`, and any scalar seeds to `\"\"` (an\n * HTML input's empty value). Conservative by design — a value that will not\n * decode cleanly is still a valid *starting* value the user edits.\n */\nexport function defaultValue(schema: Schema.Top): unknown {\n return fromAst(schema.ast);\n}\n\n/**\n * Unwrap a union to its first structured (struct / array) member — an\n * `optional` / `NullOr` wrapper (`Struct | undefined` / `Struct | null`)\n * still resolves to the wrapped struct or array's AST rather than a scalar\n * fallback. Non-unions, and unions with no structured member, pass through.\n */\nfunction unwrapToStructured(ast: SchemaAST.AST): SchemaAST.AST {\n if (!SchemaAST.isUnion(ast)) return ast;\n for (const member of ast.types) {\n const inner = unwrapToStructured(member);\n if (SchemaAST.isObjects(inner) || SchemaAST.isArrays(inner)) return inner;\n }\n return ast;\n}\n\nfunction fromAst(ast: SchemaAST.AST): unknown {\n const unwrapped = unwrapToStructured(ast);\n if (SchemaAST.isObjects(unwrapped)) {\n const out: Record<string, unknown> = {};\n for (const ps of unwrapped.propertySignatures) out[String(ps.name)] = fromAst(ps.type);\n return out;\n }\n if (SchemaAST.isArrays(unwrapped)) return [];\n return \"\";\n}\n\n/** The item AST of an {@link SchemaAST.Arrays} node: the rest (spread) type, or the first tuple element. */\nfunction arrayElementAst(ast: SchemaAST.Arrays): SchemaAST.AST | undefined {\n return ast.rest[0] ?? ast.elements[0];\n}\n\n/** Descend one array-index path segment from an (already-unwrapped) array AST. */\nfunction stepIntoArray(ast: SchemaAST.AST): SchemaAST.AST | undefined {\n if (!SchemaAST.isArrays(ast)) return undefined;\n const item = arrayElementAst(ast);\n return item === undefined ? undefined : unwrapToStructured(item);\n}\n\n/** Descend one struct-property path segment from an (already-unwrapped) struct AST. */\nfunction stepIntoStruct(ast: SchemaAST.AST, key: string): SchemaAST.AST | undefined {\n if (!SchemaAST.isObjects(ast)) return undefined;\n const ps = ast.propertySignatures.find((p) => String(p.name) === key);\n return ps === undefined ? undefined : unwrapToStructured(ps.type);\n}\n\n/**\n * Walk `schema`'s AST along `path` — through struct properties and array\n * elements alike — and return the AST found there, or `undefined` if `path`\n * doesn't resolve (a missing property, or a non-array indexed). Unlike a\n * {@link FieldsRecord} lookup, this works for any nesting depth and for\n * schemas built directly with `Form.make` (no builder involved).\n */\nexport function schemaAt(schema: Schema.Top, path: FormPath): SchemaAST.AST | undefined {\n let ast: SchemaAST.AST | undefined = unwrapToStructured(schema.ast);\n for (const segment of path) {\n if (ast === undefined) return undefined;\n ast = typeof segment === \"number\" ? stepIntoArray(ast) : stepIntoStruct(ast, segment);\n }\n return ast;\n}\n\n/**\n * Derive a blank encoded item for the array field at `path` (any nesting\n * depth) by walking `schema`'s AST there — the nested-array counterpart to\n * {@link defaultValue}. Returns `\"\"` when `path` doesn't resolve to an array.\n */\nexport function defaultItemAt(schema: Schema.Top, path: FormPath): unknown {\n const ast = schemaAt(schema, path);\n if (ast === undefined || !SchemaAST.isArrays(ast)) return \"\";\n const item = arrayElementAst(ast);\n return item === undefined ? \"\" : fromAst(item);\n}\n\n/** Seed a blank encoded value for every field: `[]` for arrays, `\"\"` otherwise. */\nexport function defaultEncodedValues(fields: FieldsRecord): Record<string, unknown> {\n const out: Record<string, unknown> = {};\n for (const [key, def] of Object.entries(fields)) {\n out[key] = isArrayFieldDef(def) ? [] : defaultValue(def.schema);\n }\n return out;\n}\n","/**\n * Form issues — the flat, path-addressed representation of a single\n * validation failure, plus the walker that turns an Effect Schema issue\n * tree into a list of them.\n *\n * An Effect Schema decode failure is a recursive {@link SchemaIssue.Issue}\n * tree: `Pointer` nodes carry path segments, `Composite` / `AnyOf` group\n * sibling failures, `Filter` / `Encoding` wrap a single inner failure, and\n * the leaves (`InvalidType`, `InvalidValue`, `MissingKey`, …) describe the\n * actual problem. {@link schemaIssuesToFormIssues} flattens that tree into\n * one {@link FormIssue} per leaf, accumulating the `Pointer.path` segments\n * into a `FormPath`. This is the framework-neutral\n * flattened error list and the same walk the repo's JSON:API materialiser\n * performs — here it stays UI-shaped (`path` + `message`) rather than\n * JSON:API-pointer-shaped.\n *\n * @copyright Thomas Foster\n * @module effect-forms/Issues\n */\n\nimport type * as Schema from \"effect/Schema\";\nimport * as SchemaIssue from \"effect/SchemaIssue\";\n\n/**\n * A path into the form's data. String segments address object keys; number\n * segments address array indices. The empty path addresses the form root\n * (a whole-form / cross-field message).\n */\nexport type FormPath = ReadonlyArray<string | number>;\n\n/** One validation failure: where it happened ({@link FormPath}) and why. */\nexport interface FormIssue {\n readonly path: FormPath;\n readonly message: string;\n}\n\n/**\n * Render one terminal issue into a human-readable message. The default is\n * Effect Schema's own formatter (`SchemaIssue.makeFormatterDefault`), which\n * renders a sentence such as `Expected string`. (An issue's `toString` is no\n * longer a readable rendering as of Effect rc.118: it prints\n * `[object Object]`.) Override it to localise or to map specific `_tag`s to\n * custom copy.\n *\n * A failed schema check reaches the formatter as the `Filter` node that\n * wraps its leaf, because the check's own message (e.g. `Expected a value\n * with a length of at least 2`) lives on the `Filter`, not on the leaf.\n */\nexport type LeafFormatter = (issue: SchemaIssue.Issue) => string;\n\n/** The default leaf formatter — Effect Schema's own rendering of the issue. */\nexport const defaultLeafFormatter: LeafFormatter = SchemaIssue.makeFormatterDefault();\n\n/**\n * Normalise a `Pointer.path` segment into a {@link FormPath} segment: integer\n * keys become numbers (array indices), everything else becomes a string.\n */\nconst normaliseSegment = (segment: PropertyKey): string | number => {\n if (typeof segment === \"number\") return segment;\n if (typeof segment === \"symbol\") return segment.toString();\n return /^\\d+$/.test(segment) ? Number(segment) : segment;\n};\n\n/** Whether `issue` is a terminal leaf: it wraps no further issues. */\nconst isTerminal = (issue: SchemaIssue.Issue): boolean => {\n switch (issue._tag) {\n case \"Pointer\":\n case \"Composite\":\n case \"Filter\":\n case \"Encoding\":\n return false;\n case \"AnyOf\":\n return issue.issues.length === 0;\n default:\n return true;\n }\n};\n\n/**\n * Walk an Effect Schema issue tree, emitting one {@link FormIssue} per leaf\n * failure. Path segments accumulate through `Pointer` nodes; `Composite` and\n * `AnyOf` fan out to siblings; `Filter` / `Encoding` are transparent\n * wrappers. An `AnyOf` with no recorded member failures (a bare union\n * mismatch) is itself a leaf.\n */\nexport function schemaIssuesToFormIssues(\n issue: SchemaIssue.Issue,\n format: LeafFormatter = defaultLeafFormatter,\n): FormIssue[] {\n const out: FormIssue[] = [];\n\n const walk = (current: SchemaIssue.Issue, path: Array<string | number>): void => {\n switch (current._tag) {\n case \"Pointer\":\n walk(current.issue, [...path, ...current.path.map(normaliseSegment)]);\n return;\n case \"Composite\":\n for (const child of current.issues) walk(child, path);\n return;\n case \"AnyOf\":\n if (current.issues.length === 0) {\n out.push({ path, message: format(current) });\n return;\n }\n for (const child of current.issues) walk(child, path);\n return;\n case \"Filter\":\n // A check that fails on the value itself: its message sits on the\n // `Filter` node, so format that rather than the bare leaf inside.\n if (isTerminal(current.issue)) {\n out.push({ path, message: format(current) });\n return;\n }\n walk(current.issue, path);\n return;\n case \"Encoding\":\n walk(current.issue, path);\n return;\n default:\n out.push({ path, message: format(current) });\n return;\n }\n };\n\n walk(issue, []);\n return out;\n}\n\n/**\n * Normalise a filter predicate's {@link Schema.FilterOutput} into a flat list of\n * {@link FormIssue}s (empty on success). Shared by whole-form refinements\n * ({@link module:effect-forms/FormBuilder}) and per-field validators\n * ({@link module:effect-forms/Validate}) so both fold into the same nested\n * error tree as schema-decode failures.\n */\nexport function filterOutputToFormIssues(output: Schema.FilterOutput): FormIssue[] {\n if (output === undefined || output === true) return [];\n if (output === false) return [{ path: [], message: \"Invalid value\" }];\n if (Array.isArray(output)) return output.flatMap(filterIssueToFormIssues);\n return filterIssueToFormIssues(output as Schema.FilterIssue);\n}\n\nfunction filterIssueToFormIssues(issue: Schema.FilterIssue): FormIssue[] {\n if (typeof issue === \"string\") return [{ path: [], message: issue }];\n if (\"path\" in issue && \"issue\" in issue) {\n const prefix = issue.path.map((s) => (typeof s === \"symbol\" ? s.toString() : s));\n const inner =\n typeof issue.issue === \"string\"\n ? [{ path: [], message: issue.issue }]\n : schemaIssuesToFormIssues(issue.issue);\n return inner.map((i) => ({ path: [...prefix, ...i.path], message: i.message }));\n }\n return schemaIssuesToFormIssues(issue);\n}\n","/**\n * Compose a form schema one field at a time, with cross-field refinements.\n *\n * {@link make} (aliased {@link empty}) starts an empty builder;\n * {@link FormBuilder.addField} adds a scalar or array field, {@link\n * FormBuilder.merge} folds another builder in, and {@link FormBuilder.refine} /\n * {@link FormBuilder.refineEffect} attach cross-field validations. The point is\n * incremental composition — assemble a large form from small, reusable\n * field-group builders — plus a home for whole-form rules (`password ===\n * confirmPassword`) that a single field schema can't express.\n *\n * {@link buildSchema} collapses the accumulated fields into an ordinary\n * `Schema.Struct` (array fields become `Schema.Array(item)`) and applies every\n * *synchronous* refinement as a struct-level `check`, so the result decodes,\n * derives constraints, and validates exactly like a hand-written schema — hand\n * it straight to {@link module:effect-forms/Form}'s `make`. *Asynchronous*\n * refinements can't be schema checks (Effect Schema has no effectful filter),\n * so they're carried on the builder and run by the Effect-returning validate\n * path — {@link asyncRefinements} exposes them and {@link runAsyncRefinements}\n * runs them into a {@link FormIssue} list.\n *\n * @copyright Thomas Foster\n * @module effect-forms/FormBuilder\n */\n\nimport * as Effect from \"effect/Effect\";\nimport * as Schema from \"effect/Schema\";\nimport type {\n AnyFieldDef,\n ArrayFieldDef,\n DecodedFromFields,\n EncodedFromFields,\n FieldDef,\n FieldsRecord,\n} from \"./Field.ts\";\nimport { isArrayFieldDef, isFieldDef, makeField } from \"./Field.ts\";\nimport type * as Issues from \"./Issues.ts\";\nimport type { FormIssue } from \"./Issues.ts\";\nimport { filterOutputToFormIssues as issuesFromFilterOutput } from \"./Issues.ts\";\n\n/** Brand for a {@link FormBuilder}. */\nexport const TypeId: unique symbol = Symbol.for(\"@thomasfosterau/effect-forms/FormBuilder\");\nexport type TypeId = typeof TypeId;\n\n/** A synchronous cross-field refinement — becomes a struct-level schema check. */\ninterface SyncRefinement {\n readonly _tag: \"sync\";\n readonly fn: (values: unknown) => Schema.FilterOutput;\n}\n\n/** An asynchronous cross-field refinement — run by the Effect validate path. */\ninterface AsyncRefinement {\n readonly _tag: \"async\";\n readonly fn: (values: unknown) => Effect.Effect<Schema.FilterOutput, never, unknown>;\n}\n\ntype Refinement = SyncRefinement | AsyncRefinement;\n\n/**\n * A form assembled field by field. `TFields` accumulates the field record;\n * `R` accumulates the schemas' decoding-service requirements. Immutable — every\n * method returns a new builder.\n */\nexport interface FormBuilder<TFields extends FieldsRecord, R> {\n readonly [TypeId]: TypeId;\n readonly fields: TFields;\n readonly refinements: ReadonlyArray<Refinement>;\n readonly _R?: R;\n\n /** Add a scalar field from a {@link FieldDef}. */\n addField<K extends string, S extends Schema.Top>(\n field: FieldDef<K, S>,\n ): FormBuilder<TFields & { readonly [key in K]: FieldDef<K, S> }, R | S[\"DecodingServices\"]>;\n /** Add an array field from an {@link ArrayFieldDef}. */\n addField<K extends string, S extends Schema.Top>(\n field: ArrayFieldDef<K, S>,\n ): FormBuilder<TFields & { readonly [key in K]: ArrayFieldDef<K, S> }, R | S[\"DecodingServices\"]>;\n /** Add a scalar field from a key and schema. */\n addField<K extends string, S extends Schema.Top>(\n key: K,\n schema: S,\n ): FormBuilder<TFields & { readonly [key in K]: FieldDef<K, S> }, R | S[\"DecodingServices\"]>;\n\n /** Fold another builder's fields and refinements into this one. */\n merge<TFields2 extends FieldsRecord, R2>(\n other: FormBuilder<TFields2, R2>,\n ): FormBuilder<TFields & TFields2, R | R2>;\n\n /**\n * Attach a synchronous whole-form validation. The predicate sees the decoded\n * values and returns a {@link Schema.FilterOutput} (`undefined` / `true` to\n * pass, a message / `{ path, issue }` / list to fail).\n */\n refine(\n predicate: (values: DecodedFromFields<TFields>) => Schema.FilterOutput,\n ): FormBuilder<TFields, R>;\n\n /** Attach an asynchronous whole-form validation (run by the validate path). */\n refineEffect<RD>(\n predicate: (\n values: DecodedFromFields<TFields>,\n ) => Effect.Effect<Schema.FilterOutput, never, RD>,\n ): FormBuilder<TFields, R | RD>;\n}\n\nconst proto = {\n [TypeId]: TypeId,\n addField(\n this: FormBuilder<FieldsRecord, unknown>,\n keyOrField: string | AnyFieldDef,\n schema?: Schema.Top,\n ): FormBuilder<FieldsRecord, unknown> {\n const field = typeof keyOrField === \"string\" ? makeField(keyOrField, schema!) : keyOrField;\n return build({ ...this.fields, [field.key]: field }, this.refinements);\n },\n merge(\n this: FormBuilder<FieldsRecord, unknown>,\n other: FormBuilder<FieldsRecord, unknown>,\n ): FormBuilder<FieldsRecord, unknown> {\n return build({ ...this.fields, ...other.fields }, [...this.refinements, ...other.refinements]);\n },\n refine(\n this: FormBuilder<FieldsRecord, unknown>,\n predicate: (values: unknown) => Schema.FilterOutput,\n ): FormBuilder<FieldsRecord, unknown> {\n return build(this.fields, [...this.refinements, { _tag: \"sync\", fn: predicate }]);\n },\n refineEffect(\n this: FormBuilder<FieldsRecord, unknown>,\n predicate: (values: unknown) => Effect.Effect<Schema.FilterOutput, never, unknown>,\n ): FormBuilder<FieldsRecord, unknown> {\n return build(this.fields, [...this.refinements, { _tag: \"async\", fn: predicate }]);\n },\n};\n\nfunction build(\n fields: FieldsRecord,\n refinements: ReadonlyArray<Refinement>,\n): FormBuilder<FieldsRecord, unknown> {\n const self = Object.create(proto);\n self.fields = fields;\n self.refinements = refinements;\n return self;\n}\n\n/** Whether `u` is a {@link FormBuilder}. */\nexport const isFormBuilder = (u: unknown): u is FormBuilder<FieldsRecord, unknown> =>\n typeof u === \"object\" && u !== null && TypeId in u;\n\n/** The empty builder — the starting point for {@link FormBuilder.addField}. */\nexport const make: FormBuilder<Record<never, never>, never> = build({}, []) as never;\n\n/** Alias of {@link make} — the empty builder. */\nexport const empty = make;\n\n/**\n * Collapse a builder into an Effect Schema: a `Schema.Struct` of the fields\n * (array fields as `Schema.Array(item)`) with every synchronous refinement\n * applied as a struct-level check. Ready for {@link module:effect-forms/Form}.\n */\nexport function buildSchema<TFields extends FieldsRecord, R>(\n self: FormBuilder<TFields, R>,\n): Schema.Codec<DecodedFromFields<TFields>, EncodedFromFields<TFields>, R> {\n const structFields: Record<string, Schema.Top> = {};\n for (const [key, def] of Object.entries(self.fields)) {\n if (isArrayFieldDef(def)) structFields[key] = Schema.Array(def.itemSchema);\n else if (isFieldDef(def)) structFields[key] = def.schema;\n }\n\n let schema: Schema.Top = Schema.Struct(structFields);\n for (const refinement of self.refinements) {\n if (refinement._tag === \"sync\") schema = schema.check(Schema.makeFilter(refinement.fn));\n }\n\n return schema as unknown as Schema.Codec<\n DecodedFromFields<TFields>,\n EncodedFromFields<TFields>,\n R\n >;\n}\n\n/** The asynchronous refinements carried on a builder, as bare predicates. */\nexport function asyncRefinements<TFields extends FieldsRecord, R>(\n self: FormBuilder<TFields, R>,\n): ReadonlyArray<\n (values: DecodedFromFields<TFields>) => Effect.Effect<Schema.FilterOutput, never, R>\n> {\n return self.refinements\n .filter((r): r is AsyncRefinement => r._tag === \"async\")\n .map((r) => r.fn as never);\n}\n\n/**\n * Normalise a filter predicate's `Schema.FilterOutput` into a flat list of\n * {@link FormIssue}s (empty on success).\n *\n * @deprecated Use `Issues.filterOutputToFormIssues`; this re-export remains\n * only for callers that imported it from `FormBuilder`.\n */\nexport const filterOutputToFormIssues: typeof Issues.filterOutputToFormIssues =\n issuesFromFilterOutput;\n\n/**\n * Run every asynchronous refinement on `self` against `values` and collect\n * their failures as {@link FormIssue}s (empty when all pass). Runs them\n * concurrently; requirements propagate on the `R` channel.\n */\nexport function runAsyncRefinements<TFields extends FieldsRecord, R>(\n self: FormBuilder<TFields, R>,\n values: DecodedFromFields<TFields>,\n): Effect.Effect<ReadonlyArray<FormIssue>, never, R> {\n const refinements = asyncRefinements(self);\n if (refinements.length === 0) return Effect.succeed([]);\n return Effect.forEach(refinements, (fn) => fn(values), { concurrency: \"unbounded\" }).pipe(\n Effect.map((outputs) => outputs.flatMap(issuesFromFilterOutput)),\n );\n}\n","/**\n * {@link FormState} — the serialisable snapshot of a form.\n *\n * This is the single object a\n * server produces (validate a submission, or seed an empty form) and hands to\n * the client to hydrate from. It is plain JSON so it survives the SSR → client\n * boundary, and {@link FormStateSchema} gives it an Effect Schema so it can be\n * decoded back on arrival.\n *\n * @copyright Thomas Foster\n * @module effect-forms/State\n */\n\nimport * as Schema from \"effect/Schema\";\nimport type { InputConstraints } from \"./Constraints.ts\";\nimport { type FormErrors, hasErrors, noErrors, setError } from \"./Errors.ts\";\nimport type { FormPath } from \"./Issues.ts\";\n\n/**\n * A form snapshot.\n *\n * - `id` distinguishes multiple forms on one page.\n * - `valid` is whether the last validation succeeded.\n * - `posted` is whether this snapshot came from a submission (vs. a seeded\n * empty form) — drives \"show errors only after submit\" UIs.\n * - `data` is the current values (typed output on success; posted values\n * merged over defaults on failure, so the form re-renders what the user\n * typed).\n * - `errors` is the nested {@link FormErrors} tree.\n * - `message` is an optional status payload (a free-form status payload).\n * - `constraints` is the optional derived {@link InputConstraints} tree.\n */\nexport interface FormState<A, Message = unknown> {\n readonly id: string;\n readonly valid: boolean;\n readonly posted: boolean;\n readonly data: A;\n readonly errors: FormErrors;\n readonly message?: Message | undefined;\n readonly constraints?: InputConstraints | undefined;\n}\n\n/** Options for {@link make}. */\nexport interface MakeFormStateOptions<Message> {\n /** The form's id, distinguishing several forms on one page. Defaults to `\"default\"`. */\n readonly id?: string;\n /** Whether the state is valid. Defaults to `true` exactly when `errors` is empty. */\n readonly valid?: boolean;\n /** Whether the state comes from a submission. Defaults to `false`. */\n readonly posted?: boolean;\n /** The nested error tree. Defaults to no errors. */\n readonly errors?: FormErrors;\n /** A status message to render with the form. Omitted by default. */\n readonly message?: Message;\n /** Native input constraints. Omitted by default. */\n readonly constraints?: InputConstraints;\n}\n\n/** Build a {@link FormState} from data plus overrides. `valid` defaults to \"no errors\". */\nexport function make<A, Message = unknown>(\n data: A,\n options: MakeFormStateOptions<Message> = {},\n): FormState<A, Message> {\n const errors = options.errors ?? noErrors;\n return {\n id: options.id ?? \"default\",\n valid: options.valid ?? !hasErrors(errors),\n posted: options.posted ?? false,\n data,\n errors,\n ...(options.message !== undefined ? { message: options.message } : {}),\n ...(options.constraints !== undefined ? { constraints: options.constraints } : {}),\n };\n}\n\n/** Return a new state carrying `message` (and not otherwise changed). */\nexport function withMessage<A, Message>(\n state: FormState<A, Message>,\n message: Message,\n): FormState<A, Message> {\n return { ...state, message };\n}\n\n/**\n * Return a new state with `message` added at `path` and `valid` forced to\n * `false` — for attaching a\n * server-side validation failure to a specific field after the schema passed.\n */\nexport function withError<A, Message>(\n state: FormState<A, Message>,\n path: FormPath,\n message: string,\n): FormState<A, Message> {\n return { ...state, valid: false, errors: setError(state.errors, path, message) };\n}\n\n/** Whether the state is valid. */\nexport const isValid = <A, Message>(state: FormState<A, Message>): boolean => state.valid;\n\n/** Effect Schema describing the JSON shape of {@link FormState} for transport. */\nexport function FormStateSchema<DataSchema extends Schema.Top>(data: DataSchema) {\n return Schema.Struct({\n id: Schema.String,\n valid: Schema.Boolean,\n posted: Schema.Boolean,\n data,\n errors: Schema.Record(Schema.String, Schema.Unknown),\n message: Schema.optional(Schema.Unknown),\n constraints: Schema.optional(Schema.Record(Schema.String, Schema.Unknown)),\n });\n}\n","/**\n * {@link make} — the core entry point: bind an Effect Schema to a form and\n * get back a validator and an empty-state factory.\n *\n * This is the framework-neutral validate-and-seed entry point,\n * expressed as a small object bound to one schema:\n *\n * - `validate(input)` parses an HTML form body (or a plain object) and decodes\n * it through the schema, returning a {@link FormState} — valid with the\n * decoded data, or invalid with the nested {@link FormErrors} and the posted\n * values preserved so the form re-renders what the user typed. It is an\n * `Effect`, so a schema requiring decoding services composes naturally; it\n * has no error channel — validation failures live in the returned state.\n * - `empty()` seeds an unposted, invalid-by-default form from the supplied\n * defaults — what a `load` returns to render a blank create form.\n *\n * Coercion (strings → numbers / booleans / dates) is the schema's job: build\n * the schema from coercing leaves (`Schema.FiniteFromString`, the\n * {@link module:effect-forms/Coerce} helpers, …) so a multipart body decodes\n * cleanly.\n *\n * @copyright Thomas Foster\n * @module effect-forms/Form\n */\n\nimport * as Effect from \"effect/Effect\";\nimport type * as Schema from \"effect/Schema\";\nimport * as SchemaParser from \"effect/SchemaParser\";\nimport { constraintsFromSchema, type InputConstraints } from \"./Constraints.ts\";\nimport { defaultEncodedValues } from \"./Field.ts\";\nimport { issuesToErrors } from \"./Errors.ts\";\nimport { buildSchema, type FormBuilder, runAsyncRefinements } from \"./FormBuilder.ts\";\nimport type { DecodedFromFields, EncodedFromFields, FieldsRecord } from \"./Field.ts\";\nimport { formDataToObject, requestToObject } from \"./FormData.ts\";\nimport { type LeafFormatter, schemaIssuesToFormIssues } from \"./Issues.ts\";\nimport { type FormState, make as makeFormState, type MakeFormStateOptions } from \"./State.ts\";\n\n/** Everything {@link Form.validate} accepts. `null` / `undefined` mean \"no submission\". */\nexport type FormInput =\n | FormData\n | URLSearchParams\n | Request\n | Record<string, unknown>\n | null\n | undefined;\n\n/** Options for {@link make}. */\nexport interface MakeFormOptions<S extends Schema.Top> {\n /** Distinguishes multiple forms on a page. Defaults to `\"default\"`. */\n readonly id?: string;\n /** The blank-form values — what {@link Form.empty} seeds and the merge base on failure. */\n readonly defaults: S[\"Type\"];\n /** Override the per-leaf message rendering. */\n readonly leafFormatter?: LeafFormatter;\n /** Constraint overrides deep-merged over the AST-derived tree. */\n readonly constraints?: InputConstraints;\n /** Derive {@link InputConstraints} from the schema AST (default `true`). */\n readonly deriveConstraints?: boolean;\n}\n\n/** A schema bound to a form: a validator plus an empty-state factory. */\nexport interface Form<S extends Schema.Top, Message = unknown> {\n readonly schema: S;\n readonly id: string;\n readonly constraints: InputConstraints;\n /** Seed a blank, unposted form from the defaults. */\n empty(overrides?: MakeFormStateOptions<Message>): FormState<S[\"Type\"], Message>;\n /** Parse a form body (no decode) into a structured object. */\n parse(input: FormData | URLSearchParams | Record<string, unknown>): Record<string, unknown>;\n /**\n * Validate a submission into a {@link FormState}. Never fails on the error\n * channel — schema failures become `errors` on the returned (invalid) state.\n */\n validate(\n input: FormInput,\n ): Effect.Effect<FormState<S[\"Type\"], Message>, never, S[\"DecodingServices\"]>;\n}\n\nconst toStructured = (input: FormInput): Effect.Effect<Record<string, unknown> | null> => {\n if (input === null || input === undefined) return Effect.succeed(null);\n if (input instanceof Request) return Effect.promise(() => requestToObject(input));\n if (input instanceof FormData || input instanceof URLSearchParams) {\n return Effect.succeed(formDataToObject(input));\n }\n return Effect.succeed(input as Record<string, unknown>);\n};\n\n/**\n * Bind `schema` to a form: `validate(input)` decodes a submission into a\n * {@link FormState} (it never fails — validation failures live in the state;\n * its requirements are the schema's decoding services) and `empty()` seeds a\n * blank form from `defaults`. The returned {@link Form} is stateless and\n * reusable across requests.\n */\nexport function make<S extends Schema.Top, Message = unknown>(\n schema: S,\n options: MakeFormOptions<S>,\n): Form<S, Message> {\n const id = options.id ?? \"default\";\n const { defaults, leafFormatter } = options;\n const constraints =\n options.deriveConstraints === false\n ? (options.constraints ?? {})\n : constraintsFromSchema(schema, options.constraints ?? {});\n // `errors: \"all\"` collects every field failure (collect-all) rather\n // than stopping at the first, so the whole form lights up at once.\n const decode = SchemaParser.decodeUnknownEffect(schema, { errors: \"all\" });\n\n const empty: Form<S, Message>[\"empty\"] = (overrides = {}) =>\n makeFormState<S[\"Type\"], Message>(defaults, {\n id,\n valid: false,\n posted: false,\n constraints,\n ...overrides,\n });\n\n const parse: Form<S, Message>[\"parse\"] = (input) =>\n input instanceof FormData || input instanceof URLSearchParams\n ? formDataToObject(input)\n : (input as Record<string, unknown>);\n\n const validate: Form<S, Message>[\"validate\"] = (input) =>\n toStructured(input).pipe(\n Effect.flatMap((object) => {\n if (object === null) return Effect.succeed(empty());\n return decode(object).pipe(\n Effect.matchEffect({\n onSuccess: (data) =>\n Effect.succeed(\n makeFormState<S[\"Type\"], Message>(data as S[\"Type\"], {\n id,\n valid: true,\n posted: true,\n constraints,\n }),\n ),\n onFailure: (issue) =>\n Effect.succeed(\n makeFormState<S[\"Type\"], Message>(\n { ...(defaults as object), ...object } as S[\"Type\"],\n {\n id,\n valid: false,\n posted: true,\n constraints,\n errors: issuesToErrors(schemaIssuesToFormIssues(issue, leafFormatter)),\n },\n ),\n ),\n }),\n );\n }),\n );\n\n return { schema, id, constraints, empty, parse, validate };\n}\n\n/** Options for {@link fromBuilder}. Like {@link MakeFormOptions} but `defaults` is optional. */\nexport interface FromBuilderOptions<TFields extends FieldsRecord> {\n /** Distinguishes multiple forms on a page. Defaults to `\"default\"`. */\n readonly id?: string;\n /** Blank-form values. Defaults to a schema-derived encoded blank per field. */\n readonly defaults?: EncodedFromFields<TFields>;\n /** Override the per-leaf message rendering. */\n readonly leafFormatter?: LeafFormatter;\n /** Constraint overrides deep-merged over the AST-derived tree. */\n readonly constraints?: InputConstraints;\n /** Derive {@link InputConstraints} from the schema AST (default `true`). */\n readonly deriveConstraints?: boolean;\n}\n\n/**\n * Bind a {@link FormBuilder} to a {@link Form}. Collapses the builder to a\n * schema (see {@link buildSchema}), then behaves like {@link make} — except its\n * `validate` also runs the builder's *asynchronous* refinements after a\n * successful decode, folding any failures into the same nested error tree. When\n * `defaults` is omitted it is derived from the fields (blank encoded values).\n */\nexport function fromBuilder<TFields extends FieldsRecord, R, Message = unknown>(\n builder: FormBuilder<TFields, R>,\n options: FromBuilderOptions<TFields> = {},\n): Form<Schema.Codec<DecodedFromFields<TFields>, EncodedFromFields<TFields>, R>, Message> {\n const schema = buildSchema(builder);\n const defaults = (options.defaults ??\n defaultEncodedValues(builder.fields)) as EncodedFromFields<TFields>;\n const base = make<typeof schema, Message>(schema, { ...options, defaults });\n\n const decode = SchemaParser.decodeUnknownEffect(schema, { errors: \"all\" });\n\n const validate: Form<typeof schema, Message>[\"validate\"] = (input) =>\n toStructured(input).pipe(\n Effect.flatMap((object) => {\n if (object === null) return Effect.succeed(base.empty());\n const posted = { ...(defaults as object), ...object } as DecodedFromFields<TFields>;\n return decode(object).pipe(\n Effect.matchEffect({\n onSuccess: (data) =>\n runAsyncRefinements(builder, data as DecodedFromFields<TFields>).pipe(\n Effect.map((issues) =>\n issues.length === 0\n ? makeFormState<DecodedFromFields<TFields>, Message>(\n data as DecodedFromFields<TFields>,\n { id: base.id, valid: true, posted: true, constraints: base.constraints },\n )\n : makeFormState<DecodedFromFields<TFields>, Message>(posted, {\n id: base.id,\n valid: false,\n posted: true,\n constraints: base.constraints,\n errors: issuesToErrors(issues),\n }),\n ),\n ),\n onFailure: (issue) =>\n Effect.succeed(\n makeFormState<DecodedFromFields<TFields>, Message>(posted, {\n id: base.id,\n valid: false,\n posted: true,\n constraints: base.constraints,\n errors: issuesToErrors(schemaIssuesToFormIssues(issue, options.leafFormatter)),\n }),\n ),\n }),\n );\n }),\n );\n\n return { ...base, validate };\n}\n","/**\n * When a form validates (and, optionally, auto-submits).\n *\n * A reactive form has to decide *when* to run validation as the user types.\n * The three modes mirror the common form-library vocabulary:\n *\n * - **`onSubmit`** (the default) — validate only when the form is submitted (or\n * validation is triggered explicitly). The quietest mode.\n * - **`onBlur`** — validate a field when it loses focus.\n * - **`onChange`** — validate on every change, optionally `debounce`d.\n *\n * `onBlur` / `onChange` may also `autoSubmit`, turning the form into a\n * live-saving surface (a settings panel, a filter bar). This module is the\n * framework-neutral half: {@link parse} normalises the loose {@link FormMode}\n * a caller supplies into a fully-resolved {@link ParsedMode} the reactive\n * store drives from. The store owns the actual scheduling.\n *\n * A separate `revalidate` dimension governs what happens *after a submit*: an\n * `onSubmit`-mode form is otherwise silent until the next submit, which\n * leaves a failed post's errors frozen even after the user fixes the\n * offending field. `revalidate` says which trigger (`\"onChange\"` /\n * `\"onBlur\"` — independent of the primary `validation` trigger) re-validates\n * once the form has been posted at least once; `\"never\"` keeps the classic\n * frozen-until-resubmit behaviour.\n *\n * @copyright Thomas Foster\n * @module effect-forms/Mode\n */\n\nimport * as Duration from \"effect/Duration\";\n\n/** What re-validates a posted form as the user keeps editing. See {@link ParsedMode.revalidate}. */\nexport type RevalidateMode = \"onChange\" | \"onBlur\" | \"never\";\n\n/**\n * How a form decides when to validate, and whether it auto-submits.\n *\n * - `onSubmit` (the default) cannot auto-submit or debounce.\n * - `onBlur` may auto-submit; debounce is not meaningful.\n * - `onChange` may auto-submit and may debounce.\n *\n * `revalidate` is independent of `validation` and applies to every mode —\n * see the module docs.\n */\nexport type FormMode = (\n | { readonly validation?: \"onSubmit\"; readonly autoSubmit?: false; readonly debounce?: never }\n | { readonly validation: \"onBlur\"; readonly autoSubmit?: boolean; readonly debounce?: never }\n | {\n readonly validation: \"onChange\";\n readonly debounce?: Duration.Input;\n readonly autoSubmit?: boolean;\n }\n) & { readonly revalidate?: RevalidateMode };\n\n/** The fully-resolved form of a {@link FormMode} — every field decided. */\nexport interface ParsedMode {\n readonly validation: \"onSubmit\" | \"onBlur\" | \"onChange\";\n /** Debounce in milliseconds, or `null` for no debounce. */\n readonly debounce: number | null;\n readonly autoSubmit: boolean;\n /** What re-validates the form once it has been posted at least once. Defaults to `\"onChange\"`. */\n readonly revalidate: RevalidateMode;\n}\n\n/**\n * Normalise a {@link FormMode} into a {@link ParsedMode}. An absent mode is\n * `onSubmit`. `debounce` is resolved to milliseconds and only applies in\n * `onChange`; `autoSubmit` is only honoured for `onBlur` / `onChange`;\n * `revalidate` defaults to `\"onChange\"` (TanStack's / RHF's default\n * post-submit behaviour) regardless of the primary `validation` mode.\n */\nexport function parse(mode?: FormMode): ParsedMode {\n const validation = mode?.validation ?? \"onSubmit\";\n const revalidate = mode?.revalidate ?? \"onChange\";\n\n if (validation === \"onBlur\") {\n return {\n validation: \"onBlur\",\n debounce: null,\n autoSubmit: mode?.autoSubmit === true,\n revalidate,\n };\n }\n\n if (validation === \"onChange\") {\n const debounce = mode?.debounce === undefined ? null : Duration.toMillis(mode.debounce);\n return { validation: \"onChange\", debounce, autoSubmit: mode?.autoSubmit === true, revalidate };\n }\n\n return { validation: \"onSubmit\", debounce: null, autoSubmit: false, revalidate };\n}\n","/**\n * {@link FormActionResult} — the framework-neutral outcome of a form\n * submission handler.\n *\n * SvelteKit's `ActionResult` (`success` / `failure` / `redirect` / `error`) is\n * Svelte-specific; this is the same idea expressed as a plain tagged union so\n * a server handler in any framework can describe what happened, and a client\n * adapter can interpret it uniformly. A Svelte adapter maps this onto\n * SvelteKit's `ActionResult`; a fetch client reads the JSON shape directly.\n *\n * @copyright Thomas Foster\n * @module effect-forms/Result\n */\n\nimport type { FormState } from \"./State.ts\";\n\n/** The submission validated and the command ran; carries the resulting state. */\nexport interface FormSuccess<A, Message> {\n readonly _tag: \"Success\";\n readonly status: number;\n readonly state: FormState<A, Message>;\n}\n\n/** The submission was rejected (validation or a user-fixable command failure). */\nexport interface FormFailure<A, Message> {\n readonly _tag: \"Failure\";\n readonly status: number;\n readonly state: FormState<A, Message>;\n}\n\n/** The handler asks the client to navigate elsewhere (post-success redirect). */\nexport interface FormRedirect {\n readonly _tag: \"Redirect\";\n readonly status: number;\n readonly location: string;\n}\n\n/** An unexpected (non-user-fixable) error: surface it, don't bind it to fields. */\nexport interface FormErrorResult {\n readonly _tag: \"Error\";\n readonly status: number;\n readonly message: string;\n}\n\n/** The outcome of a form submission. */\nexport type FormActionResult<A, Message = unknown> =\n | FormSuccess<A, Message>\n | FormFailure<A, Message>\n | FormRedirect\n | FormErrorResult;\n\n/**\n * The data a server form action returns to the client on a non-redirect\n * outcome — the wire contract a client adapter applies back to its store. A\n * validation failure carries the {@link FormState} (`form`); an unexpected\n * error carries a root `message`.\n */\nexport interface FormActionData<A = unknown, Message = unknown> {\n /** The form state (nested errors + posted values) for the client to apply. */\n readonly form?: FormState<A, Message>;\n /** A root-level message for an unexpected (non-field) failure. */\n readonly message?: string;\n}\n\n/** Construct a {@link FormSuccess} (default status 200). */\nexport const success = <A, Message>(\n state: FormState<A, Message>,\n status = 200,\n): FormActionResult<A, Message> => ({ _tag: \"Success\", status, state });\n\n/** Construct a {@link FormFailure} (default status 400). */\nexport const failure = <A, Message>(\n state: FormState<A, Message>,\n status = 400,\n): FormActionResult<A, Message> => ({ _tag: \"Failure\", status, state });\n\n/** Construct a {@link FormRedirect} (default status 303). */\nexport const redirect = <A, Message>(\n location: string,\n status = 303,\n): FormActionResult<A, Message> => ({ _tag: \"Redirect\", status, location });\n\n/** Construct a {@link FormErrorResult} (default status 500). */\nexport const errorResult = <A, Message>(\n message: string,\n status = 500,\n): FormActionResult<A, Message> => ({ _tag: \"Error\", status, message });\n","/**\n * Low-level validation helpers — decode a value through a schema and get back\n * the {@link FormErrors} tree (or the list of {@link FormIssue}s) instead of a\n * raised failure. `Form.make` is the high-level entry; these are for ad\n * hoc field- or value-level validation (e.g. a Svelte client validating a\n * single field on blur).\n *\n * The second half of the module is per-field validators: {@link\n * SyncFieldValidator} / {@link AsyncFieldValidator} (bundled as {@link\n * FieldValidators}) are the framework-neutral shape a reactive store attaches\n * to one field, mirroring TanStack Form's `validators.onChange(Async)` /\n * `onBlur(Async)`. {@link runSyncFieldValidator} runs one synchronously;\n * {@link runAsyncFieldValidator} builds the debounced Effect an async one\n * runs as — the store is responsible for forking it into a fiber per field\n * and interrupting the previous fiber on every new run (see that function's\n * docs for why that alone gives debounce + \"latest wins\" cancellation).\n *\n * @copyright Thomas Foster\n * @module effect-forms/Validate\n */\n\nimport * as Duration from \"effect/Duration\";\nimport * as Effect from \"effect/Effect\";\nimport type * as Schema from \"effect/Schema\";\nimport * as SchemaParser from \"effect/SchemaParser\";\nimport { type FormErrors, issuesToErrors } from \"./Errors.ts\";\nimport {\n filterOutputToFormIssues,\n type FormIssue,\n type LeafFormatter,\n schemaIssuesToFormIssues,\n} from \"./Issues.ts\";\n\n/** The outcome of validating a value against a schema. */\nexport type ValidationResult<A> =\n | { readonly valid: true; readonly data: A }\n | {\n readonly valid: false;\n readonly errors: FormErrors;\n readonly issues: ReadonlyArray<FormIssue>;\n };\n\n/**\n * Decode `input` through `schema`, returning a {@link ValidationResult} on the\n * success channel (decode failures become `valid: false`, not an Effect\n * failure). Decoding-service requirements propagate on the `R` channel.\n */\nexport function validateValue<S extends Schema.Top>(\n schema: S,\n input: unknown,\n format?: LeafFormatter,\n): Effect.Effect<ValidationResult<S[\"Type\"]>, never, S[\"DecodingServices\"]> {\n return SchemaParser.decodeUnknownEffect(schema, { errors: \"all\" })(input).pipe(\n Effect.matchEffect({\n onSuccess: (data): Effect.Effect<ValidationResult<S[\"Type\"]>> =>\n Effect.succeed({ valid: true, data }),\n onFailure: (issue): Effect.Effect<ValidationResult<S[\"Type\"]>> => {\n const issues = schemaIssuesToFormIssues(issue, format);\n return Effect.succeed({ valid: false, errors: issuesToErrors(issues), issues });\n },\n }),\n );\n}\n\n/**\n * Synchronous {@link validateValue} for schemas with no decoding-service\n * requirements (`R = never`) and no async decoding — the common case for plain\n * form schemas. {@link validateValue} never fails on the error channel, so\n * running it with {@link Effect.runSync} is total.\n */\nexport function validateValueSync<S extends Schema.Top>(\n schema: S,\n input: unknown,\n format?: LeafFormatter,\n): ValidationResult<S[\"Type\"]> {\n // `validateValue` never fails on the error channel; the cast drops the\n // decoding-service requirement, which the caller asserts is `never` (the\n // common case for plain form schemas — a service-requiring schema must use\n // the async {@link validateValue}).\n return Effect.runSync(\n validateValue(schema, input, format) as Effect.Effect<ValidationResult<S[\"Type\"]>>,\n );\n}\n\n/**\n * A synchronous per-field validator — TanStack Form's `validators.onChange` /\n * `onBlur` shape. Sees the field's decoded value and returns a {@link\n * Schema.FilterOutput} (`undefined` / `true` to pass, a message / issue /\n * list to fail), the same vocabulary a schema `check` or a {@link\n * module:effect-forms/FormBuilder} `refine` predicate uses.\n */\nexport type SyncFieldValidator<A> = (value: A) => Schema.FilterOutput;\n\n/**\n * An asynchronous per-field validator — TanStack Form's `onChangeAsync` /\n * `onBlurAsync`. An Effect (not a `Promise`) so its `R` channel can demand\n * services (an API client, a cache) the way a {@link\n * module:effect-forms/FormBuilder} `refineEffect` refinement does; a caller\n * running this client-side supplies `R` via a `Layer` / runtime, or keeps it\n * `never` for a plain `fetch`-based check.\n */\nexport type AsyncFieldValidator<A, R = never> = (\n value: A,\n) => Effect.Effect<Schema.FilterOutput, never, R>;\n\n/**\n * The validators one field declares, mirroring TanStack Form's per-field\n * `validators` option. `asyncDebounceMs` (default `0`, meaning no debounce)\n * governs both async variants; see {@link runAsyncFieldValidator} for how the\n * debounce and cancellation actually work.\n */\nexport interface FieldValidators<A, R = never> {\n readonly onChange?: SyncFieldValidator<A>;\n readonly onBlur?: SyncFieldValidator<A>;\n readonly onChangeAsync?: AsyncFieldValidator<A, R>;\n readonly onBlurAsync?: AsyncFieldValidator<A, R>;\n readonly asyncDebounceMs?: number;\n}\n\n/**\n * Run a {@link SyncFieldValidator}, folding its {@link Schema.FilterOutput}\n * into {@link FormIssue}s (empty on success). Total — a sync field validator\n * cannot fail the Effect error channel.\n */\nexport function runSyncFieldValidator<A>(\n validator: SyncFieldValidator<A>,\n value: A,\n): ReadonlyArray<FormIssue> {\n return filterOutputToFormIssues(validator(value));\n}\n\n/**\n * Build the Effect an {@link AsyncFieldValidator} run is: sleep `debounceMs`\n * (a no-op at `0`, the default), then run `validator` and fold its output\n * into {@link FormIssue}s.\n *\n * The debounce is a plain {@link Effect.sleep}, so it rides Effect's `Clock`\n * — deterministic and instantly-advanceable under `TestClock` in tests, real\n * time otherwise (no `setTimeout` bookkeeping for a caller to manage).\n * \"Latest wins\" falls out of ordinary fiber interruption: a caller re-running\n * this on every keystroke forks a fresh fiber per call and interrupts the\n * previous one before forking the next — interrupting mid-sleep skips the\n * validator entirely (a true debounce, not just a discarded stale result),\n * and interrupting mid-validator aborts whatever the validator was doing\n * (e.g. an in-flight `fetch` wrapped as an Effect).\n */\nexport function runAsyncFieldValidator<A, R>(\n validator: AsyncFieldValidator<A, R>,\n value: A,\n debounceMs = 0,\n): Effect.Effect<ReadonlyArray<FormIssue>, never, R> {\n return Effect.gen(function* () {\n if (debounceMs > 0) yield* Effect.sleep(Duration.millis(debounceMs));\n const output = yield* validator(value);\n return filterOutputToFormIssues(output);\n });\n}\n\n/** Which trigger a {@link FieldValidators} sync/async pair reacts to. */\nexport type FieldTrigger = \"change\" | \"blur\";\n\n/** The validator(s) (if any) that apply for one field trigger — see {@link resolveFieldTrigger}. */\nexport interface ResolvedFieldTrigger<A, R = never> {\n readonly sync: SyncFieldValidator<A> | undefined;\n readonly async: AsyncFieldValidator<A, R> | undefined;\n readonly asyncDebounceMs: number;\n}\n\n/**\n * Pick `validators`' sync/async pair for `trigger` (TanStack's `onChange` /\n * `onBlur` vs `onChangeAsync` / `onBlurAsync`). A reactive store calls this\n * once per trigger instead of repeating the trigger ternary at each call\n * site — the pure decision half of what {@link module:effect-forms-svelte/FormStore}'s\n * field-trigger dispatch runs.\n */\nexport function resolveFieldTrigger<A, R = never>(\n validators: FieldValidators<A, R> | undefined,\n trigger: FieldTrigger,\n): ResolvedFieldTrigger<A, R> {\n return {\n sync: trigger === \"change\" ? validators?.onChange : validators?.onBlur,\n async: trigger === \"change\" ? validators?.onChangeAsync : validators?.onBlurAsync,\n asyncDebounceMs: validators?.asyncDebounceMs ?? 0,\n };\n}\n"],"mappings":"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"}
|