Skip to content

refactor(fetch): centralize response copy state#47

Closed
medz wants to merge 3 commits into
mainfrom
refactor/response-copy-model
Closed

refactor(fetch): centralize response copy state#47
medz wants to merge 3 commits into
mainfrom
refactor/response-copy-model

Conversation

@medz

@medz medz commented Jun 22, 2026

Copy link
Copy Markdown
Owner

Summary

  • centralize copied response metadata and headers into an internal _ResponseSnapshot
  • route IO/JS native-backed response copies through one copy-source helper
  • keep web-backed copies on the browser Response construction path while passing a snapshot instead of scattered overlay parameters

Follow-up to #46.

Validation

  • dart analyze
  • dart test test/response_io_test.dart --reporter expanded
  • dart test -p chrome test/response_js_test.dart --reporter expanded
  • dart test -p chrome test/request_js_test.dart test/response_js_test.dart test/headers_js_test.dart test/url_search_params_js_test.dart test/_internal/web_fetch_utils_test.dart --reporter expanded
  • dart test --reporter expanded

Summary by CodeRabbit

  • Refactor
    • Internal restructuring of response metadata management to improve code organization and maintainability. No changes to end-user functionality.

@coderabbitai

coderabbitai Bot commented Jun 22, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@medz, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 14 minutes and 23 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits.

🚦 How do rate limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan refill rate.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, the refill rate gradually slows as usage increases. The highest same-day bursts are limited more strictly.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: f2ea0d81-227d-43a0-84bc-08b3a0a2492c

📥 Commits

Reviewing files that changed from the base of the PR and between bbda0a6 and 0cf98be.

📒 Files selected for processing (6)
  • lib/src/_internal/web_utils.dart
  • lib/src/fetch/headers.js.dart
  • lib/src/fetch/response.io.dart
  • lib/src/fetch/response.js.dart
  • test/response_io_test.dart
  • test/response_js_test.dart
📝 Walkthrough

Walkthrough

Both response.io.dart and response.js.dart are refactored to replace multiple nullable per-field metadata storage (_redirected, _status, _statusText, _type, _url) on Response with a new private _ResponseSnapshot class. All public getters, clone(), and native copy construction helpers are updated to derive values from the snapshot.

Changes

Response Metadata Consolidation into _ResponseSnapshot

Layer / File(s) Summary
_ResponseSnapshot type and Response._ constructor
lib/src/fetch/response.io.dart, lib/src/fetch/response.js.dart
Introduces _ResponseSnapshot with from/fromWeb factory constructors that merge a native response's metadata with optional ResponseInit overrides (headers, status, statusText, type, url, redirected). Response._ is updated to accept an optional _snapshot instead of separate nullable fields.
Public getters updated to prefer snapshot values
lib/src/fetch/response.io.dart, lib/src/fetch/response.js.dart
All public metadata getters (ok, redirected, status, statusText, type, url, headers) in both files now short-circuit from _snapshot when set. The headers getter lazily initializes _headers from _snapshot?.headers. The JS file's factory web.Response branch now builds a _ResponseSnapshot via _ResponseSnapshot.fromWeb(...).
clone() and native copy helpers refactored to snapshot
lib/src/fetch/response.io.dart, lib/src/fetch/response.js.dart
clone() computes a _ResponseSnapshot and passes it into the Response._ constructor for all clone paths. _responseFromWrappedResponse, _responseFromNativeCopySource, and _nativeResponseFromCopy are reorganized to be snapshot-driven. A new _shouldPreserveMissingContentType(init, snapshot) helper replaces the prior direct header inspection for content-type preservation.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • medz/ht#46: Refactors the same Response wrapped/native construction and copying paths in response.io.dart and response.js.dart, directly preceding the consolidation into _ResponseSnapshot in this PR.

Poem

🐇 Hopping through the metadata maze,
I gathered scattered fields with care,
One _snapshot now holds the gaze —
status, headers, type laid bare.
No more nullable fields astray,
this bunny tidied up today!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title accurately describes the main refactoring: centralizing response state through a new _ResponseSnapshot object across multiple Response implementations.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch refactor/response-copy-model

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.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: bbda0a6748

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread lib/src/fetch/response.io.dart Outdated
Comment thread lib/src/fetch/response.js.dart Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
lib/src/fetch/response.js.dart (1)

163-166: 🧹 Nitpick | 🔵 Trivial | 💤 Low value

Consider using HttpStatus.isSuccess for consistency with response.io.dart.

The IO version uses HttpStatus.isSuccess(snapshot.status) while this JS version uses an inline range check. Both are functionally equivalent for the standard 200-299 success range, but using the same helper improves maintainability.

♻️ Optional: align with IO version
   if (snapshot != null) {
-    return snapshot.status >= 200 && snapshot.status <= 299;
+    return HttpStatus.isSuccess(snapshot.status);
   }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/src/fetch/response.js.dart` around lines 163 - 166, Replace the inline
range check for HTTP success status in response.js.dart with the
HttpStatus.isSuccess helper method for consistency with the IO version.
Specifically, in the code block where snapshot.status is compared against the
200-299 range, change the condition to use HttpStatus.isSuccess(snapshot.status)
instead of the inline range check snapshot.status >= 200 && snapshot.status <=
299. This ensures both the JS and IO implementations use the same helper method
for determining successful HTTP responses.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@lib/src/fetch/response.js.dart`:
- Around line 163-166: Replace the inline range check for HTTP success status in
response.js.dart with the HttpStatus.isSuccess helper method for consistency
with the IO version. Specifically, in the code block where snapshot.status is
compared against the 200-299 range, change the condition to use
HttpStatus.isSuccess(snapshot.status) instead of the inline range check
snapshot.status >= 200 && snapshot.status <= 299. This ensures both the JS and
IO implementations use the same helper method for determining successful HTTP
responses.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 34b07c1f-5c9a-41ff-a4b7-fe1b6448e56d

📥 Commits

Reviewing files that changed from the base of the PR and between 530f6cc and bbda0a6.

📒 Files selected for processing (2)
  • lib/src/fetch/response.io.dart
  • lib/src/fetch/response.js.dart

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 143183ce06

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread lib/src/fetch/response.js.dart Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0cf98bed0c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +131 to +133
final WebResponseHost host => js_headers.headersFromHost(
host.value.headers,
),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Avoid exposing immutable web host headers

For WebResponseHost values that are direct wrappers around browser-owned responses, such as Response(await window.fetch(...)), Response.error(), or Response.redirect(...), host.value.headers can have the Fetch API's immutable guard. Returning a wrapper around that host means response.headers.set(...) or delete(...) now throws a DOM TypeError; before this getter copied the host headers into a mutable Headers, matching the package's native response behavior. The host-bound wrapper should be limited to copied/constructed web responses whose parsing methods need to observe later header mutations, rather than all raw web hosts.

Useful? React with 👍 / 👎.

@medz medz closed this Jun 22, 2026
@medz medz deleted the refactor/response-copy-model branch June 22, 2026 13:55
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.

1 participant