Skip to content

Conversation

@unnoq
Copy link
Member

@unnoq unnoq commented Dec 25, 2025

Fixes #1311

Summary by CodeRabbit

  • New Features

    • Added automatic path population for nested contract router structures, simplifying route configuration without manual path setup.
  • Improvements

    • Enhanced error messaging with clearer guidance on using available utilities.
  • Documentation

    • Updated code examples with optimized import patterns.

✏️ Tip: You can customize this high-level summary in your review settings.

@dosubot dosubot bot added the size:L This PR changes 100-499 lines, ignoring generated files. label Dec 25, 2025
@coderabbitai
Copy link

coderabbitai bot commented Dec 25, 2025

📝 Walkthrough

Walkthrough

The PR relocates populateContractRouterPaths utility and associated types from @orpc/nest to @orpc/contract package, and re-exports them from the nest package with deprecation notices to maintain backward compatibility. Tests and documentation are updated accordingly.

Changes

Cohort / File(s) Summary
Core utility migration to contract package
packages/contract/src/router-utils.ts
Added new exported type PopulatedContractRouterPaths<T>, interface PopulateContractRouterPathsOptions, and function populateContractRouterPaths() that recursively traverse router trees and populate paths for leaf procedures without explicit paths.
Removal from nest utils
packages/nest/src/utils.ts
Removed exported type PopulatedContractRouterPaths, interface PopulateContractRouterPathsOptions, and function populateContractRouterPaths() that were moved to contract package.
Backward compatibility re-exports
packages/nest/src/index.ts
Added public re-exports of populateContractRouterPaths, PopulateContractRouterPathsOptions, and PopulatedContractRouterPaths from @orpc/contract with deprecation notices.
Test updates in contract
packages/contract/src/router-utils.test.ts, packages/contract/src/router-utils.test-d.ts
Added new test cases verifying populateContractRouterPaths functionality, path assignment for nested routes, and type correctness of PopulatedContractRouterPaths.
Test removals in nest
packages/nest/src/utils.test.ts, packages/nest/src/utils.test-d.ts
Removed test cases for populateContractRouterPaths and PopulatedContractRouterPaths (now tested in contract package).
Documentation and error message updates
apps/content/docs/openapi/integrations/implement-contract-in-nest.md, packages/nest/src/implement.ts
Updated documentation example to import from consolidated path; updated error message to reference the utility's new location in @orpc/contract.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested labels

size:M, refactor, packages/contract, packages/nest

Poem

🐰 A hop from nest to contract's home,
These paths now properly roamed,
Utilities untangled, clean and bright,
No NestJS leaks to cloud the light!
The rabbit approves this tidy migration 🌱

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 75.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: moving populateContractRouterPaths imports from @orpc/nest to @orpc/contract, which is the core objective of this PR.
Linked Issues check ✅ Passed The PR moves populateContractRouterPaths to @orpc/contract and removes it from @orpc/nest/utils, preventing NestJS imports from leaking into frontend builds when importing from @orpc/contract.
Out of Scope Changes check ✅ Passed All changes are directly related to moving populateContractRouterPaths to @orpc/contract. Documentation updates and test adjustments align with this objective.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch unnoq/issue1311

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @unnoq, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request refactors the populateContractRouterPaths utility by relocating it from the @orpc/nest package to the more foundational @orpc/contract package. This change centralizes contract-related path generation logic, making it accessible across different integrations and improving modularity. The @orpc/nest package now provides a deprecated re-export to guide users towards the new canonical import path, ensuring a smoother transition for existing implementations.

Highlights

  • Utility Relocation: The populateContractRouterPaths utility function and its associated types have been moved from the @orpc/nest package to the @orpc/contract package, centralizing contract-related path generation logic.
  • Deprecation and Re-export: The @orpc/nest package now re-exports populateContractRouterPaths and its types as deprecated, guiding users to import them directly from @orpc/contract for improved compatibility and modularity.
  • New Implementation and Testing: The populateContractRouterPaths function is now fully implemented within @orpc/contract, providing automatic path population for contract procedures based on router keys. New type and runtime tests have been added to @orpc/contract to ensure its correctness.
  • Documentation Update: Documentation examples and error messages have been updated to reflect the new canonical import location for the populateContractRouterPaths utility.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request refactors the populateContractRouterPaths utility, moving it from the @orpc/nest package to @orpc/contract for better modularity. The changes include moving the function implementation, its types, and tests to the contract package, and updating documentation and re-exports in the nest package to ensure backward compatibility with a deprecation notice. The implementation of the new utility is sound, but I've provided a couple of suggestions in packages/contract/src/router-utils.ts to improve type safety and robustness.

