-
-
Notifications
You must be signed in to change notification settings - Fork 128
feat(trpc): support event iterator for toORPCRouter #716
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
The latest updates on your projects. Learn more about Vercel for Git ↗︎
|
|
Caution Review failedThe pull request is closed. """ WalkthroughThis update enhances the Changes
Sequence Diagram(s)sequenceDiagram
participant Client
participant oRPC Procedure
participant tRPC Procedure
Client->>oRPC Procedure: Call subscription with lastEventId
oRPC Procedure->>oRPC Procedure: Merge lastEventId into input (if applicable)
oRPC Procedure->>tRPC Procedure: Invoke with merged input
tRPC Procedure-->>oRPC Procedure: Return async iterable
loop For each event in iterable
oRPC Procedure->>oRPC Procedure: Wrap event with event metadata (if tracked)
oRPC Procedure-->>Client: Yield event with metadata
end
oRPC Procedure-->>Client: Signal completion
Possibly related PRs
Suggested labels
Poem
📜 Recent review detailsConfiguration used: CodeRabbit UI 📒 Files selected for processing (1)
✨ Finishing Touches
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. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed 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)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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 significantly enhances the toORPCRouter utility by adding comprehensive support for tRPC subscriptions, allowing them to function seamlessly as event iterators within the ORPC ecosystem. The changes ensure proper handling of streamed data, including tRPC's tracked events and the propagation of lastEventId for stream resumption, thereby bridging the gap between tRPC's subscription model and ORPC's event-driven capabilities.
Highlights
- Event Iterator Support: The
toORPCRouterutility now fully supports tRPC subscriptions that returnAsyncIterableobjects, allowing them to be consumed as event iterators within the ORPC framework. - Tracked Data Transformation: tRPC's
trackeddata (used for associating event IDs with streamed data) is now correctly transformed into ORPC's event metadata format, ensuring that event IDs are preserved and accessible on the ORPC client side. - Last Event ID Propagation: The
lastEventIdfrom the ORPC context is now properly passed into the tRPC procedure's input, enabling tRPC subscriptions to resume from a specific event ID when converted to ORPC procedures. - Type System Enhancements: Updated type definitions, including the introduction of
experimental_ToORPCOutputand the use ofAsyncIteratorObject, provide more accurate type inference for event iterator outputs.
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 in your pull request via creating an issue comment (i.e. comment on the pull request page) using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands.
| 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 issue 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 is currently in preview and 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 to provide feedback.
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
-
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. ↩
Codecov ReportAll modified and coverable lines are covered by tests ✅ 📢 Thoughts on this report? Let us know! |
More templates
@orpc/arktype
@orpc/client
@orpc/contract
@orpc/experimental-durable-event-iterator
@orpc/hey-api
@orpc/nest
@orpc/openapi
@orpc/openapi-client
@orpc/react
@orpc/react-query
@orpc/server
@orpc/shared
@orpc/solid-query
@orpc/standard-server
@orpc/standard-server-aws-lambda
@orpc/standard-server-fetch
@orpc/standard-server-node
@orpc/standard-server-peer
@orpc/svelte-query
@orpc/tanstack-query
@orpc/trpc
@orpc/valibot
@orpc/vue-colada
@orpc/vue-query
@orpc/zod
commit: |
There was a problem hiding this 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 (1)
packages/trpc/src/to-orpc-router.ts (1)
99-101: Enhance input validation for lastEventId merging.The current logic merges
lastEventIdwhen input is undefined or a plain object. Consider adding validation to ensurelastEventIddoesn't conflict with existing properties.const trpcInput = lastEventId !== undefined && (input === undefined || isObject(input)) - ? { ...input, lastEventId } + ? { ...input, lastEventId: input?.lastEventId ?? lastEventId } : inputThis prevents accidentally overwriting an existing
lastEventIdproperty in the input.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (6)
packages/trpc/package.json(1 hunks)packages/trpc/src/to-orpc-router.test-d.ts(3 hunks)packages/trpc/src/to-orpc-router.test.ts(2 hunks)packages/trpc/src/to-orpc-router.ts(3 hunks)packages/trpc/tests/shared.ts(2 hunks)packages/trpc/tsconfig.json(1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (3)
packages/trpc/src/to-orpc-router.test-d.ts (2)
packages/server/src/procedure.ts (1)
Procedure(55-71)packages/trpc/tests/shared.ts (2)
TRPCContext(6-6)TRPCMeta(7-10)
packages/trpc/src/to-orpc-router.test.ts (2)
packages/shared/src/iterator.ts (1)
isAsyncIteratorObject(4-10)packages/trpc/tests/shared.ts (2)
trpcRouter(14-67)t(12-12)
packages/trpc/src/to-orpc-router.ts (2)
packages/shared/src/object.ts (1)
isObject(31-39)packages/client/src/event-iterator.ts (1)
mapEventIterator(4-43)
⏰ Context from checks skipped due to timeout of 90000ms (2)
- GitHub Check: lint
- GitHub Check: publish-commit
🔇 Additional comments (15)
packages/trpc/tsconfig.json (1)
5-5: LGTM! Configuration change aligns with new dependency.The addition of the client project reference is consistent with the new
@orpc/clientdependency added in the package.json.packages/trpc/tests/shared.ts (2)
2-2: LGTM! Import addition supports event tracking functionality.The
trackedimport is correctly added to support the new event iterator test scenarios.
37-38: LGTM! Test data for event iterators is well-structured.The tracked events with sequential IDs and order metadata provide good test coverage for the new event iterator functionality.
packages/trpc/package.json (1)
41-41: LGTM! Dependency addition supports new client functionality.The
@orpc/clientdependency is correctly added with the workspace pattern consistent with other @orpc packages.packages/trpc/src/to-orpc-router.test-d.ts (3)
3-3: LGTM! Import addition supports tracked data types.The
TrackedDataimport is correctly added to support the refined type assertions for event iterators.
27-27: LGTM! Type refinement improves precision for async iterators.The type change from
AsyncIterable<string>toAsyncIteratorObject<'pong' | TrackedData<{ order: number }>, void, any>correctly reflects the specific types yielded by the subscription procedure.
38-38: LGTM! Consistent type refinement for lazy subscription.The type change to
AsyncIteratorObject<string>is consistent with the other subscription procedure type refinements.packages/trpc/src/to-orpc-router.test.ts (5)
1-1: LGTM! Import additions support comprehensive event iterator testing.The new imports (
getEventMeta,tracked,z) are correctly added to support the event iterator test functionality.
9-11: LGTM! Proper test setup with mock cleanup.The
beforeEachhook ensures clean test state by clearing mocks, which is a good testing practice.
83-103: LGTM! Comprehensive test for subscription with tracked events.The test thoroughly validates:
- Async iterator functionality
- Event sequence and completion
- Tracked event structure with IDs and metadata
- Event metadata extraction
The assertions are well-structured and cover the expected behavior.
105-133: LGTM! Thorough test coverage for lastEventId parameter handling.The test effectively validates:
lastEventIdmerging with object inputslastEventIdhandling with undefined inputslastEventIdbehavior with primitive inputsThe mock usage and assertions are appropriate for verifying the parameter passing logic.
135-166: LGTM! Excellent test for AsyncIterable support with cleanup.The test demonstrates proper handling of:
- AsyncIterable return values (not just generators)
- Cleanup logic execution via finally blocks
- Iterator termination via
return()methodThe cleanup verification ensures proper resource management.
packages/trpc/src/to-orpc-router.ts (3)
2-7: LGTM: Import additions support new functionality.The new imports are appropriate for the event iterator and metadata handling features being added.
13-16: LGTM: Type transformation correctly handles async iterables.The conditional type properly transforms async iterable outputs to
AsyncIteratorObjectwhile preserving non-async types.
26-26: LGTM: Output schema type correctly applies the transformation.The integration of
experimental_ToORPCOutputin the procedure type definition is appropriate.
| handler: async ({ context, signal, path, input, lastEventId }) => { | ||
| try { | ||
| return await procedure({ | ||
| const trpcInput = lastEventId !== undefined && (input === undefined || isObject(input)) | ||
| ? { ...input, lastEventId } | ||
| : input | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Verify input spreading behavior with complex objects.
The input merging logic looks correct, but spreading could have unexpected behavior with objects containing getters, symbols, or non-enumerable properties.
🏁 Script executed:
#!/bin/bash
# Description: Search for test cases that verify input merging behavior with complex objects
# Expected: Tests covering edge cases like objects with getters, symbols, or prototype pollution
rg -A 10 -B 5 "lastEventId.*input|input.*lastEventId" --type tsLength of output: 17376
Add tests for input merging edge cases with complex objects
The current tests only cover primitive and plain‐object inputs. Since object spread only copies own, enumerable, string-keyed properties, please add unit tests in packages/trpc/src/to-orpc-router.test.ts to verify behavior when input contains:
- Getter properties (e.g.
Object.defineProperty(input, 'foo', { get: … })) - Symbol-keyed properties
- Non-enumerable properties
- Inherited (prototype) properties
This will ensure the merge { …input, lastEventId } behaves as expected in all edge cases.
🤖 Prompt for AI Agents
In packages/trpc/src/to-orpc-router.ts around lines 97 to 102, the code merges
input with lastEventId using object spread, which only copies own, enumerable,
string-keyed properties. To ensure correct behavior in edge cases, add unit
tests in packages/trpc/src/to-orpc-router.test.ts that cover inputs containing
getter properties, symbol-keyed properties, non-enumerable properties, and
inherited prototype properties. These tests should verify how the merge handles
these cases and confirm the output matches expected behavior.
| if (isAsyncIterable(output)) { | ||
| return mapEventIterator(output[Symbol.asyncIterator](), { | ||
| error: async error => error, | ||
| value: (value) => { | ||
| if (isTrackedEnvelope(value)) { | ||
| const [id, data] = value | ||
|
|
||
| return ORPC.withEventMeta({ | ||
| id, | ||
| data, | ||
| } as TrackedData<unknown>, { | ||
| id, | ||
| }) | ||
| } | ||
|
|
||
| return value | ||
| }, | ||
| }) | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Review the type cast safety and async iterator error handling.
The implementation handles async iterables correctly, but there are potential concerns:
- The type cast
as TrackedData<unknown>assumes the tracked envelope structure is always valid - The
mapEventIteratorerror handling passes errors through unchanged - verify this aligns with expected error propagation
Consider adding runtime validation for the tracked envelope structure:
if (isTrackedEnvelope(value)) {
const [id, data] = value
+
+ // Validate tracked envelope structure
+ if (typeof id !== 'string' && typeof id !== 'number') {
+ throw new Error('Invalid tracked envelope: id must be string or number')
+ }
return ORPC.withEventMeta({
id,
data,
- } as TrackedData<unknown>, {
+ }, {
id,
})
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if (isAsyncIterable(output)) { | |
| return mapEventIterator(output[Symbol.asyncIterator](), { | |
| error: async error => error, | |
| value: (value) => { | |
| if (isTrackedEnvelope(value)) { | |
| const [id, data] = value | |
| return ORPC.withEventMeta({ | |
| id, | |
| data, | |
| } as TrackedData<unknown>, { | |
| id, | |
| }) | |
| } | |
| return value | |
| }, | |
| }) | |
| } | |
| if (isAsyncIterable(output)) { | |
| return mapEventIterator(output[Symbol.asyncIterator](), { | |
| error: async error => error, | |
| value: (value) => { | |
| if (isTrackedEnvelope(value)) { | |
| const [id, data] = value | |
| // Validate tracked envelope structure | |
| if (typeof id !== 'string' && typeof id !== 'number') { | |
| throw new Error('Invalid tracked envelope: id must be string or number') | |
| } | |
| return ORPC.withEventMeta({ | |
| id, | |
| data, | |
| }, { | |
| id, | |
| }) | |
| } | |
| return value | |
| }, | |
| }) | |
| } |
🤖 Prompt for AI Agents
In packages/trpc/src/to-orpc-router.ts between lines 112 and 130, the code casts
the tracked envelope to TrackedData<unknown> without runtime validation, which
may cause unsafe assumptions. Add runtime checks to confirm the structure of the
tracked envelope before casting to ensure type safety. Also, review the error
handler in mapEventIterator to confirm that passing errors through unchanged
matches the expected error propagation behavior; adjust the error handling logic
if necessary to properly handle or transform errors.
There was a problem hiding this 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 introduces support for tRPC subscriptions using event iterators, including resumable subscriptions with tracked data. The changes handle passing lastEventId and transforming tRPC's TrackedData envelopes into oRPC events. The review identifies a type cast issue in to-orpc-router.ts and a potential type issue in the tests, which need to be addressed to ensure type safety and correctness.
|
|
||
| return ORPC.withEventMeta({ | ||
| id, | ||
| data, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The cast as TrackedData<unknown> is incorrect. The object { id, data } is not a tuple of type [string, unknown], which is what TrackedData<unknown> resolves to. Remove this cast to avoid potential type-related bugs.
| return ORPC.withEventMeta({ | |
| id, | |
| data, | |
| return ORPC.withEventMeta({ | |
| id, | |
| data, | |
| }, { | |
| id, | |
| }) |
Summary by CodeRabbit
New Features
lastEventIdparameter for event streaming.Tests
Chores