Skip to content

Conversation

@unnoq
Copy link
Member

@unnoq unnoq commented Jun 1, 2025

Summary by CodeRabbit

  • New Features

    • Added a new utility to automatically infer the HTTP method for RPC requests based on contract routers.
    • Introduced a function to minify contract routers, creating a smaller, exportable version for client-side use.
  • Documentation

    • Added a new "Router to Contract" guide detailing how to convert and export routers for client use.
    • Updated documentation to explain automatic HTTP method inference and reference advanced guides for contract routers.
    • Added a new sidebar navigation item for easy access to the "Router to Contract" documentation.
  • Bug Fixes

    • None.
  • Tests

    • Added tests for HTTP method inference and contract router minification utilities.

@vercel
Copy link

vercel bot commented Jun 1, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
orpc ✅ Ready (Inspect) Visit Preview 💬 Add feedback Jun 2, 2025 0:50am

@coderabbitai
Copy link

coderabbitai bot commented Jun 1, 2025

Caution

Review failed

The pull request is closed.

Walkthrough

This update introduces new utilities and documentation for converting routers into client-safe contracts. It adds the minifyContractRouter and inferRPCMethodFromContractRouter functions, updates documentation to guide users through exporting routers as contracts, and enhances test coverage. The documentation sidebar is updated to reflect these additions.

Changes

Files/Paths Change Summary
apps/content/.vitepress/config.ts Added "Router to Contract" item to documentation sidebar under "Contract First".
apps/content/docs/client/rpc-link.md, apps/content/docs/openapi/client/openapi-link.md Updated docs to reference new contract router utilities and advanced guide; added usage instructions and notes.
apps/content/docs/contract-first/router-to-contract.md New documentation explaining how to minify and export routers as contracts for client use, with code examples.
packages/contract/src/link-utils.ts, packages/contract/src/index.ts Added inferRPCMethodFromContractRouter utility and exported it via the package index.
packages/contract/src/router-utils.ts Added minifyContractRouter utility for producing client-safe contract routers.
packages/contract/src/link-utils.test.ts, packages/contract/src/link-utils.test-d.ts Added tests for inferRPCMethodFromContractRouter utility.
packages/contract/src/router-utils.test.ts Added test for minifyContractRouter ensuring correct minification of contract routers.

Sequence Diagram(s)

sequenceDiagram
    participant Dev as Developer
    participant Server as Server (Router)
    participant Utils as Contract Utils
    participant Client as Client

    Dev->>Server: Define router (possibly with lazy routers)
    Dev->>Utils: Call minifyContractRouter(router)
    Utils->>Dev: Return minified contract JSON
    Dev->>Client: Export/import minified contract
    Client->>Utils: Use inferRPCMethodFromContractRouter(minifiedContract)
    Client->>Server: Make RPC/OpenAPI requests with inferred HTTP methods
Loading

Possibly related PRs

  • unnoq/orpc#219: Adds documentation and utilities related to converting routers to contracts, including the unlazyRouter function, which is directly relevant to these changes.

Poem

In the warren, routers leap and bound,
Now minified, their secrets safe and sound.
Contracts hop to client-side with glee,
HTTP methods inferred, as easy as can be!
With guides and tests, this patch is neat—
A bunny’s job, delightfully complete! 🐇✨


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8ab9ffe and ca81240.

📒 Files selected for processing (3)
  • apps/content/docs/contract-first/router-to-contract.md (1 hunks)
  • packages/contract/src/link-utils.test.ts (1 hunks)
  • packages/contract/src/link-utils.ts (1 hunks)
✨ Finishing Touches
  • 📝 Generate Docstrings

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@codecov
Copy link

codecov bot commented Jun 1, 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 Jun 1, 2025

More templates

@orpc/arktype

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

@orpc/client

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

@orpc/contract

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

@orpc/hey-api

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

@orpc/nest

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

@orpc/openapi

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

@orpc/openapi-client

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

@orpc/react

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

@orpc/react-query

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

@orpc/server

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

@orpc/shared

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

@orpc/solid-query

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

@orpc/standard-server

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

@orpc/standard-server-aws-lambda

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

@orpc/standard-server-fetch

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

@orpc/standard-server-node

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

@orpc/standard-server-peer

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

@orpc/svelte-query

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

@orpc/tanstack-query

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

@orpc/valibot

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

@orpc/vue-colada

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

@orpc/vue-query

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

@orpc/zod

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

