Skip to content

refactor(llc, ui)!: route the read and delivery receipts through the generated client - #3046

Draft
VelikovPetar wants to merge 6 commits into
refactor/flu-911_channel_lifecycle_openapi_migrationfrom
refactor/flu-923_read_receipts_openapi_migration
Draft

VelikovPetar wants to merge 6 commits into
refactor/flu-911_channel_lifecycle_openapi_migrationfrom
refactor/flu-923_read_receipts_openapi_migration

Conversation

@VelikovPetar

@VelikovPetar VelikovPetar commented Oct 6, 2026 •

Copy link
Copy Markdown
Contributor

Submit a pull request

Linear: FLU-923
Github Issue: -

CLA

  • I have signed the Stream CLA (required).
  • The code changes follow best practices
  • Code changes are tested (add some information if not applicable)

Description of the pull request

Moves marking channels and threads read and unread, and the delivery receipts, onto the OpenAPI-generated client.

  • StreamChatClient.markChannelRead, markThreadRead and markAllRead, and Channel.markRead and markThreadRead, return Result<MarkReadResponse> instead of throwing.
  • markChannelUnread, markChannelUnreadByTimestamp and markThreadUnread, and Channel.markUnread, markUnreadByTimestamp and markThreadUnread, return Result<void>.
  • markChannelsDelivered returns Result<MarkDeliveredResponse>. MarkChannelsDelivered, the callback ChannelDeliveryReporter takes, returns Future<Result<void>>; the reporter keeps the receipts on a failure, and still on a thrown error.
  • The Channel guards return a failure instead of throwing: a missing read-events capability, and a markUnread on a locally counted channel whose message isn't loaded. An uninitialized channel still throws a StateError.
  • On the local-unread path, Channel.markRead returns MarkReadResponse(duration: '0ms'), where it built an empty EmptyResponse.
  • MessageDelivery moves to models/request/ as a freezed class: no toJson, value equality, copyWith.
  • ChannelsRepository gains the four operations; channel_mapper.dart gains the envelope mappers and MessageDelivery.toRequest().
  • The seven methods are removed from StreamChatApi.channel.
  • MessageListUnreadController (internal) reads the Result to decide whether to retry a mark-read.
Generated Public
DefaultApi.markRead (POST /api/v2/chat/channels/{type}/{id}/read) StreamChatClient.markChannelRead, markThreadRead
DefaultApi.markUnread (POST /api/v2/chat/channels/{type}/{id}/unread) StreamChatClient.markChannelUnread, markChannelUnreadByTimestamp, markThreadUnread
DefaultApi.markChannelsRead (POST /api/v2/chat/channels/read) StreamChatClient.markAllRead
DefaultApi.markDelivered (POST /api/v2/chat/channels/delivered) StreamChatClient.markChannelsDelivered
MarkReadResponse / MarkDeliveredResponse same names (ours, freezed)
DurationResponse void
DeliveredMessagePayload MessageDelivery (kept)

Why

The calls take the API's envelopes rather than EmptyResponse, so a field the API adds later reaches callers without another break. The v2 routes are the same backend handlers as v1, and none is gated or in beta.

Notes for reviewers

  • MarkReadResponse carries only duration. The API's event holds a thread whose parentMessage is a MessageResponse, which needs the message mappers; it's dropped with a TODO and can be added later without a break.
  • The method names stay as in v10. Seven calls share four operations, so the spec's names can't tell most of them apart.
  • MarkChannelsDelivered is retyped (a break beyond the usual Result one): with the old Future<void> signature a failed Result would have read as success and dropped receipts that were never sent.
  • The generated requests send explicit nulls for the unused fields ({"message_id": null, "thread_id": "…"}); the server treats them as absent.

Testing

  • stream_chat analyze clean, full suite green (1,912 tests); every package and the sample app analyze clean. generate_plan.py --check reports 0 problems.
  • New client tests: client_mark_read_test.dart, client_mark_unread_test.dart, client_mark_all_read_test.dart and client_mark_channels_delivered_test.dart. The reporter tests cover a failed and a throwing callback.
  • stream_chat_flutter's message_list_view tests pass; the rest of its suite fails only on CI goldens run on macOS, identically on the base branch.
  • Live v1 vs v2 parity on the demo app, on throwaway channels deleted afterwards: all seven calls answer the same with the generated request bodies, and the real v2 responses (channel read, thread read, mark-all-read, delivered) decode.

Screenshots / Videos

Not applicable: no visible UI change.

🤖 Generated with Claude Code

…generated client

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Oct 6, 2026 •

Copy link
Copy Markdown
Contributor

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

VelikovPetar and others added 5 commits October 6, 2026 13:35
…back

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nto refactor/flu-923_read_receipts_openapi_migration

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nto refactor/flu-923_read_receipts_openapi_migration
…nto refactor/flu-923_read_receipts_openapi_migration

# Conflicts:
#	packages/stream_chat/lib/src/repository/channels_repository.dart
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

This branch has not been deployed

No deployments
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