Skip to content

feat(webhooks): add normalized message_edit event - #27

Merged
jobasfernandes merged 8 commits into
w3nder:mainfrom
jobasfernandes:feat/message-edit-event
Jun 7, 2026
Merged

jobasfernandes merged 8 commits into
w3nder:mainfrom
jobasfernandes:feat/message-edit-event

Conversation

@jobasfernandes

@jobasfernandes jobasfernandes commented Jun 6, 2026 •

Copy link
Copy Markdown
Collaborator

Resumo

Adiciona o evento normalizado message_edit (id da mensagem original + novo conteúdo), entregue por webhook e SSE de forma idêntica nas engines baileys e zapo (issue #8). 8 commits, ~11 arquivos.

Closes #8. A forma (edição pelo app mobile, secretEncryptedMessage) não entra nesta entrega e fica rastreada em #26.

Backend

  • @multi-wa/types: novo messageEditEventSchema na união engineEventSchema e message_edit no webhookEventTypeSchema.
  • engine-baileys: detecta a edição clássica (protocolMessage tipo MESSAGE_EDIT) no messages.upsert e emite message_edit (isBaileysEditUpsert + mapBaileysEdit).
  • engine-zapo: emite message_edit da edição clássica (protocolMessage no evento message) e do addon message_edit decifrado.
  • OpenAPI: message_edit no WEBHOOK_DELIVERY_SCHEMA, com exemplos (1:1 e grupo) e descrição.

Bug fixes / limpeza

  • Suprime protocolMessage que não é edição (revoke, ephemeral, peer-data, sync), que antes vazava como message com content: { type: 'unknown', kind: 'protocolMessage' }, nas duas engines (isBaileysProtocolMessage / isZapoProtocolMessage).
  • Reverte uma persistência de messageSecret no zapo que se mostrou inócua (a lib só persiste o secret de poll/event/bot - ver gap abaixo).

Gap conhecido - forma (edição pelo app mobile)

A edição feita pelo celular chega como addon criptografado (secretEncryptedMessage), que exige o messageSecret da mensagem original. Esse caminho fica não suportado de forma confiável nas duas engines, por limitação das libs:

  • zapo: persiste o messageSecret apenas de poll/event/bot, nunca de texto; a única fonte seria o messages mailbox (sem TTL, cresce sem limite). Limitação da lib (vinikjkkj/zapo#159).
  • baileys: a versão atual (7.0.0-rc13) não decifra secretEncryptedMessage. Há PRs abertos no upstream (WhiskeySockets/Baileys #2554 / #2547) que adicionam o decrypt nativo; a ideia é adotar quando saírem em release e configurar getMessage.

A forma (edição via WhatsApp Web/Desktop, conteúdo em claro) funciona normalmente nas duas engines.

Plano de teste

  • pnpm lint termina sem warnings
  • pnpm typecheck passa
  • pnpm build passa
  • TEST_DATABASE_URL=... pnpm test:coverage passa (211 testes, thresholds de cobertura ok)
  • Editar uma mensagem pelo WhatsApp Web e verificar o evento message_edit (id da original + novo texto) chegando no SSE/webhook, nas duas engines
  • Confirmar que protocolMessage que não é edição não gera mais evento message com content unknown

Summary by CodeRabbit

  • New Features
    • Added message edit support across all messaging engines, allowing users to edit previously sent messages
    • Message edits are now captured and reported through webhook events for real-time notifications
    • Extended webhooks to support message_edit event type for integrations

@coderabbitai

coderabbitai Bot commented Jun 6, 2026 •

Copy link
Copy Markdown

Lost in the diff? Review this PR in Change Stack to follow the change map from intent to exact ranges.

Review Change Stack

📝 Walkthrough

Walkthrough

This PR implements end-to-end support for WhatsApp message edit events. A new normalized message_edit event type is defined with message identity and edited content. Baileys and Zapo engines independently detect edits from protocol messages/addons, map them to the shared schema, and emit through their handlers. The webhook delivery schema and OpenAPI documentation are extended with the new event type and examples.

Changes

Message Edit Event Support

Layer / File(s) Summary
Message Edit Event Schema and Types
packages/types/src/engine.ts, packages/types/src/webhook.ts, packages/types/src/schemas.test.ts
New messageEditEventSchema defines the normalized event with message identity fields (id, chat, from, fromMe, isGroup, participant/fromAlt), optional timestamp/mentions, and normalized content reusing the inbound schema. Schema is added to the engine event discriminated union, webhook event type enum is updated, and validation tests confirm acceptance of valid/invalid message_edit payloads.
Baileys Edit Detection and Mapping
packages/engine-baileys/src/events.ts
Three exported helpers support Baileys edits: isBaileysEditUpsert detects edit protocol messages, isBaileysProtocolMessage identifies protocol messages for filtering, and mapBaileysEdit converts edit protocols to normalized MessageEditEvent with timestamp derivation from protocolMessage.timestampMs and content/context mapping from the edited message.
Baileys Engine Wiring and Tests
packages/engine-baileys/src/engine.ts, packages/engine-baileys/src/events.test.ts
The messages.upsert handler branches on isBaileysEditUpsert, emits the mapped event, and skips further processing. Test suite verifies edit detection, validates content normalization for group and direct self-edits, confirms protocol message suppression via isBaileysProtocolMessage, and ensures plain/empty inputs are rejected.
Zapo Edit Detection and Mapping
packages/engine-zapo/src/events.ts
Five exported helpers support Zapo edits: isZapoAddonEnvelope and isZapoProtocolMessage filter encrypted/protocol envelopes, isZapoEditMessage detects edit messages, mapZapoEditFromMessage converts protocol edits to events (with timestamp from timestampMs), and mapZapoEditFromAddon maps decrypted addon edits, both extracting chat/author/participant and normalizing content via existing mappers.
Zapo Engine Wiring and Tests
packages/engine-zapo/src/engine.ts, packages/engine-zapo/src/events.test.ts
The message handler filters addon envelopes and protocol messages while detecting emitable edits; the message_addon handler attempts edit extraction and returns early on success. Test suite validates addon-to-edit mapping, confirms non-edit addon behavior, verifies envelope suppression of encrypted messages, and tests protocol edit detection with correct timestamp/content handling.
OpenAPI Webhook Delivery Schema
apps/api/src/http/openapi.ts
The WEBHOOK_DELIVERY_SCHEMA union gains a message_edit variant specifying required id (original message), normalized content, and sender/chat metadata. New example payloads (message_edit_direct, message_edit_group) demonstrate direct and group edit delivery shapes. Webhook endpoint description documents message_edit semantics including the original id, new content, and fromMe flag.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related issues

  • #24: Both modify Baileys/Zapo engine message handlers and introduce/refine protocol-message suppression logic alongside new edit-detection branches, sharing the same handler-level filtering concerns.
  • #7: Both extend the engine event schemas and webhook/OpenAPI payloads to add new normalized events; the message_edit changes align with requested schema/OpenAPI extensions.

Possibly related PRs

  • w3nder/multi-wa-api#2: Lays down the shared webhook delivery/event schemas in apps/api/src/http/openapi.ts and packages/types/src/webhook.ts that this PR directly extends with message_edit support.

Suggested reviewers

  • w3nder

Poem

🐰 A message changed, and now it gleams,
Edits flow through engine seams,
From Baileys to Zapo in sync,
Normalized schemas bring the link,
Webhooks dance with the edit's grace! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 8.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: introducing a normalized message_edit event for webhooks.
Linked Issues check ✅ Passed All requirements from issue #8 are met: normalized message_edit event with id/chat/from/isGroup/participant/timestamp/content fields, mappers for baileys and zapo engines, OpenAPI documentation, and test coverage.
Out of Scope Changes check ✅ Passed All changes are directly related to implementing message_edit event support. Suppression of non-edit protocol messages is a necessary supporting change to prevent unintended content leakage.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@coderabbitai coderabbitai 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.

🧹 Nitpick comments (1)
packages/engine-zapo/src/events.ts (1)

305-305: 💤 Low value

Consider a more defensive fallback for missing message id.

The fallback chain pm?.key?.id ?? event.key.id ?? '' defaults to an empty string if both sources are missing. While rare, an empty string might not be a valid message identifier for downstream consumers (e.g., webhook delivery, client-side message tracking).

Consider throwing an error or logging a warning if both id sources are missing, or document this edge case behavior.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/engine-zapo/src/events.ts` at line 305, The id assignment uses
pm?.key?.id ?? event.key.id ?? '' which can silently produce an invalid empty
id; update the logic around where id is set (the object using pm, event, and
key) to defensively handle missing ids: explicitly check pm?.key?.id and
event.key.id and if both are absent either throw a descriptive Error or emit a
warning via the existing logger (e.g., processLogger.warn) and abort/skip
creating the message, ensuring downstream consumers never receive an empty
string id; reference the pm, event, and key variables and the id property when
implementing this change.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@packages/engine-zapo/src/events.ts`:
- Line 305: The id assignment uses pm?.key?.id ?? event.key.id ?? '' which can
silently produce an invalid empty id; update the logic around where id is set
(the object using pm, event, and key) to defensively handle missing ids:
explicitly check pm?.key?.id and event.key.id and if both are absent either
throw a descriptive Error or emit a warning via the existing logger (e.g.,
processLogger.warn) and abort/skip creating the message, ensuring downstream
consumers never receive an empty string id; reference the pm, event, and key
variables and the id property when implementing this change.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 88e28ee0-ea9d-4160-9c42-1a3eac48411d

📥 Commits

Reviewing files that changed from the base of the PR and between 2408fdb and 117f023.

📒 Files selected for processing (10)
  • apps/api/src/http/openapi.ts
  • packages/engine-baileys/src/engine.ts
  • packages/engine-baileys/src/events.test.ts
  • packages/engine-baileys/src/events.ts
  • packages/engine-zapo/src/engine.ts
  • packages/engine-zapo/src/events.test.ts
  • packages/engine-zapo/src/events.ts
  • packages/types/src/engine.ts
  • packages/types/src/schemas.test.ts
  • packages/types/src/webhook.ts

@jobasfernandes

jobasfernandes commented Jun 6, 2026 •

Copy link
Copy Markdown
Collaborator Author

Sobre o ponto do events.ts (o id que poderia ficar vazio): na prática isso não acontece. Esse trecho só roda quando a mensagem é mesmo uma edição, e toda edição já traz o id da mensagem original. O ?? '' no final é só uma garantia de formato que nunca chega a ser usada.

@jobasfernandes
jobasfernandes merged commit 8b9727f into w3nder:main Jun 7, 2026
2 checks passed
@jobasfernandes
jobasfernandes deleted the feat/message-edit-event branch June 7, 2026 15:36
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.

feat(webhooks): evento de mensagem editada

1 participant