Skip to content

refactor: unify binary and html next proxies#410

Merged
jerry609 merged 2 commits intodevfrom
refactor/pr15-next-binary-html-proxies
Mar 15, 2026
Merged

refactor: unify binary and html next proxies#410
jerry609 merged 2 commits intodevfrom
refactor/pr15-next-binary-html-proxies

Conversation

@jerry609
Copy link
Owner

@jerry609 jerry609 commented Mar 15, 2026

What changed

  • add proxyBinary() to the shared Next backend proxy helper for protected downloads that need content-type/content-disposition passthrough
  • migrate web/src/app/api/papers/export/route.ts to the shared binary helper while preserving its explicit 502 Upstream API unreachable fallback body
  • migrate web/src/app/api/newsletter/unsubscribe/[token]/route.ts to the shared text helper with the existing escaped HTML fallback expressed through onError
  • extend helper tests to cover binary passthrough and update route tests to validate the new helper wiring and fallback behavior

Why

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/newsletter/unsubscribe/[token]/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/papers/export/route.ts src/app/api/papers/export/route.test.ts src/app/api/newsletter/unsubscribe/[token]/route.ts src/app/api/newsletter/unsubscribe/[token]/route.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

Result

  • rg -n "fetch\(" web/src/app/api --glob 'route.ts' now returns no results

Summary by CodeRabbit

  • Tests

    • Added comprehensive tests for binary export handling, authentication preservation, and newsletter unsubscribe flows.
  • Bug Fixes

    • Enhanced error handling for export and unsubscribe endpoints with detailed error responses.
  • Refactor

    • Centralized proxy utilities for consistent API handling across endpoints.

Copilot AI review requested due to automatic review settings March 15, 2026 07:26
@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:49am

@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 22 minutes and 39 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: ad62440d-9ee9-42cd-8bfa-f784b1b177d1

📥 Commits

Reviewing files that changed from the base of the PR and between 2608da1 and 528ad85.

📒 Files selected for processing (4)
  • web/src/app/api/_utils/backend-proxy.ts
  • web/src/app/api/_utils/final-proxy-route-contracts.test.ts
  • web/src/app/api/newsletter/unsubscribe/[token]/route.ts
  • web/src/app/api/papers/export/route.test.ts
📝 Walkthrough

Walkthrough

A new proxyBinary function is introduced to handle binary responses by fetching upstream and streaming the response with appropriate headers. Two API routes (newsletter unsubscribe and papers export) are refactored to use centralized proxy utilities, eliminating direct fetch calls and standardizing error handling. Corresponding tests are added.

Changes

Cohort / File(s) Summary
Backend Proxy Utilities
web/src/app/api/_utils/backend-proxy.ts, web/src/app/api/_utils/backend-proxy.test.ts
Adds proxyBinary function to handle binary responses with proper caching, content-type, and content-disposition headers. Introduces BinaryProxyOptions type for customizing response headers. New test case verifies binary download headers and auth forwarding.
Newsletter Unsubscribe Route
web/src/app/api/newsletter/unsubscribe/[token]/route.ts, web/src/app/api/newsletter/unsubscribe/[token]/route.test.ts
Migrates from direct fetch to proxyText utility with centralized error handling. Test file covers token URL encoding, header preservation, and HTML-escaped error fallback responses.
Papers Export Route
web/src/app/api/papers/export/route.ts, web/src/app/api/papers/export/route.test.ts
Replaces inline fetch logic with proxyBinary call, including auth headers and accept options. Test updated to mock proxy utility instead of global fetch, with error scenario validation via onError callback.

Sequence Diagram

sequenceDiagram
    participant Client
    participant ProxyBinary as proxyBinary<br/>(Backend Proxy)
    participant Upstream as Upstream API
    participant ResponseStream as Response Stream

    Client->>ProxyBinary: proxyBinary(req, url, method, options)
    ProxyBinary->>Upstream: fetch(url, method)
    Upstream-->>ProxyBinary: Response + ArrayBuffer
    ProxyBinary->>ProxyBinary: Assemble Headers<br/>(Cache-Control, Content-Type,<br/>Content-Disposition)
    ProxyBinary->>ResponseStream: new Response(buffer, {<br/>status, headers<br/>})
    ResponseStream-->>Client: Binary Response
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

