Skip to content

feat: migrate sendMessage + getReadReceipts callers to REST#40675

Draft
ggazzo wants to merge 1 commit into
developfrom
chore/ddp-sendmsg-readreceipts-fix
Draft

feat: migrate sendMessage + getReadReceipts callers to REST#40675
ggazzo wants to merge 1 commit into
developfrom
chore/ddp-sendmsg-readreceipts-fix

Conversation

@ggazzo
Copy link
Copy Markdown
Member

@ggazzo ggazzo commented May 25, 2026

Summary

The two DDP methods that were reverted from #40659 because their client plumbing depends on DDP-specific semantics. This PR contains the deeper refactor each needed.

sendMessage

  • sdk.call('sendMessage', message, previewUrls)sdk.rest.post('/v1/chat.sendMessage', { message, previewUrls }).
  • Primary send flow (apps/meteor/client/lib/chats/flows/sendMessage.ts) feeds the server-rendered { message } back into Messages.state via mapMessageFromApi, replacing the optimistic temp record in the same tick the REST call resolves. Reproduces the Minimongo replication the DDP method triggered.
  • The seven fire-and-forget callsites are straight URL swaps:
    • apps/meteor/client/hooks/notification/useNotification.ts (desktop notification reply)
    • apps/meteor/client/apps/gameCenter/GameCenterInvitePlayersModal.tsx
    • 5 asciiart slashcommands

getReadReceipts

  • useMethod('getReadReceipts')useEndpoint('GET', '/v1/chat.getMessageReadReceipts') in ReadReceiptsModal.
  • Dialog now takes a rid prop and subscribes to notify-room/<rid>/messagesRead; on event, invalidates the ['read-receipts', messageId] react-query so the dialog refetches when new receipts land.
  • mapReadReceiptFromApi helper revives the Date fields the REST endpoint serializes as strings.

Server-side race fix

ReadReceipt.markMessagesAsRead, markMessageAsReadBySender and storeThreadMessagesReadReceipts no longer fire-and-forget the inner storeReadReceipts(...) call — they await it. Closes the read-after-write race that the omnichannel-livechat-read-receipts e2e exposed.

Test plan

  • Quote a message with attachment in a channel; confirm the blockquote appears in the sent message and the composer's quote preview unmounts.
  • Same flow inside a thread.
  • Edit a message after sending.
  • Run the asciiart slash commands.
  • Reply from a desktop notification.
  • Livechat: visitor sends a message; agent opens the chat; agent inspects "Read receipts" — expects two entries (visitor + agent).
  • CI: `omnichannel-livechat-read-receipts.spec.ts:53` passes.
  • CI: `quote-attachment.spec.ts:29` passes.

@dionisio-bot
Copy link
Copy Markdown
Contributor

dionisio-bot Bot commented May 25, 2026

Looks like this PR is not ready to merge, because of the following issues:

  • This PR is missing the 'stat: QA assured' label
  • This PR is missing the required milestone or project

Please fix the issues and try again

If you have any trouble, please check the PR guidelines

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented May 25, 2026

⚠️ No Changeset found

Latest commit: a8c6aa9

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 25, 2026

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 86f79f6e-dfe5-4c3c-a699-091f24310da8

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

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.

@codecov
Copy link
Copy Markdown

codecov Bot commented May 25, 2026

Codecov Report

❌ Patch coverage is 26.08696% with 17 lines in your changes missing coverage. Please review.
✅ Project coverage is 69.60%. Comparing base (82aad55) to head (a8c6aa9).

Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff             @@
##           develop   #40675      +/-   ##
===========================================
- Coverage    69.63%   69.60%   -0.04%     
===========================================
  Files         3338     3339       +1     
  Lines       123289   123303      +14     
  Branches     22005    21966      -39     
===========================================
- Hits         85850    85821      -29     
- Misses       34073    34117      +44     
+ Partials      3366     3365       -1     
Flag Coverage Δ
unit 70.43% <26.08%> (-0.06%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Two methods that resisted the URL-swap pass in the wider DDP -> REST
migration. This PR contains the deeper refactor each needed.

sendMessage
  Replace sdk.call('sendMessage', message, previewUrls) with
  sdk.rest.post('/v1/chat.sendMessage', { message, previewUrls }).
  In the primary send flow (apps/meteor/client/lib/chats/flows/sendMessage.ts)
  the response's server-rendered { message } is fed back into
  Messages.state via mapMessageFromApi, replacing the optimistic temp
  record in the same tick the REST call resolves. That reproduces the
  Minimongo replication the DDP method triggered — composer quote
  previews unmount, attachment renderers see attachments[] and urls[],
  message _updatedAt advances — all without waiting for the
  room-messages stream event to arrive separately.

  The seven fire-and-forget callsites do not run the optimistic
  reconcile and are straight URL swaps:
    - apps/meteor/client/hooks/notification/useNotification.ts
    - apps/meteor/client/apps/gameCenter/GameCenterInvitePlayersModal.tsx
    - apps/meteor/app/slashcommand-asciiarts/client/{lenny,tableflip,unflip,gimme,shrug}.ts

getReadReceipts
  Replace useMethod('getReadReceipts') with
  useEndpoint('GET', '/v1/chat.getMessageReadReceipts') in
  ReadReceiptsModal. Add rid prop and subscribe to
  notify-room/<rid>/messagesRead; on event, invalidate the
  ['read-receipts', messageId] query so the dialog re-fetches when new
  receipts land. mapReadReceiptFromApi revives the Date fields the
  REST endpoint serializes as strings.

Server-side: ReadReceipt.markMessagesAsRead /
ReadReceipt.markMessageAsReadBySender /
ReadReceipt.storeThreadMessagesReadReceipts no longer fire-and-forget
the storeReadReceipts insertion — they await it. Closes the
read-after-write race the omnichannel-livechat-read-receipts e2e test
exposed: a fast REST GET could observe a partial set of receipts
because the visitor's self-receipt insert was still in flight when the
test opened the Read-Receipts dialog.
@ggazzo ggazzo force-pushed the chore/ddp-sendmsg-readreceipts-fix branch from 274ea6b to a8c6aa9 Compare May 27, 2026 15:02
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