oRPC support for Temporal types, via temporal-zod.
oRPC generates its OpenAPI documents with its own ZodToJsonSchemaConverter
(from @orpc/zod/zod4), which re-implements the Zod → JSON Schema conversion
instead of calling z.toJSONSchema(). The JSON Schema metadata temporal-zod
attaches to each validator is therefore ignored, and because a Temporal
validator is a z.union([...]) under the hood, the converter emits a messy
anyOf and drops the format/pattern.
bun add temporal-orpc temporal-zod
Pass temporalJsonSchemaInterceptor to the converter, and every Temporal
validator renders as the correct string schema:
import { OpenAPIGenerator } from "@orpc/openapi";
import { ZodToJsonSchemaConverter } from "@orpc/zod/zod4";
import { temporalJsonSchemaInterceptor } from "temporal-orpc";
const generator = new OpenAPIGenerator({
schemaConverters: [
new ZodToJsonSchemaConverter({
interceptors: [temporalJsonSchemaInterceptor],
}),
],
});
So a procedure taking zInstant now documents itself as:
{
"type": "string",
"format": "date-time",
"pattern": "…",
"description": "An ISO 8601 instant string with a required UTC offset (e.g. 2023-01-15T13:45:30Z)"
}
The interceptor is driven by temporal-zod's registry rather than by a per-type
list, so all eight Temporal types are covered — Instant, ZonedDateTime,
PlainDate, PlainTime, PlainDateTime, PlainYearMonth, PlainMonthDay, and
Duration — in both the coercing and *Instance variants.
Only schemas that temporal-zod itself created are rewritten. The interceptor
consults temporalRegistry — a Zod registry scoped to temporal-zod — rather
than z.globalRegistry, which is shared with your whole application. Your own
schemas are left entirely to oRPC, including ones you annotate the same way, such
as z.string().min(5).meta({ type: "string", format: "email" }), which keeps the
minLength oRPC derives from its checks. $ref dedup and example rendering are
untouched.
Prefer the *Instance validators in procedure inputs and outputs if you use
Tanstack Query: a coerced Temporal value is a fresh
object every time, so the query cache will not compare as you expect. See the
temporal-zod README
for the same caveat under tRPC.
Apache-2.0
oRPC support for
temporal-zod.oRPC's
ZodToJsonSchemaConverter(from@orpc/zod/zod4) does not use Zod's ownz.toJSONSchema(). Instead it re-implements the conversion with its own tree walk, so the.meta()JSON Schema thattemporal-zodattaches to each validator is ignored: a Temporal validator is az.union([...])under the hood, so oRPC emits a messyanyOfand drops theformat/patternmetadata.This package fixes that with a single temporalJsonSchemaInterceptor you pass to the converter. It rewrites only the schemas in
temporalRegistry—temporal-zod's own validators — and leaves every other node in your schema tree to oRPC.Example
See
temporal-orpc on GitHub