🐰 Binary bits now flow with grace,
Through proxy paths at steady pace,
Headers dance where streams align,
From upstream down a perfect line!
Errors caught with callbacks' care,
Centralized solutions everywhere! ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'refactor: unify binary and html next proxies' accurately describes the main change: consolidating binary and HTML response proxying into shared helpers.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch refactor/pr15-next-binary-html-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 Next.js API layer by introducing a dedicated proxyBinary helper and migrating two previously hand-rolled backend fetch handlers to use the new or existing shared proxy utilities. The primary goal is to unify and simplify the API proxy contract, reducing redundant code and ensuring consistent, robust handling of various response types, including binary files and HTML pages, with well-defined error fallbacks. This completes the cleanup of ad-hoc backend fetch implementations, centralizing the proxy logic for improved maintainability and reliability.

Highlights

  • New proxyBinary Helper: Introduced a new proxyBinary helper function within backend-proxy.ts to streamline the handling of binary data streams, ensuring proper content-type and content-disposition header preservation for protected downloads.
  • Migration of /api/papers/export Route: Migrated the web/src/app/api/papers/export route to utilize the newly created proxyBinary helper, centralizing its backend proxy logic and maintaining its explicit JSON fallback for upstream API errors.
  • Migration of /api/newsletter/unsubscribe/[token] Route: Refactored the web/src/app/api/newsletter/unsubscribe/[token] route to use the existing proxyText helper, incorporating its explicit HTML fallback for errors, which includes proper escaping of error messages.
  • Enhanced Test Coverage: Extended unit tests for the backend proxy helpers to cover binary passthrough functionality and updated route-specific tests to validate the new helper integrations and their respective error fallback behaviors.

🧠 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
    • Imported the new proxyBinary function for testing.
    • Added a new test case to verify that proxyBinary correctly preserves binary download headers and handles authentication for protected exports.
  • web/src/app/api/_utils/backend-proxy.ts
    • Defined a new type BinaryProxyOptions to configure binary proxy behavior, including response headers.
    • Implemented the proxyBinary function, which fetches upstream binary data, sets Cache-Control to no-cache, and preserves Content-Type and Content-Disposition headers from the upstream response.
  • web/src/app/api/newsletter/unsubscribe/[token]/route.test.ts
    • Created a new test file to validate the newsletter unsubscribe route's integration with the proxyText helper.
    • Verified that the route correctly calls proxyText with the appropriate URL and options, including the responseContentType and the custom onError fallback for HTML responses.
  • web/src/app/api/newsletter/unsubscribe/[token]/route.ts
    • Refactored the GET handler to replace manual fetch logic with a call to the proxyText helper.
    • Configured proxyText with responseContentType: "text/html" and a custom onError callback that generates an HTML error page with properly escaped error details.
  • web/src/app/api/papers/export/route.test.ts
    • Updated the test file to mock proxyBinary instead of withBackendAuth and global.fetch.
    • Verified that the export route correctly calls proxyBinary and handles its JSON error fallback, ensuring the correct error details are returned.
  • web/src/app/api/papers/export/route.ts
    • Refactored the GET handler to replace manual fetch and header handling with a call to the new proxyBinary helper.
    • Configured proxyBinary with accept: "*/*", auth: true, and a custom onError callback that returns a JSON error response for upstream API unreachability.
Activity
  • No human activity has been recorded on this pull request yet.
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 is a great refactoring effort to unify the API proxy logic. By introducing a proxyBinary helper and migrating the paper export and newsletter unsubscribe routes to use the shared proxy helpers, the API layer becomes more consistent and maintainable. The changes are well-tested, and the new implementations are much cleaner. I have one minor suggestion regarding HTML escaping in the error handler for the newsletter unsubscribe route to make it more robust.

