Skip to content

refactor: unify stream next proxies#409

Merged
jerry609 merged 2 commits intodevfrom
refactor/pr14-next-stream-proxies
Mar 15, 2026
Merged

refactor: unify stream next proxies#409
jerry609 merged 2 commits intodevfrom
refactor/pr14-next-stream-proxies

Conversation

@jerry609
Copy link
Owner

What changed

  • add proxyStream() to the shared Next backend proxy helper with long-lived SSE support, optional JSON passthrough, shared auth handling, and no default request timeout
  • migrate the remaining stream proxy routes to the shared helper: studio/chat, gen-code, research/paperscool/daily, research/paperscool/analyze, and research/repro/context POST
  • preserve the existing paperscool/daily JSON fast-path and the explicit 502 Upstream API unreachable fallback shape for the research stream routes that already had it
  • add focused tests for the stream helper and each migrated stream route

Why

  • finishes the stream-proxy cleanup as a single reviewable slice without mixing in binary download or HTML fallback routes
  • removes the duplicated SSE proxy code paths and aligns them on one helper contract
  • leaves only two direct backend fetch handlers in Next: the binary export route and the HTML unsubscribe route

Validation

  • npx vitest run src/app/api/_utils/backend-proxy.test.ts src/app/api/_utils/auth-headers.test.ts src/app/api/papers/export/route.test.ts src/app/api/studio/chat/route.test.ts src/app/api/gen-code/route.test.ts src/app/api/research/paperscool/daily/route.test.ts src/app/api/research/paperscool/analyze/route.test.ts src/app/api/research/repro/context/route.test.ts
  • npx eslint src/app/api/_utils/backend-proxy.ts src/app/api/_utils/backend-proxy.test.ts src/app/api/studio/chat/route.ts src/app/api/studio/chat/route.test.ts src/app/api/gen-code/route.ts src/app/api/gen-code/route.test.ts src/app/api/research/paperscool/daily/route.ts src/app/api/research/paperscool/daily/route.test.ts src/app/api/research/paperscool/analyze/route.ts src/app/api/research/paperscool/analyze/route.test.ts src/app/api/research/repro/context/route.ts src/app/api/research/repro/context/route.test.ts
  • npx tsc --noEmit
  • npm run build

Remaining cleanup

  • web/src/app/api/papers/export/route.ts
  • web/src/app/api/newsletter/unsubscribe/[token]/route.ts

Copilot AI review requested due to automatic review settings March 15, 2026 07:20
@vercel
Copy link

vercel bot commented Mar 15, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
paper-bot Ready Ready Preview, Comment Mar 15, 2026 7:40am

@coderabbitai
Copy link

coderabbitai bot commented Mar 15, 2026

Warning

Rate limit exceeded

@jerry609 has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 2 minutes and 40 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 1d0b5fc8-047e-416b-a29f-e8fde6ea65d4

📥 Commits

Reviewing files that changed from the base of the PR and between 5b33d08 and e1896b4.

📒 Files selected for processing (9)
  • web/src/app/api/_utils/backend-proxy.test.ts
  • web/src/app/api/_utils/backend-proxy.ts
  • web/src/app/api/_utils/stream-route-contracts.test.ts
  • web/src/app/api/gen-code/route.ts
  • web/src/app/api/research/paperscool/analyze/route.ts
  • web/src/app/api/research/paperscool/daily/route.ts
  • web/src/app/api/research/repro/context/route.test.ts
  • web/src/app/api/research/repro/context/route.ts
  • web/src/app/api/studio/chat/route.ts
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch refactor/pr14-next-stream-proxies
📝 Coding Plan
  • Generate coding plan for human review comments

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

Summary of Changes

Hello, 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 refactors the application's backend proxying logic by centralizing stream handling into a single, robust utility. The primary goal is to eliminate duplicated code paths for Server-Sent Events (SSE) and standardize how long-lived connections and their associated authentication and error handling are managed across various API routes. This change streamlines the codebase, making it more maintainable and consistent, and sets the stage for further simplification of backend fetch handlers.

Highlights

  • New Stream Proxy Helper: Introduced a new proxyStream() helper function in the shared Next.js backend proxy utility. This helper supports long-lived Server-Sent Events (SSE), optional JSON passthrough, shared authentication handling, and has no default request timeout.
  • Migration of Stream Routes: Migrated several existing stream proxy routes to utilize the new proxyStream() helper. These include studio/chat, gen-code, research/paperscool/daily, research/paperscool/analyze, and research/repro/context POST endpoints.
  • Preserved Functionality: Ensured that existing specific functionalities, such as the paperscool/daily JSON fast-path and the explicit 502 Upstream API unreachable fallback shape for research stream routes, are preserved after migration.
  • Comprehensive Testing: Added focused unit tests for the new proxyStream() helper itself, as well as for each of the migrated stream routes, to ensure correct functionality and error handling.

