Skip to content

Releases: block65/openapi-codegen

v14.0.0

Choose a tag to compare

@maxholman maxholman released this 27 Sep 12:44

Breaking

  • @block65/rest-client 16 is required. Generated commands use its sequential media commands and parse hooks. Upgrade the peer dependency, then regenerate.
  • Validated commands set an instance field. A validated subclass now sets responseSchema (or dataSchema for a stream) as an instance field instead of static responseSchema, because that is where rest-client 16's parse hooks look.
  • text/event-stream without an itemSchema is a plain Command. It is no longer typed as Uint8Array chunks.
  • A bodiless success is undefined, and no success is never. A 2xx response without content types the output as undefined, which is what json() and send() resolve with. An operation documenting no 2xx response at all gets never. Both used to be unknown.
  • Open values are JsonValue on both sides. An empty schema, an untyped record value or an array without items is typed JsonValue instead of Jsonifiable, and valibot checks it recursively instead of accepting unknown.
  • Only local $refs are read. A $ref to another file or a URL stops generation and names the ref; it used to be fetched at codegen time. @apidevtools/json-schema-ref-parser is no longer a dependency.

Sequential media commands

A 2xx response whose media type has an OAS 3.2 itemSchema becomes a sequential command. For text/event-stream it extends rest-client's EventStreamCommand, whose output is the union of each item's data contentSchema, so client.stream() yields typed, parsed events. A contentMediaType of text/plain sets the text data transformer, and JSON is the default. A construct that doesn't fit stops generation and names the operation, as does an itemSchema in a document older than 3.2.

Documents are read as OAS 3.2, and a 3.1 document is read unchanged. A schema may be true or false, and a media type may be a $ref.

Recursive schemas

A schema that contains itself, or schemas that refer to each other, used to fail with "Cyclic dependency". They now generate, with v.lazy on the valibot side. An acyclic document generates byte-identical output.

$ref fixes

  • A $ref that escapes a name as a JSON pointer does (~1, ~0), is percent-encoded, or points into part of a component now resolves. A ref into part of a component is inlined, keeping any keywords beside the $ref.
  • A $ref to a schema the document doesn't define stops generation, giving the ref's JSON pointer. It used to fail later as "ref used before available".
  • Component order follows every nested $ref, and only refs in subschemas count. A $ref-shaped key inside example, default, const or enum is data.

Type fixes

  • Nullable object, array and string types admit null, as their valibot schemas always did.
  • required is honoured on object schemas that omit type.
  • additionalProperties records are keyed by string, not string | number.

Faster generation

Large modules are built in chunks. Output is byte-identical, and the openai document generates in 8s instead of 59s.

v13.0.0

Choose a tag to compare

@maxholman maxholman released this 23 Sep 10:10

Breaking

  • @block65/openapi-codegen/oxlint is removed. It pointed at a .ts file, which node refuses to load from node_modules, so importing it broke the consumer's lint. Delete the override from your lint config and regenerate.
  • in: cookie stops generation. No command or validator reads a cookie, so the parameter used to be dropped without a word. Generation now throws naming the operation and the parameter, as in: querystring does.
  • Open object schemas are lint errors. prefer-strict-object is never exempt: an object the document leaves open fails the consumer's lint until the document sets additionalProperties: false.

Lint directives in generated files

Every run lints every generated file with the project's own oxlint and config. Each file gets one // oxlint-disable line naming only the exempt rules that fired in it, so reportUnusedDisableDirectives stays satisfied and the directives follow the current config, including after an upgrade. A file that lands on its recorded revision keeps its bytes on disk. Without oxlint in the project the files get no directive.

A header schema is v.object() on purpose, because a request carries headers the document does not name. Where prefer-strict-object fires on one, its declaration is bracketed by a disable and enable that say so.

Dependencies

oxlint plugin 0.11.0 and shared-config 0.5.0. The plugin deletes snake-case-wire-keys, so it is no longer exempt.

v12.0.0

Choose a tag to compare

@maxholman maxholman released this 22 Sep 12:38

Generated commands name the @block65/rest-client 15 query serializer for the style their document states, so the peer dependency moves to ^15.0.0. This is the breaking change.

  • A command whose query parameters use a style other than form with explode overrides querySerializer with the matching serializer, imported by name. One that states none inherits formExplodeSerializer, the OpenAPI default. An operation whose parameters need two serializers stops generation with the pair named.
  • A one-member anyOf or oneOf is emitted as its member instead of v.union([member]), and an empty one as v.unknown().
  • Generated modules lint clean under @block65/shared-config 0.4.0 with the valibot rule group enabled. defineOverrides turns off prefer-strict-object, prefer-exact-optional and snake-case-wire-keys for generated files, with the reason for each in the shipped source.

What's Changed

  • Clear the lint backlog and refresh dependencies by @maxholman[bot] in #21
  • refactor: pass each phase a context instead of shared loop state by @maxholman[bot] in #22
  • feat(query): emit the document's query serializer on rest-client 15 by @maxholman[bot] in #23

Full Changelog: v11.0.0...v12.0.0

v11.0.0

Choose a tag to compare

@maxholman maxholman released this 02 Sep 09:28

Breaking

  • The generated Hono integration is now hono.ts (was hono-valibot.ts), validating requests through Standard Schema (~standard.validate) instead of valibot directly.
  • Generated output requires @block65/rest-client >= 14, which replaces PublicValibotHonoError with PublicValidationError.

New

  • Generated files carry a content-hash stamp in the banner and are left untouched when regeneration produces unchanged content — no more date-only churn, robust against downstream formatters.

v10.2.0

Choose a tag to compare

@maxholman maxholman released this 22 Jun 12:39

feat: narrow generated types and validators to the real data contract

  • RFC 3339 string formats (date, date-time, time, duration) now emit template-literal types plus matching regex validators. Previously only date-time was handled, as the opaque `Jsonify`.
  • integer/int64 now maps to `bigint` (range exceeds Number.MAX_SAFE_INTEGER).
  • enums emit a bare picklist/literal/union, including null and non-string members.

Breaking for consumers: `DateTime` is now a template-literal string instead of `Jsonify`, and int64 fields are `bigint` instead of `number`.

Also: CI runs on node 26; test target typechecks lib/ and bin/.

v10.1.0

Choose a tag to compare

@maxholman maxholman released this 08 Jun 03:22

What's new

Features

  • minProperties / maxProperties support — object schemas now emit v.minEntries() / v.maxEntries() constraints (plain objects, empty-property records, and allOf compositions). Previously these JSON Schema keywords were silently dropped.
  • ResponseValidationError re-export — generated main.ts now re-exports ResponseValidationError from @block65/rest-client, so consumers get instanceof narrowing without adding a direct dependency.

Maintenance

  • Regenerated all fixtures.
  • Bumped dependencies to latest (@block65/rest-client 13.1.0, undici 8.4.0, and others).
  • Tests pin retries: 0 via an explicit fetcher and disable timeouts (vitest.config.ts); fixed the petstore mock path for explode-style array query serialization.

Full Changelog: v10.0.6...v10.1.0

v10.0.6

Choose a tag to compare

@maxholman maxholman released this 18 May 11:17
  • main.ts emits file-level `import type { … }` instead of per-name `import { type X }` for type-only imports.
  • Optional query/header params no longer carry a redundant `| undefined` union — optionality is conveyed by `?:` alone.
  • Pairs with `@block65/rest-client@13.0.5` `CommandQuery` constraint relaxation; generated query types satisfy it while remaining `JsonObject`-clean.
  • Adds regression tests covering import shape, optional query types, and `AllInputs` membership.

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).
  • exactPetSchema → inputPetSchema: 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.

v10.0.4

Choose a tag to compare

@maxholman maxholman released this 11 May 05:30

Highlights

  • New: two-file commands output. Codegen now emits commands.ts (lean, no schema imports) alongside commands-validated.ts (subclasses that attach static responseSchema). Consumers swap files (or bundler-alias dev → validated) to opt into response validation without paying bundle cost in prod. Pairs with @block65/rest-client 13.0.4 which drops the validateResponses flag and validates whenever a schema is present.

  • Fix: inline 2xx response schemas no longer silently skipped. Operations whose 2xx body is an inline object with nested \$refs (e.g. { user: { \$ref: \"...\" } }) now correctly emit a per-command response schema. Previously the codegen fell through and validateResponses: true was a silent no-op for those commands — a real production leak class.

  • Fix: array responses now validate as arrays. Endpoints like Pet[] previously had static responseSchema = petSchema (single Pet, wrong — the response is the whole array). Now emit v.array(petSchema).

Removed

  • Static bodySchema, paramsSchema, querySchema are no longer attached to generated Command classes. rest-client never read them, and Hono middleware imports schemas directly from valibot.ts already — they were pure bundle overhead.

Generated output

  • Namespace imports (import * as commands / import * as schemas) in the validated file keep diffs stable across regenerations.

Dependencies

  • Peer dep: @block65/rest-client ^13.0.3 (required for schema-presence-driven validation).
  • Misc dep rollforward: valibot 1.4, hono 4.12.18, etc.

Note on versioning

Strictly this should be a major bump (peer dep range moved 12 → 13, generated output changed). Released as a patch given a single pre-launch consumer.

v10.0.3

Choose a tag to compare

@maxholman maxholman released this 09 May 08:24

Full Changelog: v10.0.2...v10.0.3