Comment on lines +18 to +22
const escaped = detail
.replace(/&/g, "&amp;")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;")
.replace(/"/g, "&quot;")

Choose a reason for hiding this comment

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

medium

The HTML escaping logic is incomplete as it doesn't handle single quotes ('). While the risk is low in this context, it's a good practice to perform complete HTML entity encoding for any data being embedded in an HTML response to prevent potential cross-site scripting (XSS) vulnerabilities, should the source of the error message change in the future. Please consider adding escaping for single quotes.

        const escaped = detail
          .replace(/&/g, "&amp;")
          .replace(/</g, "&lt;")
          .replace(/>/g, "&gt;")
          .replace(/"/g, "&quot;")
          .replace(/'/g, "&#39;")

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 the remaining Next.js API routes that used ad-hoc backend fetch logic (binary export + HTML unsubscribe) onto the shared backend proxy helper, completing the unified proxy contract work started in earlier PRs.

Changes:

  • Added proxyBinary() to the shared backend proxy utilities for authenticated binary downloads with Content-Type/Content-Disposition passthrough.
  • Migrated the papers export route to proxyBinary() while keeping the explicit 502 fallback payload.
  • Migrated the newsletter unsubscribe route to proxyText() with HTML fallback expressed via onError, and updated/added tests accordingly.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
web/src/app/api/papers/export/route.ts Switches export download to shared proxyBinary() with existing 502 fallback behavior.
web/src/app/api/papers/export/route.test.ts Updates route test to validate proxyBinary() wiring and fallback contract.
web/src/app/api/newsletter/unsubscribe/[token]/route.ts Switches unsubscribe HTML proxying to shared proxyText() with onError HTML fallback.
web/src/app/api/newsletter/unsubscribe/[token]/route.test.ts Adds route test validating proxying, encoding, and HTML fallback escaping.
web/src/app/api/_utils/backend-proxy.ts Introduces proxyBinary() helper for binary download proxying.
web/src/app/api/_utils/backend-proxy.test.ts Adds coverage for binary proxy header/auth passthrough.

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

`${apiBaseUrl()}/api/newsletter/unsubscribe/${encodeURIComponent(token)}`,
"GET",
{
responseContentType: "text/html",
Comment on lines +138 to +151
const body = await upstream.arrayBuffer()
const headers = new Headers(options.responseHeaders)
headers.set("Cache-Control", "no-cache")
headers.set(
"Content-Type",
upstream.headers.get("content-type") || "application/octet-stream",
)

const contentDisposition = upstream.headers.get("content-disposition")
if (contentDisposition) {
headers.set("Content-Disposition", contentDisposition)
}

return new Response(body, {
@jerry609 jerry609 force-pushed the refactor/pr15-next-binary-html-proxies branch from 95f77da to 4df2547 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 force-pushed the refactor/pr15-next-binary-html-proxies branch from 4df2547 to 0da4e6a Compare March 15, 2026 07:34
@jerry609 jerry609 force-pushed the refactor/pr15-next-binary-html-proxies branch from 0da4e6a to bd81642 Compare March 15, 2026 07:38
@jerry609 jerry609 changed the base branch from refactor/pr14-next-stream-proxies to dev March 15, 2026 07:42
@jerry609 jerry609 force-pushed the refactor/pr15-next-binary-html-proxies branch from bd81642 to 2608da1 Compare March 15, 2026 07:42
@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:48
@sonarqubecloud
Copy link

@jerry609 jerry609 merged commit 4007780 into dev Mar 15, 2026
18 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

Refactors the remaining Next.js API routes that used ad-hoc fetch proxying (binary export + HTML unsubscribe) to use the shared backend proxy helper, completing the unification work from prior proxy cleanup PRs.

Changes:

  • Added proxyBinary() to the shared backend proxy helper for streaming binary responses with Content-Type/Content-Disposition passthrough.
  • Migrated papers/export to proxyBinary() while keeping its explicit 502 Upstream API unreachable JSON fallback.
  • Migrated newsletter/unsubscribe to proxyText() and preserved the escaped-HTML 502 fallback via onError, plus added contract tests for the route wiring.

Reviewed changes

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

Show a summary per file
File Description
web/src/app/api/papers/export/route.ts Switches export download endpoint to shared proxyBinary() with custom 502 fallback.
web/src/app/api/papers/export/route.test.ts Removes the route-specific export proxy test (now covered via helper + contract tests).
web/src/app/api/newsletter/unsubscribe/[token]/route.ts Switches unsubscribe HTML endpoint to shared proxyText() with escaped HTML error fallback.
web/src/app/api/_utils/final-proxy-route-contracts.test.ts Adds contract tests asserting the routes call the shared proxy helpers and preserve fallback behavior.
web/src/app/api/_utils/backend-proxy.ts Introduces proxyBinary() implementation in the shared proxy layer.
web/src/app/api/_utils/backend-proxy.test.ts Adds unit coverage for binary passthrough + auth handling in proxyBinary().

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

Comment on lines +18 to +20
describe("final proxy route contracts", () => {
it("proxies protected exports through the shared binary helper", async () => {
proxyBinaryMock.mockResolvedValueOnce(new Response("bibtex-body"))
@jerry609 jerry609 deleted the refactor/pr15-next-binary-html-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