commit: ca81240

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: 2

🧹 Nitpick comments (5)
packages/contract/src/link-utils.test.ts (1)

22-23: Good error handling test, but could be more specific.

The test verifies that calling with a non-existent path throws an error, which is important. However, consider making the assertion more specific about the error message or type.

Consider enhancing the error assertion:

- expect(() => method({}, ['nested', 'not-exist'])).toThrow()
+ expect(() => method({}, ['nested', 'not-exist'])).toThrow(/No valid procedure found at path/)
packages/contract/src/link-utils.ts (1)

12-27: Solid implementation with proper error handling.

The function correctly:

  • Returns a closure matching the expected signature for RPCLink
  • Uses get utility for safe path resolution
  • Validates the procedure with isContractProcedure
  • Provides a descriptive error message for invalid paths
  • Uses fallbackContractConfig for proper method resolution
  • Converts HEAD to GET for HTTP compatibility

The error message formatting could be slightly improved for better readability.

Consider improving the error message formatting:

-      throw new Error(`
-        [inferRPCMethodFromContractRouter] No valid procedure found at path "${path.join('.')}".
-        This may happen when the contract router is not properly configured.
-      `)
+      throw new Error(
+        `[inferRPCMethodFromContractRouter] No valid procedure found at path "${path.join('.')}". ` +
+        `This may happen when the contract router is not properly configured.`
+      )
apps/content/docs/contract-first/router-to-contract.md (3)

12-12: Fix subject–verb agreement in the guide text.

The sentence currently reads:

