Skip to content

feat(webhook): dispatch message.reaction events (WebSocket/webhook parity)#380

Merged
rmyndharis merged 1 commit into
mainfrom
feat/webhook-message-reaction-event
Jun 20, 2026
Merged

feat(webhook): dispatch message.reaction events (WebSocket/webhook parity)#380
rmyndharis merged 1 commit into
mainfrom
feat/webhook-message-reaction-event

Conversation

@rmyndharis

Copy link
Copy Markdown
Owner

What

Message reactions were broadcast over WebSocket only — a webhook-only consumer could never observe reactions, an undocumented asymmetry (message.reaction was a subscribable WS event but not a webhook event).

Change

  • Register message.reaction in WEBHOOK_EVENTS (among the dispatched events) and expose it in the dashboard event picker.
  • Dispatch it from SessionService.applyReaction, alongside the existing WebSocket emit, with the same payload ({ messageId, chatId, reaction, senderId, reactions }, where reactions is the post-apply snapshot). Dispatch is fire-and-forget and happens only after the reaction is persisted.
  • Add a dedicated idempotency-key case.

Idempotency

A reaction carries no unique id and is a read-modify-write of the message's reactions map — the same sender can re-apply the same emoji over time (👍 → remove → 👍). Keying on (sender, message) alone would collapse a genuine re-reaction onto the earlier one. The key is therefore salted with the per-dispatch occurredAt (captured once, reused across retries) — the same mechanism the recurring session.* lifecycle events use: distinct occurrences get distinct keys while retries of one delivery stay stable.

⚠️ Consumer-visible

Webhooks subscribed with the wildcard '*' will begin receiving message.reaction deliveries. Existing semantics for all other events are unchanged.

Tests

  • idempotency.util.spec.ts: salt distinctness (re-reaction is a distinct event), retry-stability, two-sender distinctness.
  • session.service.spec.ts: a reaction now dispatches message.reaction with the post-apply reactions snapshot.
  • Backend lint + build + full jest (980) green; dashboard build + lint green. API spec updated.

…rity)

Reactions were broadcast over WebSocket only, so a webhook-only consumer
could not observe them. Dispatch message.reaction alongside the WS emit with
the same payload (the reaction event plus the post-apply reactions snapshot),
register it in WEBHOOK_EVENTS, and expose it in the dashboard event picker.

Reactions carry no unique id and are a read-modify-write (a sender can
re-apply the same emoji over time), so the idempotency key is salted with the
per-dispatch occurredAt — distinct occurrences get distinct keys while retries
of the same delivery stay stable. Wildcard ('*') subscribers will begin
receiving this event.
@rmyndharis rmyndharis merged commit c7759e8 into main Jun 20, 2026
5 checks passed
@rmyndharis rmyndharis deleted the feat/webhook-message-reaction-event branch June 20, 2026 15:20
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