Skip to content

feat(effect)!: support Effect Schema in .errors and rename extension to schema - #2341

Merged
dinwwwh merged 3 commits into
mainfrom
claude/brave-knuth-0rhu7k
Oct 27, 2026
Merged

dinwwwh merged 3 commits into
mainfrom
claude/brave-knuth-0rhu7k

Conversation

@dinwwwh

@dinwwwh dinwwwh commented Oct 26, 2026

Copy link
Copy Markdown
Member

Summary

The Effect Schema extension now also covers .errors, so Effect Schemas can be used as error data. Because it now does more than .input/.output, it is renamed from @orpc/effect/extensions/input-output to @orpc/effect/extensions/schema.

import '@orpc/effect/extensions/schema'

const procedure = os
  .errors({
    FORBIDDEN: { data: Schema.Struct({ reason: Schema.String }) },
  })
  .input(Schema.Struct({ name: Schema.String }))
  .handler(handlerGen(function* ({ input, errors }) {
    return yield* Effect.fail(errors.FORBIDDEN({ data: { reason: 'Reserved name' } }))
  }))

Changes

  • .errors accepts Effect Schemas as error data on:
    • the contract builder (oc) and all its variants
    • the procedure builder (os) and all its variants
    • decorated procedures, i.e. after .handler(...)
  • Types: error data is typed from the schema's Encoded/Type, the same way .input/.output already are. Items that are not Effect Schemas keep their exact type, including error(...) factories. A map that uses only Standard Schemas resolves to the same type as before.
  • Runtime:
    • Effect Schemas are converted with the existing toStandardSchema.
    • Error maps with no Effect Schemas are passed through unchanged.
    • Hidden meta plugins on the error map are kept.
  • New exported types: EffectErrorMap, EffectErrorMapItem, ToStandardErrorMap.
  • The docs section is now "Schema Extension" and includes a .errors example.

Not covered

.errors on standalone middleware (os.middleware(...).errors(...)). decorateMiddleware assigns 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 to Schema.toStandardSchemaV1 as the workaround.

Breaking change

Imports of @orpc/effect/extensions/input-output must change to @orpc/effect/extensions/schema. The old path has no alias.

Testing

  • Runtime tests:
    • each patched builder converts only the Effect Schema items
    • maps with no Effect Schemas are passed through as-is
    • hidden meta plugins are kept
    • a procedure that throws an Effect-schema error returns a defined error whose data has been decoded
  • Type tests: .errors on every builder variant and on DecoratedProcedure, standard-only maps passing through unchanged, error constructor input types, and a @ts-expect-error for invalid data. I made each .errors assertion fail on purpose to confirm it is checked.
  • Checks run: pnpm vitest run packages/effect, root tsc, eslint, node scripts/verify-docs-jsdoc.ts, blume validate --strict, and an unbuild of the package, which emits dist/extensions/schema.*.

Generated by Claude Code

…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
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Oct 26, 2026 •

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

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

codecov Bot commented Oct 26, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@codspeed

codspeed Bot commented Oct 26, 2026 •

Copy link
Copy Markdown
Contributor

Merging this PR will not alter performance

1 warning

⚠️ 5 benchmarks are dominated by system calls

System calls cannot be simulated consistently and are left out of the measure. The reported value understates the real cost. Switch to the Walltime instrument to measure them.

Learn more about system calls

See affected benchmarks

✅ 28 untouched benchmarks
⏩ 2 skipped benchmarks1


Comparing claude/brave-knuth-0rhu7k (29f9d1f) with main (f1160ed)

Open in CodSpeed

Footnotes

  1. 2 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports. ↩

@pkg-pr-new

pkg-pr-new Bot commented Oct 26, 2026 •

Copy link
Copy Markdown
More templates

@orpc/ai-sdk

npm i https://pkg.pr.new/@orpc/ai-sdk@2341

@orpc/arktype

npm i https://pkg.pr.new/@orpc/arktype@2341

