feat(trpc): tRPC integration - #1683
Conversation
Port the @orpc/trpc package from v1 to v2, allowing tRPC routers to be converted into oRPC routers via toORPCRouter, including OpenAPI support, subscriptions/tracked events, lazy routers, and error conversion. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
More templates
@orpc/arktype
@orpc/bun
@orpc/client
@orpc/cloudflare
@orpc/contract
@orpc/experimental-effect
@orpc/evlog
@orpc/json-schema
@orpc/nest
@orpc/next
@orpc/openapi
@orpc/opentelemetry
@orpc/pino
@orpc/publisher
@orpc/ratelimit
@orpc/server
@orpc/shared
@orpc/tanstack-query
@orpc/trpc
@orpc/valibot
@orpc/zod
commit: |
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Reviewed changes — port of the
Feedback
|
|
test comment 2
|
Users now type the recommended '~openapi' meta key themselves using OpenAPIMeta from @orpc/openapi, or expose any custom key via the new mapMeta option. This drops @orpc/openapi from runtime dependencies. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
ℹ️ Minor suggestions only. Package type-checks and all 11 new tests pass.
Reviewed changes — port of the @orpc/trpc package from v1 to v2, adding toORPCRouter to convert tRPC routers into oRPC routers, plus tests and docs.
- Add
@orpc/trpcpackage withtoORPCRouter,ORPCMeta, andToORPCRouterResulttype mapping. - Adapt to v2 architecture by preserving tRPC schemas while disabling oRPC validation, forwarding meta (including
~openapi), wrappingTRPCErrorasORPCError, and supporting lazy/subscription routers. - Add docs and fix migration link with a new
docs/integrations/trpc.mdpage and corrected sidebar entry.
Kimi K2 (free via Pullfrog for OSS) | 𝕏
Cover dot-path lazy routers nested in plain object records, missing parent segments in partially loaded routers, and non-TRPCError passthrough from broken async iterables. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Important
The latest commits address some prior feedback (drop ORPCMeta, add mapMeta, reach 100% test coverage), but a few open concerns from the last review remain unresolved. I can't approve until they're addressed or explicitly accepted.
Reviewed changes — since the prior review, the package replaced the built-in ORPCMeta type with explicit '~openapi' typing and a user-supplied mapMeta option, and added tests covering dot-path lazy routers, partially loaded routers, scalar lastEventId input passthrough, and non-TRPCError rethrowing. Type-check and the 15 runtime tests pass.
Kimi K2 (free via Pullfrog for OSS) | 𝕏
Resolves oRPC meta plugins (e.g. openapi from @orpc/openapi) into a plain meta object usable with tRPC builders' .meta(), simulating how oRPC builders apply meta plugins. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Important
The new toTRPCMeta bridge is clean, but I cannot approve while three unresolved Pullfrog concerns remain on the tRPC package.
Reviewed changes — since the last review, the package added the toTRPCMeta helper so oRPC meta plugins can be used with tRPC builders, plus tests and docs.
- Added
toTRPCMetainpackages/trpc/src/to-trpc-meta.ts, wrappingresolveMetaPluginsfrom@orpc/contractto resolve oRPC meta plugins into a plain meta object. - Added
@orpc/contractdependency and exported the new helper frompackages/trpc/src/index.ts. - Added tests covering empty-plugin resolution, plugin merge logic, custom
defineMetaplugins, and end-to-end conversion withtoORPCRouter. - Updated
docs/integrations/trpc.mdto promotetoTRPCMetafirst and document the shallow-merge caveat of chained tRPC.meta()calls. - Resolved the previously open
isObject(input)/lastEventIdarray-input concern by verifying that tRPC'sisObjectexplicitly excludes arrays.
⚠️ @trpc/server peer dependency lacks an upper bound
packages/trpc/package.json declares "@trpc/server": ">=11.4.2". Because the code imports from @trpc/server/unstable-core-do-not-import, a future tRPC semver-major release could break the integration without a compatibility signal.
⚠️ Docs error-formatting snippet is missing imports
apps/content/docs/integrations/trpc.md uses z.ZodError, z.prettifyError, and z.flattenError in its error-formatting example, but the zod import is not shown, so the snippet is not copy-pasteable.
⚠️ batchIndex: 0 is hard-coded
packages/trpc/src/to-orpc-router.ts always passes batchIndex: 0 to tRPC procedures, with a TODO noting it should be inferred from context. Converted procedures will not behave correctly under the oRPC Batch Plugin.
Kimi K2 (free via Pullfrog for OSS) | 𝕏
There was a problem hiding this comment.
Important
No new issues in the latest commit, but this PR still cannot be approved until the unresolved Pullfrog review threads from the previous review are addressed.
Reviewed changes — the latest commit reorganized docs/integrations/trpc.md so the general router-conversion content comes before the OpenAPI section.
- Moved router conversion to its own section explaining that the result is a regular oRPC router compatible with handlers, clients, middlewares, plugins, and interceptors.
- Added
callandcreateRouterClientexamples showing direct procedure invocation and server-side clients. - Added an info box noting that input/output validation remains delegated to tRPC.
Kimi K2 (free via Pullfrog for OSS) | 𝕏
toTRPCMeta covers the meta-authoring use case; the docs now link to the OpenAPI guides instead of duplicating them. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Important
The latest commit is clean, but three unresolved concerns from prior reviews remain unaddressed.
Reviewed changes — since the prior review at f6298018, the package dropped the optional mapMeta API and the tRPC integration docs were trimmed.
- Removed the
mapMetaoption fromtoORPCRouter: meta now passes straight through from tRPC, and users are expected to put OpenAPI metadata under'~openapi'(typically viatoTRPCMeta). - Simplified the OpenAPI docs section by removing the manual
OpenAPIMetaexample and the request-handling code block; the page now links to the dedicated OpenAPI docs. - Removed the
mapMetatest case and kept the rest of the test suite passing (18 tests).
Kimi K2 (free via Pullfrog for OSS) | 𝕏
Simplify lazy router conversion, wrap iterators via @orpc/shared (dropping the @orpc/client dependency), mark returned errors opaque, and verify the tRPC invocation contract with a mocked procedure. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Each test now creates only the router it needs; tests/shared.ts keeps just the tRPC builder and schemas. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Important
The latest commit simplifies conversion internals, but it drops support for nested lazy routers and leaves a stale project reference.
Reviewed changes — since the prior review at 664a7954, the latest commit refactored lazy conversion and call forwarding.
- Removed the
@orpc/clientdependency and switched fromwrapAsyncIteratorPreservingEventMetato@orpc/shared'swrapAsyncIteratorwhile preserving event metadata explicitly. - Simplified lazy-router conversion by removing the accessible-proxy wrapper.
- Added
opaqueReturnedErrors: trueto converted procedures. - Strengthened call tests to assert context, signal, path, type, and raw input forwarding.
Kimi K2 (free via Pullfrog for OSS) | 𝕏
Each test file now defines its own schemas and tRPC builder. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A plain throwing query cannot cover this path: tRPC wraps resolver errors in TRPCError, so only errors thrown while consuming the returned value escape unwrapped. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Important
The latest commit is clean and the stale tsconfig.json reference is fixed, but several Pullfrog concerns from prior reviews remain unaddressed — most notably, nested lazy routers placed under plain object records are still inaccessible at runtime.
Reviewed changes — since the prior Pullfrog review at 77141d7, the PR cleaned up tests, removed the stale ../client project reference, loosened the toTRPCMeta return type, and restructured the tRPC integration docs. Type-check and the 15 runtime tests pass.
- Restructured
apps/content/docs/integrations/trpc.mdto lead with router conversion and error formatting before coveringtoTRPCMetain a dedicated Metadata section. - Removed the stale
../clientproject reference frompackages/trpc/tsconfig.jsonafter@orpc/clientwas removed as a dependency. - Loosened
toTRPCMeta’s return type fromMetatoRecord<string, any>inpackages/trpc/src/to-trpc-meta.tsso it can be passed directly to tRPC.meta()calls with arbitrary user-defined meta shapes. - Inlined test routers in
packages/trpc/src/to-orpc-router.test.tsandpackages/trpc/src/to-orpc-router.test-d.tsand removed the shared fixture to avoid cross-test coupling. - Restored the non-
TRPCErrorrethrow test using a mutation that returns an async iterable whose iterator factory throws the original error.
⚠️ Nested lazy routers under plain object records remain inaccessible
A runtime reproduction confirms the issue raised in the previous review is still present: tRPC stores a lazy placed under a plain record (nested: { lazy: lazy(...) }) with the dot-joined key nested.lazy. lazyToORPCRouter assigns that key verbatim, so orpcRouter.nested.lazy is undefined while (orpcRouter as any)['nested.lazy'] is the Lazy. The existing deep lazy test only covers lazies inside lazy-loaded sub-routers, not this plain-record case.
⚠️ @trpc/server peer dependency still lacks an upper bound
packages/trpc/package.json:39 still declares "@trpc/server": ">=11.4.2". Because this package imports from @trpc/server/unstable-core-do-not-import, a future tRPC semver-major release could break the integration without a compatibility signal.
⚠️ batchIndex: 0 remains hard-coded
packages/trpc/src/to-orpc-router.ts:110-111 still passes batchIndex: 0 to tRPC procedures, so converted procedures will not behave correctly under the oRPC Batch Plugin.
ℹ️ Nitpicks
apps/content/docs/integrations/trpc.md:58still usesz.ZodError,z.prettifyError, andz.flattenErrorwithout showing the imports (zod,ORPCError,TRPCError), so the error-formatting snippet is not copy-pasteable.
Kimi K2 (free via Pullfrog for OSS) | 𝕏
There was a problem hiding this comment.
Important
The latest commit resolves the nested lazy-router issue from the previous review. Type-check and all 15 runtime tests pass, and I found no new issues in this increment. This PR still carries unresolved Pullfrog feedback from the prior review, so it is not yet mergeable.
Reviewed changes — since the prior Pullfrog review at b38745d, the latest commit fixes nested lazy routers placed under plain object records.
- Fixed nested lazy-router placement in
packages/trpc/src/to-orpc-router.tsby splitting tRPC's dot-joined lazy keys withsetfrom@orpc/shared, soorpcRouter.nested.lazyis now accessible at runtime. - Added/updated tests in
packages/trpc/src/to-orpc-router.test.tscovering deep lazy-loaded sub-routers and lazies nested under plain object records.
Kimi K2 (free via Pullfrog for OSS) | 𝕏

Summary
Brings the tRPC integration (
@orpc/trpc) to v2. You can now convert a tRPC router into an oRPC router and use it with any oRPC feature:toTRPCMetalets you use oRPC meta plugins (likeopenapi(...)) directly in tRPC's.meta()