Comment on lines +114 to +138
export function populateContractRouterPaths<T extends AnyContractRouter>(router: T, options: PopulateContractRouterPathsOptions = {}): PopulatedContractRouterPaths<T> {
const path = toArray(options.path)

if (isContractProcedure(router)) {
if (router['~orpc'].route.path === undefined) {
return new ContractProcedure({
...router['~orpc'],
route: {
...router['~orpc'].route,
path: toHttpPath(path),
},
}) as any
}

return router as any
}

const populated: Record<string, any> = {}

for (const key in router) {
populated[key] = populateContractRouterPaths(router[key]!, { ...options, path: [...path, key] })
}

return populated as any
}
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

The function populateContractRouterPaths uses as any in three places (lines 125, 128, 137), which undermines TypeScript's type safety. While complex recursive types can make strict typing difficult, it's worth exploring alternatives to any to prevent potential runtime bugs. For example, on line 128, return router; might work without a cast. In other places, a more specific cast like as PopulatedContractRouterPaths<T> would be safer than any.

Comment on lines +133 to +135
for (const key in router) {
populated[key] = populateContractRouterPaths(router[key]!, { ...options, path: [...path, key] })
}
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

The for...in loop iterates over all enumerable properties of an object, including those on its prototype chain. To ensure you're only processing properties of the router object itself, it's a good practice to include a hasOwnProperty check.

Suggested change
for (const key in router) {
populated[key] = populateContractRouterPaths(router[key]!, { ...options, path: [...path, key] })
}
for (const key in router) {
if (Object.prototype.hasOwnProperty.call(router, key)) {
populated[key] = populateContractRouterPaths(router[key]!, { ...options, path: [...path, key] })
}
}

@codecov
Copy link

codecov bot commented Dec 25, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@pkg-pr-new
Copy link

pkg-pr-new bot commented Dec 25, 2025

More templates

@orpc/ai-sdk

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

@orpc/arktype

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

@orpc/client

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

@orpc/contract

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

@orpc/experimental-durable-iterator

npm i https://pkg.pr.new/@orpc/experimental-durable-iterator@1312

@orpc/hey-api

npm i https://pkg.pr.new/@orpc/hey-api@1312

@orpc/interop

npm i https://pkg.pr.new/@orpc/interop@1312

@orpc/json-schema

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

@orpc/nest

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

@orpc/openapi

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

@orpc/openapi-client

npm i https://pkg.pr.new/@orpc/openapi-client@1312

@orpc/otel

npm i https://pkg.pr.new/@orpc/otel@1312

@orpc/experimental-pino

npm i https://pkg.pr.new/@orpc/experimental-pino@1312

@orpc/experimental-publisher

npm i https://pkg.pr.new/@orpc/experimental-publisher@1312

@orpc/experimental-publisher-durable-object

npm i https://pkg.pr.new/@orpc/experimental-publisher-durable-object@1312

@orpc/experimental-ratelimit

npm i https://pkg.pr.new/@orpc/experimental-ratelimit@1312

@orpc/react

npm i https://pkg.pr.new/@orpc/react@1312

@orpc/react-query

npm i https://pkg.pr.new/@orpc/react-query@1312

@orpc/experimental-react-swr

npm i https://pkg.pr.new/@orpc/experimental-react-swr@1312

@orpc/server

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

@orpc/shared

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

@orpc/solid-query

npm i https://pkg.pr.new/@orpc/solid-query@1312

@orpc/standard-server

npm i https://pkg.pr.new/@orpc/standard-server@1312

@orpc/standard-server-aws-lambda

npm i https://pkg.pr.new/@orpc/standard-server-aws-lambda@1312

@orpc/standard-server-fastify

npm i https://pkg.pr.new/@orpc/standard-server-fastify@1312

@orpc/standard-server-fetch

npm i https://pkg.pr.new/@orpc/standard-server-fetch@1312

@orpc/standard-server-node

npm i https://pkg.pr.new/@orpc/standard-server-node@1312

@orpc/standard-server-peer

npm i https://pkg.pr.new/@orpc/standard-server-peer@1312

@orpc/svelte-query

npm i https://pkg.pr.new/@orpc/svelte-query@1312

@orpc/tanstack-query

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

@orpc/trpc

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

@orpc/valibot

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

@orpc/vue-colada

npm i https://pkg.pr.new/@orpc/vue-colada@1312

@orpc/vue-query

npm i https://pkg.pr.new/@orpc/vue-query@1312

@orpc/zod

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

commit: ff37597

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
packages/nest/src/utils.test.ts (1)

3-10: Duplicate test case on lines 4 and 5.

Both lines test the same input '/ping' with the same expected output. Consider removing one or replacing it with a different test case for better coverage.

