feat!: migrate to @openapi-spec types and target OpenAPI 3.2 with a version option - #1998
Conversation
…ersion option Replace json-schema-typed and @hey-api/spec-types with @openapi-spec/types. JsonSchema is the OpenAPI 3.2 Schema Object, @orpc/openapi re-exports the OpenAPIV3_0/1/2 namespaces and builds documents as OpenAPI 3.2. A new `version` option on generate() downgrades to 3.1 or 3.0 with @openapi-spec/downgrader, base no longer carries `openapi`, and the returned document type follows the requested version.
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
More templates
@orpc/ai-sdk
@orpc/arktype
@orpc/bun
@orpc/client
@orpc/cloudflare
@orpc/contract
@orpc/experimental-effect
@orpc/evlog
@orpc/hibernation
@orpc/json-schema
@orpc/experimental-msw
@orpc/nest
@orpc/next
@orpc/node
@orpc/openapi
@orpc/opentelemetry
@orpc/pinia-colada
@orpc/pino
@orpc/publisher
@orpc/ratelimit
@orpc/server
@orpc/shared
@orpc/swr
@orpc/tanstack-query
@orpc/trpc
@orpc/valibot
@orpc/zod
commit: |
There was a problem hiding this comment.
ℹ️ The migration is in good shape — one wrong literal in the migration guide, plus a coverage gap worth a cheap safety net.
Reviewed changes
This PR migrates @orpc/json-schema and @orpc/openapi from json-schema-typed / @hey-api/spec-types to @openapi-spec/types, and makes OpenAPIGenerator emit OpenAPI 3.2 by default with a version option that downgrades the finished document to 3.1/3.0 through @openapi-spec/downgrader:
@orpc/json-schema—JsonSchemais now the OpenAPI 3.2 Schema Object;JsonSchemaKeywordsderives from its declared fields;JsonSchemaType/JsonSchemaFormatbecome hand-written enums replacing thejson-schema-typedre-exports.@orpc/openapitypes — theOpenAPIVersiontemplate type and version-conditionalOpenAPIDocument<TVersion>;OpenAPIV3_0/OpenAPIV3_1/OpenAPIV3_2re-exported;OpenAPIOperationObjectremoved.OpenAPIGenerator— theversionoption (default3.2.0), version-typed return, the 3.2 → 3.1 → 3.0 downgrade pipeline before serialization,base.openapino longer accepted, and the QUERY guard now keyed off the requested version.- Mechanics — numeric response statuses stringified via
toResponseStatusKey(the 3.2ResponsesObjectindex signature is string-typed); the coercer adjusted for the narroweritems/additionalItemstyping. - Docs & skills — the
### OpenAPI Versionsection, the v1 migration note, and theorpc-openapiskill description.
I ran the openapi + json-schema suites (617 tests, all pass) and the root type check (exit 0, which validates the new openapi-generator.test-d.ts version-return assertions). I also pushed a real $defs-heavy e2e router (zod converter, shared Planet component, output unions) through 3.1.2 and 3.0.4: hoisted components rewrite cleanly to #/components/schemas/… with no dangling #/$defs/ refs after the downgrade, and type: ['string', 'null'] becomes nullable: true.
ℹ️ The downgrade path is only exercised by one synthetic router
The new version tests all drive a single hand-built router (one path param, one nullable string output). Nothing runs a real e2e router — crud, reusable-components, or typed-errors, which exercise $defs hoisting, component reuse, allOf compositions, and error bodies — at 3.1 or 3.0. The @openapi-spec/downgrader README documents that 3.1 → 3.0 removes the $defs keyword and can leave #/$defs/… refs dangling ("hoist reusable subschemas into components.schemas before downgrading"); oRPC's registry hoists root $defs (rewriting refs), which sidesteps that for zod-derived schemas, but $defs nested inside a component body or in a user-supplied base.components would not be. My probe showed the common path is clean, so this is a safety net rather than a known bug — generating the existing crud router at version: '3.1.2' and '3.0.4' (asserting no #/$defs/ refs and nullable conversion) would pin the behavior the feature promises.
Technical details
# Add a version-parameterized e2e downgrade test
## Affected sites
- packages/openapi/tests/openapi-generator/crud.test.ts (or reusable-components.test.ts) — currently only generate without a `version` (default 3.2.0)
## Required outcome
- Generate an existing $defs/component-heavy e2e router at 3.1.x and 3.0.x and assert the document downgrades cleanly: every `$ref` resolves (`#/components/schemas/…`), no `#/$defs/…` refs remain, and a `type: [T, 'null']` schema becomes `nullable: true`.
## Suggested approach
- Parameterize the existing e2e `describe` with `it.each(['3.2.0', '3.1.2', '3.0.4'])` and assert the `openapi` field, a couple of `$ref`-anchored schemas, and one nullable conversion.ℹ️ Nitpicks
packages/openapi/src/openapi-generator.ts:198— theas OpenAPIDocument<TVersion>cast on the serializer result is the same shape as before; nothing to change, just noting the serializer return goes straight through the versioned type.
DeepSeek Flash (free via Pullfrog for OSS) | 𝕏
There was a problem hiding this comment.
🟡 Changes recommended
Version validation and keyword typing can accept invalid values, and the migration guide names the wrong legacy version.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
Migrates OpenAPI and JSON Schema typing to @openapi-spec, defaults generation to OpenAPI 3.2, and adds downgrade support.
Changes:
- Adds version-aware OpenAPI 3.0/3.1/3.2 generation.
- Replaces legacy schema/spec type dependencies.
- Updates tests, documentation, and skills for OpenAPI 3.2.
File summaries
| File | Description |
|---|---|
tests/plugins/all-plugins.test.ts |
Updates the integration spec to OpenAPI 3.2. |
skills/orpc/SKILL.md |
Documents OpenAPI 3.2 generation. |
skills/orpc-openapi/SKILL.md |
Documents selectable versions and downgrading. |
pnpm-workspace.yaml |
Exempts new dependencies from release-age checks. |
pnpm-lock.yaml |
Updates resolved dependencies. |
packages/zod/package.json |
Replaces the legacy schema type dependency. |
packages/openapi/tests/openapi-generator/typed-errors.test.ts |
Uses string response status keys. |
packages/openapi/tests/openapi-generator/reusable-components.test.ts |
Uses string response status keys. |
packages/openapi/tests/openapi-generator/file-transfer.test.ts |
Uses string response status keys. |
packages/openapi/tests/openapi-generator/event-streaming.test.ts |
Uses string response status keys. |
packages/openapi/tests/openapi-generator/crud.test.ts |
Uses string response status keys. |
packages/openapi/src/types.ts |
Adds versioned OpenAPI document types and namespace exports. |
packages/openapi/src/types.test-d.ts |
Tests document type selection. |
packages/openapi/src/plugins/openapi-reference.ts |
Accepts documents from all supported versions. |
packages/openapi/src/plugins/openapi-reference.test.ts |
Updates plugin test document typing. |
packages/openapi/src/openapi-generator.ts |
Adds version selection and document downgrading. |
packages/openapi/src/openapi-generator.test.ts |
Tests versioned output and serialization order. |
packages/openapi/src/openapi-generator.test-d.ts |
Tests version-dependent return types. |
packages/openapi/src/openapi-generator-operation.ts |
Migrates operation generation to 3.2 types. |
packages/openapi/src/openapi-generator-operation.test.ts |
Updates operation tests for 3.2 types. |
packages/openapi/src/openapi-generator-components.ts |
Migrates component handling to 3.2 types. |
packages/openapi/src/openapi-generator-components.test.ts |
Updates component test documents. |
packages/openapi/src/meta.ts |
Types custom operation metadata as OpenAPI 3.2. |
packages/openapi/package.json |
Adds types and downgrader dependencies. |
packages/json-schema/src/types.ts |
Derives JSON Schema types from OpenAPI 3.2. |
packages/json-schema/src/composition-utils.test.ts |
Adjusts contextual schema typing. |
packages/json-schema/src/coercer.ts |
Preserves legacy additionalItems coercion. |
packages/json-schema/package.json |
Replaces json-schema-typed. |
eslint.config.js |
Restricts direct imports of the new type package. |
apps/content/docs/openapi/specification.mdx |
Documents version selection and downgrading. |
apps/content/docs/migrations/from-v1.mdx |
Adds migration guidance for the new default. |
Review details
Files not reviewed (1)
- pnpm-lock.yaml: Generated file
- Files reviewed: 30/31 changed files
- Comments generated: 3
- Review effort level: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| export type JsonSchemaKeywords = keyof { | ||
| [K in keyof OpenAPIV3_2.SchemaObjectFields as string extends K ? never : K]: unknown | ||
| } |
| * | ||
| * @see {@link https://orpc.dev/docs/openapi/specification#openapi-version | OpenAPI Specification - OpenAPI Version} | ||
| */ | ||
| export type OpenAPIVersion = `3.0.${number}` | `3.1.${number}` | `3.2.${number}` |
|
|
||
| - The `oo` helper (`oo.spec`) was removed. To customize the operation object, attach [`openapi({ spec })` metadata](/docs/openapi/specification#customizing-the-operation-object) directly on the procedure or router. | ||
| - The `shouldHoistDef` option was replaced by [`customComponentName`](/docs/openapi/specification#hoisting-defs). Root `$defs` are now always hoisted into `components.schemas`; this option only renames them. | ||
| - Documents are generated as OpenAPI 3.2.0 by default. Pass [`version: '3.1.1'`](/docs/openapi/specification#openapi-version) to keep old behavior. |

Replaces
json-schema-typedand@hey-api/spec-typeswith@openapi-spec/types, soJsonSchemais the OpenAPI 3.2 Schema Object and@orpc/openapire-exports theOpenAPIV3_0,OpenAPIV3_1, andOpenAPIV3_2namespaces.OpenAPIGeneratornow builds OpenAPI 3.2 documents and takes aversionoption that downgrades to 3.1 or 3.0 through@openapi-spec/downgrader, with the return type following the requested version.Breaking changes
generate()emits3.2.0by default (was3.1.2). Passversion: '3.1.2'to keep 3.1 documents.baseno longer acceptsopenapi.OpenAPIDocumentrequires a version argument;OpenAPIDocument<OpenAPIVersion>is the union of every supported document.OpenAPIOperationObjectis replaced byOpenAPIV3_2.OperationObject.JsonSchemaKeywordsis derived from the 3.2 Schema Object, so legacy keywords such asadditionalItemsare no longer part of it.Behavior
3.0.x,3.1.x, or3.2.xversionis accepted. The minor version selects the conversion and the document carries the exact requested value.base,openapi({ spec }), converter output) stays OpenAPI 3.2 and is downgraded with the rest of the document, sotype: ['string', 'null']becomesnullable: truein 3.0 output.Docs
versionin its own section, and the v1 migration guide notes the new default.Testing
3.2.0,3.2.7,3.1.2,3.1.0,3.0.4, and3.0.0, with type tests for the version-dependent return type.