docs: add example of event iterator to playgrounds#1047
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Note Other AI code review bot(s) detectedCodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review. WalkthroughAdds EventIteratorQueries streaming UI components across multiple playgrounds that consume oRPC SSE via TanStack Query and renders streamed JSON. Introduces BatchLinkPlugin usage with an exclude rule to skip batching for SSE paths and adds BatchHandlerPlugin to some server RPC handlers. All changes are additive. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor U as User
participant C as EventIteratorQueries (UI)
participant Q as TanStack Query
participant O as oRPC Client
participant S as Server (SSE)
U->>C: Open page
C->>Q: useQuery(streamedOptions)
Q->>O: Issue SSE request (marked sse)
O->>S: GET /sse/...
Note right of S: Server streams chunks
S-->>O: chunk 1..n
O-->>Q: forward chunks
Q-->>C: update cache/state per chunk
C-->>U: render streamed JSON updates
S-->>O: stream end
O-->>Q: finalize
sequenceDiagram
participant O as oRPC Client
participant B as BatchLinkPlugin
participant S as Server
O->>B: Outgoing request (path)
alt path[0] == "sse"
B-->>O: Exclude from batching
O->>S: Send request immediately (SSE)
else
B->>B: Group/Batch request
B->>S: Send batched request
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (4)
🧰 Additional context used🧬 Code graph analysis (4)playgrounds/nuxt/server/routes/rpc/[...].ts (1)
playgrounds/solid-start/src/routes/rpc/[...rest].ts (1)
playgrounds/svelte-kit/src/routes/rpc/[...rest]/+server.ts (1)
playgrounds/tanstack-start/src/routes/api/rpc.$.ts (1)
⏰ 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). (3)
🔇 Additional comments (4)
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. Comment |
Summary of ChangesHello @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 documentation and examples within the project's playgrounds by adding a robust demonstration of oRPC's experimental event iterator for streaming data. By integrating this functionality with Tanstack Query across various frontend frameworks, it provides a clear and practical guide for developers looking to implement real-time data streaming. The changes also include necessary adjustments to the oRPC client configurations to ensure proper handling of streaming requests, thereby improving the overall functionality and educational value of the playgrounds. Highlights
Using Gemini Code AssistThe 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
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 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
|
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
There was a problem hiding this comment.
Code Review
This pull request adds examples for event iterators to various playground applications. The changes are consistent across the different frameworks, demonstrating how to use oRPC streaming with Tanstack Query. The configuration is also updated to exclude streaming endpoints from request batching, which is correct. I've found one issue with the useQuery hook usage in the Astro playground and a minor formatting issue in the Svelte example. Otherwise, the changes look good.
More templates
@orpc/arktype
@orpc/client
@orpc/contract
@orpc/experimental-durable-iterator
@orpc/hey-api
@orpc/interop
@orpc/json-schema
@orpc/nest
@orpc/openapi
@orpc/openapi-client
@orpc/otel
@orpc/react
@orpc/react-query
@orpc/experimental-react-swr
@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.
Actionable comments posted: 2
🧹 Nitpick comments (15)
playgrounds/cloudflare-worker/src/lib/orpc.ts (1)
16-22: Exclude predicate hardening + plugin ordering check with DurableIterator.
- Harden exclude as in other files to handle non‑array path and fall back to URL/Accept.
- Minor: confirm BatchLinkPlugin runs before any plugin that might transform SSE requests. If plugin ordering is by plugin.order, BatchLinkPlugin has order 5_000_000; ensure DurableIteratorLinkPlugin doesn’t register a higher-priority interceptor that would rely on batching decisions.
Proposed exclude:
- new BatchLinkPlugin({ - exclude: ({ path }) => path[0] === 'sse', + new BatchLinkPlugin({ + exclude: ({ path, request }) => { + const seg0 = Array.isArray(path) ? path[0] : String(path ?? '').split(/[.//]/)[0] + const isSsePath = seg0 === 'sse' || request.url.includes('/sse/') + const acceptsSse = + typeof request.headers['accept'] === 'string' && + request.headers['accept'].includes('text/event-stream') + return isSsePath || acceptsSse + },To verify relative ordering, please confirm the DurableIterator plugin’s interceptor order (or share its order value). Based on learnings.
playgrounds/nuxt/plugins/orpc.client.ts (1)
12-20: Defensive exclude for SSE and brief inline comment.Guard for string/undefined path and document the intent so future edits don’t break streaming demos.
- new BatchLinkPlugin({ - exclude: ({ path }) => path[0] === 'sse', + new BatchLinkPlugin({ + // Never batch SSE endpoints; keep streaming semantics intact + exclude: ({ path, request }) => { + const seg0 = Array.isArray(path) ? path[0] : String(path ?? '').split(/[.//]/)[0] + return seg0 === 'sse' + || request.url.includes('/sse/') + || (typeof request.headers['accept'] === 'string' + && request.headers['accept'].includes('text/event-stream')) + },Based on learnings.
playgrounds/astro/src/lib/orpc.ts (1)
12-17: Robust exclude for SSE to avoid accidental batching regressions.Replicate the hardened predicate so it keeps working if path becomes a string or URL format changes.
- exclude: ({ path }) => path[0] === 'sse', + exclude: ({ path, request }) => { + const seg0 = Array.isArray(path) ? path[0] : String(path ?? '').split(/[.//]/)[0] + return seg0 === 'sse' + || request.url.includes('/sse/') + || (typeof request.headers['accept'] === 'string' + && request.headers['accept'].includes('text/event-stream')) + },Based on learnings.
playgrounds/next/src/lib/orpc.ts (1)
20-26: Make theexcludepredicate resilient to stringpathand cover SSE requests
Guard against non-arraypathvalues and also check the request URL orAcceptheader for SSE.playgrounds/next/src/lib/orpc.ts @@ -18,7 +18,20 @@ const link = new RPCLink({ plugins: [ new BatchLinkPlugin({ - exclude: ({ path }) => path[0] === 'sse', + exclude: ({ path, request }) => { + const seg0 = Array.isArray(path) + ? path[0] + : String(path ?? '').split(/[.\\/]/)[0] // handles 'sse.foo' or 'sse/foo' + const isSsePath = seg0 === 'sse' || request.url.includes('/sse/') + const acceptsSse = + typeof request.headers['accept'] === 'string' && + request.headers['accept'].includes('text/event-stream') + return isSsePath || acceptsSse + }, groups: [{ condition: () => true, context: {}, }], }),playgrounds/tanstack-start/src/lib/orpc.ts (1)
34-39: LGTM; optional SSE detection enhancementConsider expanding the exclude callback to fall back on the request URL or Accept header when
pathisn’t an array:- exclude: ({ path }) => path[0] === 'sse', + exclude: ({ path, request }) => { + const seg0 = Array.isArray(path) + ? path[0] + : String(path ?? '').split(/[.//]/)[0]; + return seg0 === 'sse' + || request.url.includes('/sse/') + || (typeof request.headers['accept'] === 'string' + && request.headers['accept'].includes('text/event-stream')); + },playgrounds/astro/src/components/orpc-stream.tsx (1)
5-16: Tighten UX and fix heading style
Add loading/error handling and correct “Tanstack” → “TanStack”. QueryClient is already a stable singleton and SSE is excluded from batching—no further changes needed there.Apply:
export function EventIteratorQueries() { - const streamed = useQuery(orpc.sse.experimental_streamedOptions({ queryFnOptions: { maxChunks: 3 } }), queryClient) + const streamed = useQuery(orpc.sse.experimental_streamedOptions({ queryFnOptions: { maxChunks: 3 } }), queryClient) + const { data, isPending, error } = streamed return ( <div> - <h2>oRPC and Tanstack Query | Event Iterator example</h2> + <h2>oRPC and TanStack Query | Event Iterator example</h2> <pre> - {JSON.stringify(streamed.data, null, 2)} + {isPending + ? 'Loading…' + : error + ? String(error) + : JSON.stringify(data ?? 'No data yet', null, 2)} </pre> </div> ) }playgrounds/svelte-kit/src/routes/orpc-stream.svelte (1)
13-18: Add basic loading/error states for a clearer demoSurface pending/error to avoid showing empty JSON during fetch or on failures.
<div> <h2>oRPC and Tanstack Query | Event Iterator example</h2> - <pre> -{JSON.stringify($streamed.data, null, 2)} - </pre> + {#if $streamed.isPending} + <pre>Loading…</pre> + {:else if $streamed.error} + <pre class="error">{String($streamed.error)}</pre> + {:else} + <pre>{JSON.stringify($streamed.data, null, 2)}</pre> + {/if} </div>playgrounds/svelte-kit/src/lib/orpc.ts (1)
14-20: Optional: document mode for clarityBatchLinkPlugin defaults to mode: 'streaming'. Consider setting it explicitly to self-document intended behavior.
new BatchLinkPlugin({ exclude: ({ path }) => path[0] === 'sse', + mode: 'streaming', groups: [{ condition: () => true, context: {}, }], }),playgrounds/cloudflare-worker/src/components/orpc-stream.tsx (1)
7-14: Show loading/error to improve the example UXReact Query exposes status flags; render them for a clearer streaming demo.
return ( <div> <h2>oRPC and Tanstack Query | Event Iterator example</h2> - <pre> - {JSON.stringify(streamed.data, null, 2)} - </pre> + <pre> + {streamed.isPending + ? 'Loading…' + : streamed.error + ? String(streamed.error) + : JSON.stringify(streamed.data, null, 2)} + </pre> </div> )playgrounds/solid-start/src/routes/orpc-stream.tsx (1)
9-16: Optional: add pending/error UI like other demosParity with React/Svelte examples makes the demo clearer.
return ( <div> <h2>oRPC and Tanstack Query | Event Iterator example</h2> - <pre> - {JSON.stringify(streamed.data, null, 2)} - </pre> + <pre> + {streamed.isPending + ? 'Loading…' + : streamed.error + ? String(streamed.error) + : JSON.stringify(streamed.data, null, 2)} + </pre> </div> )playgrounds/nuxt/components/orpc-stream.vue (1)
6-8: Add basic loading/error UI and avoid SSE refetch on window focus.
- Streaming demos benefit from showing pending/error states to clarify behavior.
- Consider disabling refetchOnWindowFocus to prevent restarting the stream when tab focuses.
Example (adjust to your integration surface):
- Add UI: query.isPending ? 'Loading…' : JSON.
- Set refetchOnWindowFocus: false via your query options/config.
Please confirm where you prefer to pass refetchOnWindowFocus: false (inside experimental_streamedOptions if supported, or via QueryClient defaults for demos).
Also applies to: 12-18
playgrounds/solid-start/src/lib/orpc.ts (1)
21-27: Optional: Consider grouping batches more narrowly.
groups: [{ condition: () => true }]will batch all eligible requests together. If you anticipate varied headers/contexts or large concurrent volumes, consider grouping by path or method to keep batches smaller and more coherent.Is global batching intentional for this playground, or would grouping by first path segment be preferable?
playgrounds/tanstack-start/src/components/orpc-stream.tsx (1)
4-15: Provide loading/error states and stabilize UX for streaming.
- Show
streamed.isPending/isErrorUI to make the example clearer.- Consider
refetchOnWindowFocus: falseto avoid restarting the stream on focus.playgrounds/next/src/app/orpc-stream.tsx (1)
6-16: Minor UX: prevent refetch-on-focus for SSE and add basic status UI.Next.js client components often regain focus during hot reload/navigation, which can restart SSE queries. Consider
refetchOnWindowFocus: falseand simple loading/error messages for the demo.Confirm whether your
experimental_streamedOptionsAPI supports merging additional TanStack options directly; if not, set this via QueryClient defaults for the demo page.playgrounds/electron/src/renderer/src/components/orpc-stream.tsx (1)
4-15: Demo polish: add loading/error UI; consider disabling refetch on focus.Electron windows can frequently gain/lose focus; disable refetch-on-focus for smoother streaming and display basic
isPending/isErrorstates.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (25)
playgrounds/astro/src/components/orpc-stream.tsx(1 hunks)playgrounds/astro/src/lib/orpc.ts(1 hunks)playgrounds/astro/src/pages/index.astro(2 hunks)playgrounds/browser-extension/entrypoints/popup/App.tsx(2 hunks)playgrounds/browser-extension/entrypoints/popup/components/orpc-stream.tsx(1 hunks)playgrounds/cloudflare-worker/src/App.tsx(2 hunks)playgrounds/cloudflare-worker/src/components/orpc-stream.tsx(1 hunks)playgrounds/cloudflare-worker/src/lib/orpc.ts(2 hunks)playgrounds/electron/src/renderer/src/App.tsx(2 hunks)playgrounds/electron/src/renderer/src/components/orpc-stream.tsx(1 hunks)playgrounds/next/src/app/orpc-stream.tsx(1 hunks)playgrounds/next/src/app/page.tsx(2 hunks)playgrounds/next/src/lib/orpc.ts(1 hunks)playgrounds/nuxt/app.vue(1 hunks)playgrounds/nuxt/components/orpc-stream.vue(1 hunks)playgrounds/nuxt/plugins/orpc.client.ts(1 hunks)playgrounds/solid-start/src/lib/orpc.ts(2 hunks)playgrounds/solid-start/src/routes/index.tsx(2 hunks)playgrounds/solid-start/src/routes/orpc-stream.tsx(1 hunks)playgrounds/svelte-kit/src/lib/orpc.ts(1 hunks)playgrounds/svelte-kit/src/routes/+page.svelte(2 hunks)playgrounds/svelte-kit/src/routes/orpc-stream.svelte(1 hunks)playgrounds/tanstack-start/src/components/orpc-stream.tsx(1 hunks)playgrounds/tanstack-start/src/lib/orpc.ts(1 hunks)playgrounds/tanstack-start/src/routes/index.tsx(2 hunks)
🧰 Additional context used
🧬 Code graph analysis (17)
playgrounds/tanstack-start/src/routes/index.tsx (1)
playgrounds/tanstack-start/src/components/orpc-stream.tsx (1)
EventIteratorQueries(4-15)
playgrounds/cloudflare-worker/src/lib/orpc.ts (1)
packages/client/src/plugins/batch.ts (1)
BatchLinkPlugin(75-310)
playgrounds/cloudflare-worker/src/components/orpc-stream.tsx (2)
playgrounds/astro/src/components/orpc-stream.tsx (1)
EventIteratorQueries(5-16)playgrounds/cloudflare-worker/src/lib/orpc.ts (1)
orpc(28-28)
playgrounds/tanstack-start/src/components/orpc-stream.tsx (1)
playgrounds/tanstack-start/src/lib/orpc.ts (1)
orpc(48-48)
playgrounds/electron/src/renderer/src/components/orpc-stream.tsx (12)
playgrounds/astro/src/components/orpc-stream.tsx (1)
EventIteratorQueries(5-16)playgrounds/browser-extension/entrypoints/popup/components/orpc-stream.tsx (1)
EventIteratorQueries(4-15)playgrounds/cloudflare-worker/src/components/orpc-stream.tsx (1)
EventIteratorQueries(4-15)playgrounds/next/src/app/orpc-stream.tsx (1)
EventIteratorQueries(6-17)playgrounds/solid-start/src/routes/orpc-stream.tsx (1)
EventIteratorQueries(4-17)playgrounds/tanstack-start/src/components/orpc-stream.tsx (1)
EventIteratorQueries(4-15)playgrounds/astro/src/lib/orpc.ts (1)
orpc(23-23)playgrounds/cloudflare-worker/src/lib/orpc.ts (1)
orpc(28-28)playgrounds/next/src/lib/orpc.ts (1)
orpc(32-32)playgrounds/solid-start/src/lib/orpc.ts (1)
orpc(33-33)playgrounds/svelte-kit/src/lib/orpc.ts (1)
orpc(26-26)playgrounds/tanstack-start/src/lib/orpc.ts (1)
orpc(48-48)
playgrounds/solid-start/src/lib/orpc.ts (1)
packages/client/src/plugins/batch.ts (1)
BatchLinkPlugin(75-310)
playgrounds/nuxt/plugins/orpc.client.ts (1)
packages/client/src/plugins/batch.ts (1)
BatchLinkPlugin(75-310)
playgrounds/astro/src/components/orpc-stream.tsx (3)
playgrounds/browser-extension/entrypoints/popup/components/orpc-stream.tsx (1)
EventIteratorQueries(4-15)playgrounds/solid-start/src/routes/orpc-stream.tsx (1)
EventIteratorQueries(4-17)playgrounds/astro/src/lib/orpc.ts (1)
orpc(23-23)
playgrounds/browser-extension/entrypoints/popup/App.tsx (1)
playgrounds/browser-extension/entrypoints/popup/components/orpc-stream.tsx (1)
EventIteratorQueries(4-15)
playgrounds/solid-start/src/routes/index.tsx (1)
playgrounds/solid-start/src/routes/orpc-stream.tsx (1)
EventIteratorQueries(4-17)
playgrounds/browser-extension/entrypoints/popup/components/orpc-stream.tsx (4)
playgrounds/astro/src/components/orpc-stream.tsx (1)
EventIteratorQueries(5-16)playgrounds/cloudflare-worker/src/components/orpc-stream.tsx (1)
EventIteratorQueries(4-15)playgrounds/solid-start/src/routes/orpc-stream.tsx (1)
EventIteratorQueries(4-17)playgrounds/cloudflare-worker/src/lib/orpc.ts (1)
orpc(28-28)
playgrounds/solid-start/src/routes/orpc-stream.tsx (2)
playgrounds/astro/src/components/orpc-stream.tsx (1)
EventIteratorQueries(5-16)playgrounds/solid-start/src/lib/orpc.ts (1)
orpc(33-33)
playgrounds/electron/src/renderer/src/App.tsx (1)
playgrounds/electron/src/renderer/src/components/orpc-stream.tsx (1)
EventIteratorQueries(4-15)
playgrounds/cloudflare-worker/src/App.tsx (1)
playgrounds/cloudflare-worker/src/components/orpc-stream.tsx (1)
EventIteratorQueries(4-15)
playgrounds/next/src/app/page.tsx (1)
playgrounds/next/src/app/orpc-stream.tsx (1)
EventIteratorQueries(6-17)
playgrounds/svelte-kit/src/lib/orpc.ts (1)
packages/client/src/plugins/batch.ts (1)
BatchLinkPlugin(75-310)
playgrounds/next/src/app/orpc-stream.tsx (1)
playgrounds/next/src/lib/orpc.ts (1)
orpc(32-32)
⏰ 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). (2)
- GitHub Check: lint
- GitHub Check: publish-commit
🔇 Additional comments (11)
playgrounds/astro/src/pages/index.astro (1)
16-17: Astro wiring LGTMImport + client:only usage are consistent with your other components.
If you ever switch this island to share cache with others, consider wrapping a parent on the page to avoid multiple clients.
playgrounds/browser-extension/entrypoints/popup/App.tsx (1)
13-15: QueryClientProvider is correctly integrated in the popup entrypoint
main.tsx importsQueryClient/QueryClientProvider, creates aqueryClient, and wraps the app in<QueryClientProvider>, souseQuerywill function as expected.playgrounds/browser-extension/entrypoints/popup/components/orpc-stream.tsx (1)
4-15: Add basic loading/error states and fix “TanStack” capitalizationConsider a minimal UX pass so the example doesn’t render “undefined” while loading and surfaces errors, and update “Tanstack” to “TanStack”:
export function EventIteratorQueries() { - const streamed = useQuery(orpc.sse.experimental_streamedOptions({ queryFnOptions: { maxChunks: 3 } })) + const streamed = useQuery(orpc.sse.experimental_streamedOptions({ queryFnOptions: { maxChunks: 3 } })) + const { data, isPending, error } = streamed return ( <div> - <h2>oRPC and Tanstack Query | Event Iterator example</h2> + <h2>oRPC and TanStack Query | Event Iterator example</h2> <pre> - {JSON.stringify(streamed.data, null, 2)} + {isPending ? 'Loading…' : error ? String(error) : JSON.stringify(data ?? 'No data yet', null, 2)} </pre> </div> ) }Please confirm that your oRPC client setup (in the browser-extension) explicitly excludes SSE endpoints from the batch-link plugin, so that streamed requests aren’t inadvertently batched.
playgrounds/electron/src/renderer/src/App.tsx (1)
13-14: No BatchLinkPlugin in Electron renderer oRPC client; SSE routes are inherently excluded from batching.playgrounds/svelte-kit/src/routes/+page.svelte (1)
5-5: SvelteKit streaming example wired correctlyImport path and placement under QueryClientProvider look good and consistent with existing sections.
Also applies to: 24-26
playgrounds/cloudflare-worker/src/App.tsx (1)
6-6: Cloudflare Worker: Streaming sample added cleanlyImport and render order are consistent with the rest of the page. Looks good.
Also applies to: 35-36
playgrounds/tanstack-start/src/routes/index.tsx (1)
4-4: TanStack Start: Clean additionImport path and placement are consistent with existing sections. No issues.
Also applies to: 23-24
playgrounds/nuxt/app.vue (1)
13-16: Nuxt: OrpcStream component found and will be auto-registeredplaygrounds/solid-start/src/routes/index.tsx (1)
20-21: LGTM: clean integration of the streaming demoImport and render look correct; no side effects on existing UI.
Also applies to: 3-3
playgrounds/svelte-kit/src/lib/orpc.ts (1)
13-21: SSE exclusion is correctly configured. Top-level router namespace issse, sopath[0] === 'sse'will bypass batching as intended.playgrounds/solid-start/src/lib/orpc.ts (1)
20-28: Remove unnecessary string guard
Thepathparameter inBatchLinkPlugin’sexcludecallback is always astring[](e.g. the official docs callpath.join('/')on it) (orpc.unnoq.com), so checkingpath[0] === 'sse'already tests the first segment correctly.Likely an incorrect or invalid review comment.
Summary by CodeRabbit
New Features
Performance
UI