🔎 Proposed fix
 it('toNestPattern', () => {
   expect(toNestPattern('/ping')).toBe('/ping')
-  expect(toNestPattern('/ping')).toBe('/ping')
   expect(toNestPattern('/{id}')).toBe('/:id')
   expect(toNestPattern('/{id}/{+path}')).toBe('/:id/*path')

   expect(toNestPattern('/{id}/name{name}')).toBe('/:id/name{name}')
 })
packages/contract/src/router-utils.test.ts (1)

77-101: Good test coverage for the new utility.

The tests appropriately verify path preservation for procedures with explicit paths and auto-population for those without. Consider adding a test case for the options.path parameter to verify custom prefix functionality:

// Test with custom path prefix
const populatedWithPrefix = populateContractRouterPaths(contract, { path: ['api', 'v1'] })
expect(populatedWithPrefix.ping['~orpc'].route.path).toBe('/api/v1/ping')
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cc1a1aa and ff37597.

📒 Files selected for processing (9)
  • apps/content/docs/openapi/integrations/implement-contract-in-nest.md
  • packages/contract/src/router-utils.test-d.ts
  • packages/contract/src/router-utils.test.ts
  • packages/contract/src/router-utils.ts
  • packages/nest/src/implement.ts
  • packages/nest/src/index.ts
  • packages/nest/src/utils.test-d.ts
  • packages/nest/src/utils.test.ts
  • packages/nest/src/utils.ts
💤 Files with no reviewable changes (1)
  • packages/nest/src/utils.test-d.ts
🧰 Additional context used
🧬 Code graph analysis (2)
packages/contract/src/router-utils.ts (5)
packages/nest/src/index.ts (3)
  • PopulatedContractRouterPaths (25-25)
  • PopulateContractRouterPathsOptions (21-21)
  • populateContractRouterPaths (15-15)
packages/contract/src/router.ts (1)
  • AnyContractRouter (17-17)
packages/shared/src/array.ts (1)
  • toArray (1-3)
packages/contract/src/procedure.ts (1)
  • isContractProcedure (51-66)
packages/client/src/adapters/standard/utils.ts (1)
  • toHttpPath (6-8)
packages/contract/src/router-utils.test-d.ts (3)
packages/contract/src/router-utils.ts (1)
  • PopulatedContractRouterPaths (95-100)
packages/contract/src/builder.ts (2)
  • router (198-200)
  • oc (203-212)
packages/contract/src/procedure.ts (1)
  • ContractProcedure (25-47)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: test
  • GitHub Check: publish-commit
  • GitHub Check: lint
  • GitHub Check: Cloudflare Pages
🔇 Additional comments (7)
packages/nest/src/utils.ts (1)

1-8: LGTM!

The utility file is appropriately simplified. The toNestPattern function is retained for NestJS-specific path conversion, while the populateContractRouterPaths utility has been correctly relocated to @orpc/contract to avoid bundling NestJS dependencies in frontend code.

packages/nest/src/implement.ts (1)

48-53: LGTM!

The error message correctly directs users to the new import location for populateContractRouterPaths, aligning with the PR's objective to prefer imports from @orpc/contract.

apps/content/docs/openapi/integrations/implement-contract-in-nest.md (1)

67-67: LGTM!

The documentation correctly demonstrates importing populateContractRouterPaths from @orpc/contract alongside oc, which aligns with the PR's objective and provides clear guidance to users.

packages/nest/src/index.ts (1)

11-26: LGTM!

Excellent approach to maintaining backward compatibility. The deprecated re-exports allow existing consumers to continue working while the deprecation notices clearly guide them to migrate to the new import path from @orpc/contract.

packages/contract/src/router-utils.test-d.ts (1)

50-68: LGTM!

Good type-level test coverage for PopulatedContractRouterPaths. The tests verify that the type correctly preserves the procedure's type parameters (input/output schemas, error map, meta) through the transformation.

packages/contract/src/router-utils.ts (2)

95-138: LGTM!

The implementation is well-structured and follows the established patterns in this file (e.g., enhanceContractRouter, minifyContractRouter). The recursive approach correctly handles nested routers, preserves existing paths when present, and only populates missing paths. The type definition properly preserves procedure type parameters through the transformation.

The JSDoc comments provide clear documentation and link to the relevant NestJS integration docs.


5-6: Dependency is correctly declared.

The @orpc/client dependency is properly declared in packages/contract/package.json as "@orpc/client": "workspace:*", so there are no resolution issues.

@cloudflare-workers-and-pages
Copy link

Deploying orpc with  Cloudflare Pages  Cloudflare Pages

Latest commit: ff37597
Status: ✅  Deploy successful!
Preview URL: https://f1943be5.orpc-1qh.pages.dev
Branch Preview URL: https://unnoq-issue1311.orpc-1qh.pages.dev

View logs

@unnoq unnoq merged commit 544b973 into main Dec 25, 2025
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L This PR changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Export src/utils.ts in @orpc/nest as @orpc/nest/utils

3 participants