🧠 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.

Changelog
  • web/src/app/api/_utils/backend-proxy.test.ts
    • Added proxyStream to imports.
    • Included new test cases for proxyStream to verify SSE passthrough without buffering.
    • Added a test case for proxyStream to confirm correct JSON fallback when a non-stream response is received.
  • web/src/app/api/_utils/backend-proxy.ts
    • Imported Agent from undici for custom dispatchers.
    • Defined StreamProxyOptions type for stream-specific proxy configurations.
    • Created SSE_DISPATCHER with bodyTimeout and headersTimeout set to 0 for long-lived connections.
    • Implemented the proxyStream asynchronous function to handle streaming responses, including content type negotiation, header setting, and error handling.
    • Modified fetchUpstream to accept an optional init object, allowing custom dispatcher configurations.
  • web/src/app/api/gen-code/route.test.ts
    • Added a new test file for the gen-code route.
    • Included tests to verify that the POST request correctly utilizes the proxyStream helper with appropriate parameters.
  • web/src/app/api/gen-code/route.ts
    • Removed custom apiBaseUrl function and withBackendAuth import.
    • Imported apiBaseUrl and proxyStream from the shared backend proxy utility.
    • Refactored the POST handler to use the new proxyStream function for code generation requests.
  • web/src/app/api/research/paperscool/analyze/route.test.ts
    • Added a new test file for the paperscool/analyze route.
    • Included tests to confirm that POST requests are correctly proxied through the proxyStream helper with specific options and error handling.
  • web/src/app/api/research/paperscool/analyze/route.ts
    • Removed Agent import and custom sseDispatcher.
    • Imported apiBaseUrl and proxyStream from the shared backend proxy utility.
    • Refactored the POST handler to use proxyStream, including custom error handling for unreachable upstream APIs.
  • web/src/app/api/research/paperscool/daily/route.test.ts
    • Added a new test file for the paperscool/daily route.
    • Included tests to verify that POST requests are proxied via proxyStream with stream/JSON passthrough options.
    • Tested the onError fallback mechanism to ensure correct 502 response for upstream errors.
  • web/src/app/api/research/paperscool/daily/route.ts
    • Removed Agent import, custom sseDispatcher, and withBackendAuth import.
    • Imported apiBaseUrl and proxyStream from the shared backend proxy utility.
    • Refactored the POST handler to use proxyStream, incorporating JSON fallback, authentication, and custom error handling.
  • web/src/app/api/research/repro/context/route.test.ts
    • Added a new test file for the repro/context route.
    • Included tests to confirm that the GET request still uses the proxyJson helper.
    • Added tests to verify that the POST request correctly uses the proxyStream helper for context generation.
  • web/src/app/api/research/repro/context/route.ts
    • Replaced withBackendAuth import with proxyStream import from the shared backend proxy utility.
    • Refactored the POST handler to use the new proxyStream function for context generation requests.
  • web/src/app/api/studio/chat/route.test.ts
    • Added a new test file for the studio/chat route.
    • Included tests to ensure that the POST request correctly utilizes the proxyStream helper with authentication.
  • web/src/app/api/studio/chat/route.ts
    • Removed custom apiBaseUrl function and withBackendAuth import.
    • Imported apiBaseUrl and proxyStream from the shared backend proxy utility.
    • Refactored the POST handler to use the new proxyStream function for chat requests.
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

@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 introduces a significant and valuable refactoring by unifying the server-sent event (SSE) stream proxy logic into a shared proxyStream helper. This greatly simplifies the route handlers for studio/chat, gen-code, and various research-related endpoints, making them more consistent and easier to maintain. The addition of the passthroughNonStreamResponse option to handle mixed stream/JSON responses is a clever solution that cleans up complex logic in the paperscool/daily route. The new tests for the helper and each migrated route are also well-written and improve test coverage.