If your router include a [lazy router](/docs/router#lazy-router), you need to fully resolve it to make it compatible with contract.

It should be:

- If your router include a [lazy router](/docs/router#lazy-router), you need to fully resolve it to make it compatible with contract.
+ If your router includes a [lazy router](/docs/router#lazy-router), you need to fully resolve it to make it compatible with contract.
🧰 Tools
🪛 LanguageTool

[uncategorized] ~12-~12: This verb does not appear to agree with the subject. Consider using a different form.
Context: .... ## Unlazy the Router If your router include a [lazy router](/docs/router#lazy-route...

(AI_EN_LECTOR_REPLACEMENT_VERB_AGREEMENT)


[uncategorized] ~12-~12: You might be missing the article “the” here.
Context: ...y resolve it to make it compatible with contract. ```ts import { unlazyRouter } from '@...

(AI_EN_LECTOR_MISSING_DETERMINER_THE)


17-17: Correct the variable name typo in the code snippet.

The example declares unlaziedRouter, which appears to be a misspelling. For clarity and consistency, rename it to something like resolvedRouter:

- const unlaziedRouter = await unlazyRouter(router)
+ const resolvedRouter = await unlazyRouter(router)

46-46: Add a note about JSON module import requirements.

Importing a JSON file in TypeScript usually requires enabling resolveJsonModule (and sometimes esModuleInterop) in tsconfig.json. Consider adding a brief note or a link to the TS docs to help users avoid import errors:

::: tip
Make sure your `tsconfig.json` has `"resolveJsonModule": true` (and `"esModuleInterop": true` if needed) so that `import contract from './contract.json'` works without compilation issues.
:::
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 85d7ad9 and 8ab9ffe.

📒 Files selected for processing (10)
  • apps/content/.vitepress/config.ts (1 hunks)
  • apps/content/docs/client/rpc-link.md (1 hunks)
  • apps/content/docs/contract-first/router-to-contract.md (1 hunks)
  • apps/content/docs/openapi/client/openapi-link.md (1 hunks)
  • packages/contract/src/index.ts (1 hunks)
  • packages/contract/src/link-utils.test-d.ts (1 hunks)
  • packages/contract/src/link-utils.test.ts (1 hunks)
  • packages/contract/src/link-utils.ts (1 hunks)
  • packages/contract/src/router-utils.test.ts (2 hunks)
  • packages/contract/src/router-utils.ts (2 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (2)
packages/contract/src/link-utils.test.ts (3)
packages/contract/src/link-utils.ts (1)
  • inferRPCMethodFromContractRouter (12-27)
packages/contract/src/router-utils.ts (1)
  • minifyContractRouter (71-91)
packages/contract/src/builder.ts (1)
  • oc (189-198)
packages/contract/src/link-utils.ts (4)
packages/contract/src/router.ts (1)
  • AnyContractRouter (17-17)
packages/contract/src/index.ts (1)
  • HTTPMethod (21-21)
packages/contract/src/procedure.ts (1)
  • isContractProcedure (51-66)
packages/contract/src/config.ts (1)
  • fallbackContractConfig (20-26)
🪛 LanguageTool
apps/content/docs/contract-first/router-to-contract.md

[uncategorized] ~12-~12: This verb does not appear to agree with the subject. Consider using a different form.
Context: .... ## Unlazy the Router If your router include a [lazy router](/docs/router#lazy-route...

(AI_EN_LECTOR_REPLACEMENT_VERB_AGREEMENT)


[uncategorized] ~12-~12: You might be missing the article “the” here.
Context: ...y resolve it to make it compatible with contract. ```ts import { unlazyRouter } from '@...

(AI_EN_LECTOR_MISSING_DETERMINER_THE)

⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: publish-commit
  • GitHub Check: lint
🔇 Additional comments (15)
apps/content/.vitepress/config.ts (1)

82-82: Verify sidebar ordering consistency.
The new "Router to Contract" entry is correctly added under "Contract First". Ensure the ordering matches related sections and the link path is accurate.

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

8-8: Expose link-utils in public API.
Adding export * from './link-utils' makes inferRPCMethodFromContractRouter available through the main package index. It follows the existing export ordering.

apps/content/docs/openapi/client/openapi-link.md (1)

41-41: Refresh advanced router note.
Updated the info box to direct users to the new "Router to Contract" guide. The wording and link are clear and consistent with other docs.

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

1-4: Validate test imports.
Imports for RPCLink, the shared test contract router, and inferRPCMethodFromContractRouter appear correct. Confirm that the shared router test data provides the expected metadata for method inference.

apps/content/docs/client/rpc-link.md (1)

108-111: Check "Automatically use method" details header.
The details block introduction is useful. Verify that VitePress properly renders this expandable section.

packages/contract/src/link-utils.test.ts (3)

1-4: LGTM! Clean and appropriate imports.

The imports are well-organized and include all necessary dependencies for the test.


5-14: Good test setup with comprehensive route coverage.

The test creates a well-structured contract router that covers:

  • Different HTTP methods (HEAD, GET, POST, DELETE)
  • Default method behavior (line 9 - post route without explicit method)
  • Nested routes for testing path resolution

The use of minifyContractRouter in the setup is appropriate and follows the expected workflow.


16-21: Comprehensive method inference validation.

The test assertions properly verify:

  • HEAD to GET conversion (line 16)
  • Explicit method preservation (lines 17, 19, 20)
  • Default method behavior (line 18 - POST is the default)
  • Nested route handling (lines 19-20)

This covers the core functionality thoroughly.

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

63-70: Excellent documentation with helpful context.

The JSDoc comment clearly explains the purpose, usage, and benefits of the function. The link to documentation provides additional context for users.


71-82: Solid procedure minification logic.

The function correctly:

  • Creates a new minimal procedure object
  • Clears the errorMap for security and size reduction
  • Preserves meta and route which are essential for client functionality
  • Maintains the correct structure expected by isContractProcedure

84-91: Proper recursive handling for nested routers.

The recursive logic correctly processes nested router structures by:

  • Creating a new object to avoid mutations
  • Recursively calling minifyContractRouter on each property
  • Preserving the router structure
packages/contract/src/router-utils.test.ts (2)

2-4: Good import additions for new functionality.

The imports correctly add the necessary functions (isContractProcedure and minifyContractRouter) to support the new test case.


40-74: Comprehensive test coverage for router minification.

The test effectively validates:

  • Correct minification of different procedure types (ping with metadata vs pong without)
  • Proper structure preservation (lines 43-61 define expected minimal shapes)
  • Contract procedure compliance using isContractProcedure predicate
  • Both top-level and nested procedure handling

The test data shows that:

  • errorMap is properly cleared to empty object
  • meta is preserved when present (mode: 'dev' for ping)
  • route is preserved when present (path: '/base' for ping)

This thoroughly validates the minification logic.

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

1-6: Clean imports with appropriate dependencies.

The imports are well-organized and include all necessary utilities:

  • Type imports for HTTPMethod and AnyContractRouter
  • Utility functions for path resolution, config fallback, and procedure validation

7-11: Clear and helpful documentation.

The JSDoc comment effectively explains the function's purpose and includes a link to relevant documentation for additional context.

@unnoq unnoq merged commit 6d0ea4a into main Jun 2, 2025
4 of 6 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