@orpc/bun

npm i https://pkg.pr.new/@orpc/bun@2341

@orpc/client

npm i https://pkg.pr.new/@orpc/client@2341

@orpc/cloudflare

npm i https://pkg.pr.new/@orpc/cloudflare@2341

@orpc/contract

npm i https://pkg.pr.new/@orpc/contract@2341

@orpc/effect

npm i https://pkg.pr.new/@orpc/effect@2341

@orpc/evlog

npm i https://pkg.pr.new/@orpc/evlog@2341

@orpc/hibernation

npm i https://pkg.pr.new/@orpc/hibernation@2341

@orpc/json-schema

npm i https://pkg.pr.new/@orpc/json-schema@2341

@orpc/experimental-lock

npm i https://pkg.pr.new/@orpc/experimental-lock@2341

@orpc/mcp

npm i https://pkg.pr.new/@orpc/mcp@2341

@orpc/msw

npm i https://pkg.pr.new/@orpc/msw@2341

@orpc/nest

npm i https://pkg.pr.new/@orpc/nest@2341

@orpc/next

npm i https://pkg.pr.new/@orpc/next@2341

@orpc/node

npm i https://pkg.pr.new/@orpc/node@2341

@orpc/openapi

npm i https://pkg.pr.new/@orpc/openapi@2341

@orpc/opentelemetry

npm i https://pkg.pr.new/@orpc/opentelemetry@2341

@orpc/pinia-colada

npm i https://pkg.pr.new/@orpc/pinia-colada@2341

@orpc/pino

npm i https://pkg.pr.new/@orpc/pino@2341

@orpc/publisher

npm i https://pkg.pr.new/@orpc/publisher@2341

@orpc/ratelimit

npm i https://pkg.pr.new/@orpc/ratelimit@2341

@orpc/server

npm i https://pkg.pr.new/@orpc/server@2341

@orpc/shared

npm i https://pkg.pr.new/@orpc/shared@2341

@orpc/swr

npm i https://pkg.pr.new/@orpc/swr@2341

@orpc/tanstack-query

npm i https://pkg.pr.new/@orpc/tanstack-query@2341

@orpc/trpc

npm i https://pkg.pr.new/@orpc/trpc@2341

@orpc/valibot

npm i https://pkg.pr.new/@orpc/valibot@2341

@orpc/zod

npm i https://pkg.pr.new/@orpc/zod@2341

commit: 29f9d1f

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ No new issues found.

Reviewed changes

  • .errors accepts Effect Schemas — a new toStandardErrorMap shallow-copies the error map and converts only items whose data is an Effect Schema (EffectSchema.isSchema) via the existing toStandardSchema, leaving every other item untouched; ContractBuilder.prototype.errors, Builder.prototype.errors, and DecoratedProcedure.prototype.errors are patched, which covers every oc/os variant since all variants are ContractBuilder/Builder instances at runtime.
  • Types — new exported EffectErrorMap, EffectErrorMapItem, and ToStandardErrorMap<T> (T extends ErrorMap ? T : …) keep standard-only maps at their exact type while mapping Effect data to Schema<S['Encoded'], S['Type']>, and the augmentation is applied to oc, all ProcedureContractBuilder*, Builder*, and DecoratedProcedure.
  • Rename — the entry point moves from @orpc/effect/extensions/input-output to @orpc/effect/extensions/schema (breaking, old path removed) in package.json exports/publishConfig/sideEffects, with no stale repo references.
  • Docs — the section is renamed "Schema Extension", gains a .errors example, and notes the standalone-middleware gap (wrap with Schema.toStandardSchemaV1), which matches DecoratedMiddleware.errors being 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-error for 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.

Pullfrog  | View workflow run | Using deepseek-v4.1-flash (free via Pullfrog for OSS) | 𝕏

@dinwwwh
dinwwwh merged commit 74eb82a into main Oct 27, 2026
14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants