feat: delivery pipeline — validate, persist, resolve devices, push envelopes (#194)#272
Merged
codebestia merged 3 commits intoJun 29, 2026
Merged
Conversation
Adds a single code path all messages take after persist:
1. Re-validates members against conversation_members (not room state).
2. Resolves active (non-revoked) devices for every member.
3. Loads persisted envelopes from the database.
4. Emits message_envelope to device:{id} room with each device's ciphertext.
5. Emits new_message to the conversation room as a UI notification.
Each socket joins its device:{deviceId} room on connect, so the Redis
adapter routes per-device emissions correctly across instances.
Persist-before-deliver is enforced: deliverMessage is called only after
the message row and all envelope rows have been committed.
|
@Tijesunimi004 Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits. You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀 |
Owner
|
@Tijesunimi004 |
codebestia
approved these changes
Jun 29, 2026
codebestia
left a comment
Owner
There was a problem hiding this comment.
LGTM!
Thank you for your contribution.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #194
What
Implements the delivery pipeline described in #194 as the single path all messages take after being stored.
Changes
src/services/deliveryPipeline.ts(new)Encapsulates the full post-persist delivery flow:
conversation_members— membership is re-validated against the DB, not inferred from Socket.IO room occupancy.revokedAt IS NULL).message_envelopetodevice:{deviceId}for each device that has an envelope — each device receives exactly its own ciphertext.new_messageto the conversation room as a stripped notification (no ciphertext) so clients update unread counts and UI.src/index.tsSockets now join
device:{deviceId}on connect, enabling per-device targeting viaio.to('device:...'). This works across horizontally-scaled instances because the Redis adapter routes room emissions through pub/sub.src/socket/messaging.tsReplaces the single
io.to(conversationId).emit('new_message', message)call withawait deliverMessage(io, message, conversationId). The message and all envelopes are committed to the database before this call — persist-before-deliver is guaranteed by control flow.src/__tests__/deliveryPipeline.test.ts(new)Unit tests covering:
new_messageroom notification without ciphertextAcceptance criteria
deliverMessageis called only afterdb.insertfor bothmessagesandmessageEnvelopescompletes.device:{deviceId}, not to the conversation room.conversation_memberseven when rooms are used: step 1 ofdeliverMessagequeries the table directly.