Skip to content

v10.0.5

Choose a tag to compare

@maxholman maxholman released this 11 May 07:13

Fix: optional handling now matches direction of data flow

The previous exact / coerced split conflated two orthogonal concerns — whether to coerce wire strings and whether to tolerate undefined. The result: server-side hono middleware and client-side response parsing were both wrapping optional fields in v.optional(...), which permits undefined even though JSON-parsed wire data can never carry one. Handlers had to defensively guard against { field: undefined } cases that were structurally impossible.

Realigned the schemas along direction of data flow:

  • inputXxxSchema — for outgoing TS-side values (request bodies before JSON.stringify, pre-flight validation). Uses v.optional(...). No wire coercion (types are already TS-native). Tolerates the destructure-with-default { foo: undefined } pattern.

  • xxxSchema (wire) — for incoming JSON-parsed values (hono middleware, rest-client response parsing). Uses v.exactOptional(...) — field is present-with-value or absent, never undefined. Includes bigint / number coercion for HTTP wire formats.

For server handlers, the win is concrete: c.req.valid(\"json\") now returns { name: string, nickname?: string } rather than { name: string, nickname: string | undefined }. No phantom-undefined to guard against.

Renames

Before After
exactPetSchema inputPetSchema
petSchema (with v.optional + coercion) petSchema (with v.exactOptional + coercion)
--exact-only --input-only
CodegenOptions.exactOnly CodegenOptions.inputOnly
SchemaMode "exact" / "coerced" "input" / "wire"

Behavioral changes

  • petSchema (wire variant, same name as before): optional fields now use v.exactOptional instead of v.optional. Strictly correct for JSON-parsed data; would reject { field: undefined } if it ever appeared (it can't, after JSON.parse).
  • exactPetSchemainputPetSchema: optional handling flipped from v.exactOptional to v.optional. Use this for client-side pre-flight validation where TS callers may pass undefineds.

Versioning note

Strictly a major bump (renames + flipped semantics). Released as patch given a single pre-launch consumer.