I've found one minor issue in the new proxyStream helper related to the fallback content type for non-stream responses, for which I've left a specific comment with a suggested fix. Overall, this is an excellent improvement.

) {
const text = await upstream.text()
return buildTextResponse(text, upstream, {
responseContentType: requestOptions.responseContentType ?? "application/json",

Choose a reason for hiding this comment

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

medium

The expression requestOptions.responseContentType ?? "application/json" is currently equivalent to requestOptions.responseContentType because requestOptions.responseContentType is always defined (it defaults to "text/event-stream").

This can lead to a bug when passthroughNonStreamResponse is true and the upstream API returns a non-stream response (e.g., JSON) without a Content-Type header. In that scenario, the response will be incorrectly served with Content-Type: text/event-stream.

For non-stream passthrough responses, the fallback content type should be application/json to correctly handle this case.

Suggested change
responseContentType: requestOptions.responseContentType ?? "application/json",
responseContentType: "application/json",

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Refactors several Next.js API route handlers that proxy to the backend (including SSE endpoints) to use a shared proxyStream helper, consolidating streaming proxy behavior and adding targeted Vitest coverage.

Changes:

  • Added proxyStream to web/src/app/api/_utils/backend-proxy.ts (SSE dispatcher + optional JSON passthrough).
  • Updated multiple API routes to use proxyStream instead of bespoke fetch/SSE handling.
  • Added route-level tests verifying correct proxyStream invocation and error fallback behavior.

Reviewed changes

Copilot reviewed 12 out of 12 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
web/src/app/api/studio/chat/route.ts Switch studio chat POST to shared stream proxy helper.
web/src/app/api/studio/chat/route.test.ts Adds test to confirm shared proxy helper usage.
web/src/app/api/research/repro/context/route.ts Uses shared stream proxy for POST context generation while keeping existing GET proxy.
web/src/app/api/research/repro/context/route.test.ts Adds tests for GET proxy behavior and POST stream proxy usage.
web/src/app/api/research/paperscool/daily/route.ts Replaces custom SSE/JSON fallback proxying with proxyStream options.
web/src/app/api/research/paperscool/daily/route.test.ts Adds test for stream proxy options and onError fallback response.
web/src/app/api/research/paperscool/analyze/route.ts Replaces custom SSE proxying with proxyStream.
web/src/app/api/research/paperscool/analyze/route.test.ts Adds test to confirm shared proxy helper usage.
web/src/app/api/gen-code/route.ts Switch gen-code POST to shared stream proxy helper.
web/src/app/api/gen-code/route.test.ts Adds test to confirm shared proxy helper usage.
web/src/app/api/_utils/backend-proxy.ts Introduces proxyStream and undici dispatcher support for long-lived streams.
web/src/app/api/_utils/backend-proxy.test.ts Adds tests for SSE passthrough and non-stream fallback behavior.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

) {
const text = await upstream.text()
return buildTextResponse(text, upstream, {
responseContentType: requestOptions.responseContentType ?? "application/json",
@jerry609 jerry609 force-pushed the refactor/pr13-next-json-fallback-proxies branch from 2462ff9 to 2310e36 Compare March 15, 2026 07:31
@jerry609 jerry609 force-pushed the refactor/pr14-next-stream-proxies branch from dcba4e9 to 706ab9e Compare March 15, 2026 07:31
@jerry609 jerry609 changed the base branch from refactor/pr13-next-json-fallback-proxies to dev March 15, 2026 07:34
@jerry609 jerry609 force-pushed the refactor/pr14-next-stream-proxies branch from 706ab9e to f4648a9 Compare March 15, 2026 07:34
@github-actions
Copy link

github-actions bot commented Mar 15, 2026

Vercel Preview

Copilot AI review requested due to automatic review settings March 15, 2026 07:38
@sonarqubecloud
Copy link

@jerry609 jerry609 merged commit a8ba43e into dev Mar 15, 2026
20 checks passed
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR centralizes Server-Sent Events (SSE) proxying for Next.js API routes by introducing a shared proxyStream helper and updating several streaming routes to use it, alongside new contract/tests to prevent regressions.

Changes:

  • Add proxyStream (SSE-aware) to the shared backend proxy utilities, including long-lived dispatcher support and optional JSON passthrough fallback.
  • Refactor streaming routes (studio chat, gen-code, paperscool analyze/daily, repro context generation) to use proxyStream instead of bespoke fetch/stream plumbing.
  • Add/extend Vitest coverage for streaming route contracts and the new proxy helper behavior.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
web/src/app/api/studio/chat/route.ts Switch studio chat SSE route to shared proxyStream helper.
web/src/app/api/research/repro/context/route.ts Route POST (context generation) now proxies via proxyStream; GET remains on existing _base proxy helper.
web/src/app/api/research/repro/context/route.test.ts Adds unit tests ensuring GET stays on _base and POST uses proxyStream with expected options.
web/src/app/api/research/paperscool/daily/route.ts Replace custom dispatcher + dual SSE/JSON handling with proxyStream + passthrough fallback and custom error handler.
web/src/app/api/research/paperscool/analyze/route.ts Replace custom dispatcher-based SSE proxy with proxyStream and custom error handler.
web/src/app/api/gen-code/route.ts Switch gen-code SSE route to shared proxyStream helper.
web/src/app/api/_utils/stream-route-contracts.test.ts Adds contract tests enforcing that key streaming routes call proxyStream with stable options.
web/src/app/api/_utils/backend-proxy.ts Introduces proxyStream, shared SSE dispatcher, and fetch support for undici dispatcher.
web/src/app/api/_utils/backend-proxy.test.ts Adds coverage for SSE passthrough behavior and non-stream fallback behavior in proxyStream.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

) {
const text = await upstream.text()
return buildTextResponse(text, upstream, {
responseContentType: "application/json",
@jerry609 jerry609 deleted the refactor/pr14-next-stream-proxies branch March 15, 2026 13:07
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