Repository navigation
feat(effect)!: support Effect Schema in .errors and rename extension to schema - #2341
Conversation
…n to `schema` The `@orpc/effect/extensions/input-output` extension is renamed to `@orpc/effect/extensions/schema`, since it now covers more than `.input` and `.output`: Effect Schemas can also be used as error `data` in `.errors` on the contract builder, the procedure builder (all variants), and decorated procedures. Effect Schemas are converted to Standard Schemas, error maps without them are passed through untouched, and hidden meta plugins on the error map are preserved. BREAKING CHANGE: import `@orpc/effect/extensions/schema` instead of `@orpc/effect/extensions/input-output`. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011yypgknaDUG4ZWXZfin3Zc
Derive `EffectErrorMapItem` from `ErrorMapItem` instead of redeclaring its fields, copy the error map once in `toStandardErrorMap`, and cover error factories in the `.errors` type tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011yypgknaDUG4ZWXZfin3Zc
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
orpc | 29f9d1f | Commit Preview URL Branch Preview URL |
Oct 26 2026, 12:50 PM |
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
Merging this PR will not alter performance1 warning
Comparing Footnotes
|
More templates
@orpc/ai-sdk
@orpc/arktype
@orpc/bun
@orpc/client
@orpc/cloudflare
@orpc/contract
@orpc/effect
@orpc/evlog
@orpc/hibernation
@orpc/json-schema
@orpc/experimental-lock
@orpc/mcp
@orpc/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.
✅ No new issues found.
Reviewed changes
.errorsaccepts Effect Schemas — a newtoStandardErrorMapshallow-copies the error map and converts only items whosedatais an Effect Schema (EffectSchema.isSchema) via the existingtoStandardSchema, leaving every other item untouched;ContractBuilder.prototype.errors,Builder.prototype.errors, andDecoratedProcedure.prototype.errorsare patched, which covers everyoc/osvariant since all variants areContractBuilder/Builderinstances at runtime.- Types — new exported
EffectErrorMap,EffectErrorMapItem, andToStandardErrorMap<T>(T extends ErrorMap ? T : …) keep standard-only maps at their exact type while mapping EffectdatatoSchema<S['Encoded'], S['Type']>, and the augmentation is applied tooc, allProcedureContractBuilder*,Builder*, andDecoratedProcedure. - Rename — the entry point moves from
@orpc/effect/extensions/input-outputto@orpc/effect/extensions/schema(breaking, old path removed) inpackage.jsonexports/publishConfig/sideEffects, with no stale repo references. - Docs — the section is renamed "Schema Extension", gains a
.errorsexample, and notes the standalone-middleware gap (wrap withSchema.toStandardSchemaV1), which matchesDecoratedMiddleware.errorsbeing a per-instance assignment with no prototype to patch. - Tests — runtime coverage for per-builder conversion, pass-through of Effect-free maps (item identity and hidden meta plugins preserved), and an end-to-end decode; type tests cover every builder variant,
DecoratedProcedure, standard-only maps, error-constructor input types, and a@ts-expect-errorfor invalid data.
I re-ran pnpm vitest run packages/effect (111 pass), pnpm exec tsc -p tsconfig.json --noEmit (clean, covers schema.test-d.ts), node scripts/verify-docs-jsdoc.ts (0 errors), and pnpm exec eslint on the changed source/test files (clean). No stale #input-and-output-extensions anchors remain.
One non-actionable note: toStandardErrorMap always returns a fresh map object even when no Effect Schema is present, so map identity changes (items and hidden meta plugins are still preserved via the shallow copy). Nothing in the codebase relies on error-map identity, so this is fine — just slightly broader than the "passed through unchanged" phrasing in the PR description.
deepseek-v4.1-flash (free via Pullfrog for OSS) | 𝕏

Summary
The Effect Schema extension now also covers
.errors, so Effect Schemas can be used as errordata. Because it now does more than.input/.output, it is renamed from@orpc/effect/extensions/input-outputto@orpc/effect/extensions/schema.Changes
.errorsaccepts Effect Schemas as errordataon:oc) and all its variantsos) and all its variants.handler(...)Encoded/Type, the same way.input/.outputalready are. Items that are not Effect Schemas keep their exact type, includingerror(...)factories. A map that uses only Standard Schemas resolves to the same type as before.toStandardSchema.EffectErrorMap,EffectErrorMapItem,ToStandardErrorMap..errorsexample.Not covered
.errorson standalone middleware (os.middleware(...).errors(...)).decorateMiddlewareassigns that method separately on each middleware, so there is no prototype to patch from outside. Passing an Effect Schema there is a type error, not a silent runtime failure, and the docs point toSchema.toStandardSchemaV1as the workaround.Breaking change
Imports of
@orpc/effect/extensions/input-outputmust change to@orpc/effect/extensions/schema. The old path has no alias.Testing
.errorson every builder variant and onDecoratedProcedure, standard-only maps passing through unchanged, error constructor input types, and a@ts-expect-errorfor invalid data. I made each.errorsassertion fail on purpose to confirm it is checked.pnpm vitest run packages/effect, roottsc, eslint,node scripts/verify-docs-jsdoc.ts,blume validate --strict, and anunbuildof the package, which emitsdist/extensions/schema.*.Generated by Claude Code