Skip to content

refactor(fetch): make Body extend Blob#51

Merged
medz merged 2 commits into
mainfrom
refactor/body-blob-stream
Jun 23, 2026
Merged

refactor(fetch): make Body extend Blob#51
medz merged 2 commits into
mainfrom
refactor/body-blob-stream

Conversation

@medz

@medz medz commented Jun 23, 2026

Copy link
Copy Markdown
Owner

Type

Refactor

Summary

  • Make Body extend the conditional platform Blob implementation and implement Stream<Uint8List> directly.
  • Simplify Body construction by delegating Blob-compatible inputs to Blob, while keeping Body, FormData, and stream-specific handling in Body.
  • Preserve Fetch body helpers and bodyUsed semantics, and update public surface coverage for the new inheritance shape.

Notes

Validation

  • dart format --output=none --set-exit-if-changed .
  • dart analyze
  • dart test -p vm -p node -p chrome

Closes #50

Summary by CodeRabbit

Release Notes

  • Breaking Changes

    • Body.stream is now a method with an optional chunkSize parameter; use body.stream() instead of body.stream.
    • Body.size may throw UnsupportedError for stream-backed bodies with unknown length.
    • Body now extends Blob and implements Stream<Uint8List>.
  • Documentation

    • Updated changelog documenting breaking changes to the Body API and interface hierarchy.

@medz medz added the enhancement New feature or request label Jun 23, 2026
@coderabbitai

coderabbitai Bot commented Jun 23, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: a0d7c5ce-0fb5-4252-aaa7-54f2763b523a

📥 Commits

Reviewing files that changed from the base of the PR and between 0546d13 and 8349abd.

📒 Files selected for processing (4)
  • CHANGELOG.md
  • lib/src/fetch/body.dart
  • test/body_test.dart
  • test/public_api_surface_test.dart

📝 Walkthrough

Walkthrough

Body is refactored from a block.Block-backed Stream<Uint8List> to a class that extends the platform Blob implementation and directly implements Stream<Uint8List>. Internal storage is replaced with blobParts/_streamHost/_streamSize, the stream getter becomes a chunked method, and all read/clone/slice paths are updated. Tests and the public API surface test are extended to cover the new shape, and a BREAKING entry is added to the changelog.

Changes

Body extends Blob + Stream refactor

Layer / File(s) Summary
Body class shape, storage model, and read methods
lib/src/fetch/body.dart
Changes Body to extends Blob with Stream<Uint8List> implements Stream<Uint8List>, rewrites storage to blobParts + _streamHost/_streamSize, overrides size (throws for unknown-length stream-backed bodies), converts stream getter to a chunked method with chunkSize validation, and updates bytes()/arrayBuffer() to route through _readStream or super.arrayBuffer().
blob(), clone(), slice(), and listen()
lib/src/fetch/body.dart
blob() uses super.slice(...) for blobParts-backed bodies and materializes stream-backed ones via bytes(); clone() uses streamTee for stream-backed or super.slice(...) for blobParts-backed; slice(...) throws UnsupportedError for stream-backed; listen(...) calls stream() instead of the removed getter.
Static normalization helpers
lib/src/fetch/body.dart
Adds _fromBlobInit, _fromFormData, _fromStream, _readStream, and _blobInitType static helpers, replacing prior inline construction and stream materialization.
Tests, public API surface, and changelog
test/body_test.dart, test/public_api_surface_test.dart, CHANGELOG.md
Adds _ThrowingReadBlob test double; covers Body as Blob/Stream<Uint8List>, snapshot semantics, no source read-method invocations, stream-backed size/slice rejection, chunkSize validation, chunk copy-on-consume, and updated stream access; extends public API surface test with type checks; documents breaking change.

Sequence Diagram(s)

sequenceDiagram
    participant Caller
    participant Body
    participant Blob
    participant StreamHost

    Note over Caller,StreamHost: Blob-backed read path
    Caller->>Body: arrayBuffer()
    Body->>Blob: super.arrayBuffer()
    Blob-->>Body: ByteBuffer
    Body-->>Caller: ByteBuffer

    Note over Caller,StreamHost: Stream-backed read path
    Caller->>Body: arrayBuffer()
    Body->>StreamHost: _readStream(_streamHost)
    StreamHost-->>Body: accumulated Uint8List chunks
    Body-->>Caller: ByteBuffer

    Note over Caller,StreamHost: clone() on stream-backed body
    Caller->>Body: clone()
    Body->>Body: streamTee(_streamHost)
    Body-->>Body: update _streamHost with tee[0]
    Body-->>Caller: new Body with tee[1] as _streamHost
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related issues

Possibly related PRs

  • medz/ht#12: This PR's clone() rewrite for stream-backed bodies uses the streamTee helper introduced in PR #12, making the connection direct.
  • medz/ht#45: This PR delegates Body.slice(...) and blob() to super.slice(...) via Blob internals, which depend on the MIME-type normalization and slice contentType handling introduced in PR #45.
  • medz/ht#54: This PR's Body delegates read behavior to Blob internals, and PR #54 changes Blob part normalization and snapshot/defensive-copy semantics that Body now relies on.

Poem

🐇 Hoppity-hop through the byte stream I go,
extends Blob now, what a delightful show!
No more old getter, just stream() with a size,
streamTee for cloning — oh, how very wise.
Each chunk is a copy, safe in my paw,
The Body is Blob — the best change I saw! 🎉

🚥 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 title directly summarizes the main change: refactoring Body to extend the Blob class, which is the primary focus of this PR.
Linked Issues check ✅ Passed The PR fulfills all acceptance criteria from issue #50: Body extends platform Blob, implements Stream, exposes Blob-compatible surface, preserves bodyUsed semantics, and includes comprehensive test coverage.
Out of Scope Changes check ✅ Passed All changes are scoped to the Body refactoring: CHANGELOG documents the breaking change, body.dart implements the new structure, and tests validate both inherited Blob behavior and stream functionality.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ 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/body-blob-stream

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.

@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: f7a57bf979

ℹ️ 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/body.dart
@medz medz force-pushed the refactor/body-blob-stream branch from f7a57bf to 8349abd Compare June 23, 2026 08:36

@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: 8349abd386

ℹ️ 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/body.dart
final URLSearchParams _ => _urlEncodedUtf8,
final Blob blob => blob.type,
final block.Block blockHost => blockHost.type,
_ => '',

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 Preserve native Blob content types

When users pass a native web.Blob or web.File directly as BodyInit on the web target, Blob now accepts and reads that host-backed part, but this fallback leaves the type as '', so Body(web.Blob(...type: 'text/plain')).contentType is null. Request/Response only auto-populate the content-type header from body.contentType, so these accepted native Blob/File bodies lose their MIME type even though package Blob bodies still preserve it; please extract the host Blob/File type when delegating these inputs.

Useful? React with 👍 / 👎.

@medz medz merged commit 3495187 into main Jun 23, 2026
2 checks passed
@medz medz deleted the refactor/body-blob-stream branch June 23, 2026 08:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

refactor(fetch): make Body extend platform Blob and implement Stream

1 participant