Skip to content

feat(webhooks): normalize call, group and membership events - #23

Merged
jobasfernandes merged 10 commits into
w3nder:mainfrom
jobasfernandes:feat/normalize-more-events
Jun 5, 2026
Merged

jobasfernandes merged 10 commits into
w3nder:mainfrom
jobasfernandes:feat/normalize-more-events

Conversation

@jobasfernandes

@jobasfernandes jobasfernandes commented Jun 4, 2026 •

Copy link
Copy Markdown
Collaborator

Resumo

Normaliza 4 novos eventos no contrato engine-agnostico EngineEvent, identicos entre as engines baileys e zapo: call, group_participants, group_update e membership_request. Inclui o enderecamento alternativo lid<->pn (fromAlt/authorAlt/participantAlt) nesses eventos, espelhando o fromAlt das mensagens (#19). 6 commits.

Closes #7.

Contrato (@multi-wa/types)

  • Novos membros da uniao EngineEvent: callEventSchema, groupParticipantsEventSchema, groupUpdateEventSchema, membershipRequestEventSchema (reusa participantActionSchema).
  • call.status: offer|accept|reject|terminate (intersecao neutra; "perdida" = offer sem accept seguido de terminate).
  • membership_request.action: created|revoked (ambas engines) + rejected (so-baileys).
  • Campos *Alt opcionais (lid<->pn) nos jids principais.
  • webhookEventTypeSchema estendido com os 4 tipos.

Engines

  • engine-baileys: mappers mapBaileysCall/mapBaileysGroupParticipants/mapBaileysGroupUpdate/mapBaileysMembershipRequest + listeners (call, group-participants.update, groups.update, group.join-request). *Alt via callerPn/authorPn/participantPn.
  • engine-zapo: mapZapoCall + roteador mapZapoGroup (despacha o evento unico group por action, com fan-out de membership) + listeners (call, group). fromAlt do call via senderLidJid/callCreatorJid; participantAlt via phoneJid.

API / OpenAPI

  • WebhookDelivery: 4 branches novos no oneOf + exemplos + descricao (incl. nota lid<->pn).

Fora de escopo

  • newsletter e business adiados (sem paridade entre engines).
  • Resolucao lid<->pn por-membro na lista participants do group_participants.

Plano de teste

  • pnpm lint, pnpm typecheck, pnpm build e pnpm test:all terminam zerados (188 testes).
  • Mappers cobertos por unidade nas duas engines (events.test.ts) e o contrato em schemas.test.ts.
  • Validacao manual via SSE: ligar para uma sessao conectada emite call (offer/accept/reject/terminate); add/remove/promote/demote emite group_participants; mudanca de assunto/descricao/announce/restrict/ephemeral emite group_update; solicitacao de entrada emite membership_request.

Summary by CodeRabbit

  • New Features

    • Webhooks now support four additional event types: call, group_participants, group_update, and membership_request. Apps will receive notifications for incoming calls, participant changes, group metadata updates (partial-patch semantics), and membership requests; alternate addressing fields are exposed when available.
  • Documentation

    • API webhook docs updated with new event descriptions and concrete example payloads illustrating the new types and alternate-address fields.

@coderabbitai

coderabbitai Bot commented Jun 4, 2026 •

Copy link
Copy Markdown

Ready to act? Review this PR in Change Stack to turn feedback into patch suggestions you can inspect and refine.

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 12bb2023-7780-4103-8f80-94126c3edd6a

📥 Commits

Reviewing files that changed from the base of the PR and between 4b44e33 and 21b1b5c.

📒 Files selected for processing (3)
  • packages/engine-baileys/src/events.test.ts
  • packages/engine-zapo/src/events.test.ts
  • packages/types/src/schemas.test.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • packages/types/src/schemas.test.ts
  • packages/engine-baileys/src/events.test.ts
  • packages/engine-zapo/src/events.test.ts

📝 Walkthrough

Walkthrough

Adds four normalized engine event kinds—call, group_participants, group_update, membership_request—by extending Zod types and webhook enums, implementing mappers for Baileys and Zapo with unit tests, wiring event listeners in both engines, and updating OpenAPI webhook schema, examples, and description.

Changes

Normalized event types across engines

Layer / File(s) Summary
Event type schemas and webhook contract
packages/types/src/engine.ts, packages/types/src/webhook.ts
New Zod schemas and inferred types for call, group_participants, group_update, and membership_request; engineEventSchema and webhookEventTypeSchema extended.
Baileys event mappers
packages/engine-baileys/src/events.ts
Four mapper functions (mapBaileysCall, mapBaileysGroupParticipants, mapBaileysGroupUpdate, mapBaileysMembershipRequest) normalize Baileys payloads with allow-lists, timestamp/ephemeral conversions, and conditional alt-addressing fields.
Baileys engine wiring
packages/engine-baileys/src/engine.ts
BaileysEngine.connect() registers listeners for call, group-participants.update, groups.update, and group.join-request, mapping and emitting normalized events.
Zapo event mappers
packages/engine-zapo/src/events.ts
mapZapoCall and mapZapoGroup normalize Zapo events; mapZapoGroup routes participant actions, conditional metadata updates, and expands membership requests per participant.
Zapo engine wiring
packages/engine-zapo/src/engine.ts
ZapoEngine registers call and group handlers, mapping inputs and emitting each mapped result.
OpenAPI webhook documentation
apps/api/src/http/openapi.ts
WEBHOOK_DELIVERY_SCHEMA gains oneOf variants for the new event kinds, WEBHOOK_DELIVERY_EXAMPLES includes example payloads, and WEBHOOK_DESCRIPTION documents event semantics including partial group_update patches and alternate addressing.
Unit tests
packages/*/src/*.test.ts
Adds tests covering Baileys/Zapo mappers and schema parsing, including alternate identity (lid/pn) preservation and edge cases.
Test configuration
vitest.config.ts
Removes referenceRepos and replaces prior exclude logic with explicit test.include globs and simplified test.exclude.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • w3nder/multi-wa-api#2: Modifies apps/api/src/http/openapi.ts webhook delivery schema and examples; closely related to the OpenAPI documentation edits in this PR.

Suggested reviewers

  • w3nder

Poem

🐰 Four new events hop into view,
Calls and groups, now normalized too!
Baileys and Zapo nod in tune,
Webhooks bloom beneath the moon. 🎉

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% 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
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title accurately summarizes the main change: normalizing four new webhook event types (call, group, membership) into the engine-agnostic contract.
Linked Issues check ✅ Passed The PR implementation fully addresses issue #7 objectives: four new event types (call, group_participants, group_update, membership_request) are normalized with engine-agnostic schemas, implemented in both engines with proper mappers, and include alternate addressing fields.
Out of Scope Changes check ✅ Passed All changes are in-scope: type definitions, mapper implementations, engine wiring, tests, OpenAPI documentation, and test configuration align with issue #7 normalization objectives; newsletter/business/per-member resolution were intentionally deferred.

✏️ 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.

Actionable comments posted: 2

🧹 Nitpick comments (2)
packages/types/src/engine.ts (1)

102-110: ⚡ Quick win

Consider adding a minimum length constraint on participants array.

The participants field accepts an empty array. Looking at the test file (line 177-180), the test expects participants: [] to fail, but that's only because action: 'modify' is invalid. An empty array with a valid action like 'add' would currently pass validation, which may not be semantically correct for a participant update event.

If empty participant arrays should be rejected, add .min(1):

 export const groupParticipantsEventSchema = z.object({
   type: z.literal('group_participants'),
   chat: z.string(),
   action: participantActionSchema,
-  participants: z.array(z.string()),
+  participants: z.array(z.string()).min(1),
   author: z.string().optional(),
   authorAlt: z.string().optional(),
   timestamp: z.number().optional()
 })
🤖 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/types/src/engine.ts` around lines 102 - 110, The participants array
in groupParticipantsEventSchema currently allows empty arrays; update the
participants field (in groupParticipantsEventSchema) to require at least one
entry by applying a minimum-length constraint (e.g., change participants:
z.array(z.string()) to participants: z.array(z.string()).min(1)) so events like
'add' cannot validate with an empty participants list.
packages/engine-zapo/src/events.test.ts (1)

539-549: ⚡ Quick win

Add regression cases for missing enabled / expirationSeconds in metadata actions.

Please add assertions that mapZapoGroup returns [] when action is announce/restrict without enabled, and ephemeral without expirationSeconds, so partial-update behavior is enforced by tests.

Suggested test additions
   it('routes metadata actions to group_update', () => {
@@
     expect(
       mapZapoGroup({ action: 'ephemeral', groupJid: 'g@g.us', expirationSeconds: 604800 })
     ).toEqual([{ type: 'group_update', chat: 'g@g.us', ephemeralSeconds: 604800 }])
+    expect(mapZapoGroup({ action: 'announce', groupJid: 'g@g.us' })).toEqual([])
+    expect(mapZapoGroup({ action: 'restrict', groupJid: 'g@g.us' })).toEqual([])
+    expect(mapZapoGroup({ action: 'ephemeral', groupJid: 'g@g.us' })).toEqual([])
   })
🤖 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.test.ts` around lines 539 - 549, Add
regression assertions to ensure mapZapoGroup enforces partial-update behavior:
add tests that when calling mapZapoGroup({ action: 'announce', groupJid:
'g@g.us' }) and mapZapoGroup({ action: 'restrict', groupJid: 'g@g.us' }) (i.e.,
missing enabled) it returns [], and that mapZapoGroup({ action: 'ephemeral',
groupJid: 'g@g.us' }) (missing expirationSeconds) also returns []; update the
existing test block that covers metadata actions (which currently checks
subject/announce/ephemeral with fields present) to include these extra
expect(...).toEqual([]) assertions referencing mapZapoGroup so the behavior is
covered.
🤖 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.

Inline comments:
In `@packages/engine-baileys/src/events.ts`:
- Around line 396-402: The function mapBaileysCall currently drops Baileys v7's
"timeout" status because CALL_STATUSES only allows
'offer'|'accept'|'reject'|'terminate'; update mapBaileysCall to translate a
call.status === 'timeout' to 'terminate' (before checking CALL_STATUSES) so that
timeout events are normalized to CallStatus. Modify the logic around
CALL_STATUSES and the initial guard in mapBaileysCall (referencing
BaileysCallInput, CALL_STATUSES and the returned CallStatus) to perform the
mapping first, then apply the allow-list and return the normalized status.

In `@packages/engine-zapo/src/events.ts`:
- Around line 410-426: The code is fabricating group_update fields by coercing
missing event.enabled/event.expirationSeconds into false/0; in the
ZAPO_UPDATE_ACTIONS branch (where GroupUpdateEvent update is built) only assign
update.announce, update.restrict, and update.ephemeralSeconds when the
corresponding source properties are actually present (e.g., event.enabled !==
undefined and event.expirationSeconds !== undefined/null) instead of using the
nullish coalescing defaults (?? false/0); preserve the existing
subject/description checks and the hasField existence test so the function
returns an update only when at least one real source field was provided.

---

Nitpick comments:
In `@packages/engine-zapo/src/events.test.ts`:
- Around line 539-549: Add regression assertions to ensure mapZapoGroup enforces
partial-update behavior: add tests that when calling mapZapoGroup({ action:
'announce', groupJid: 'g@g.us' }) and mapZapoGroup({ action: 'restrict',
groupJid: 'g@g.us' }) (i.e., missing enabled) it returns [], and that
mapZapoGroup({ action: 'ephemeral', groupJid: 'g@g.us' }) (missing
expirationSeconds) also returns []; update the existing test block that covers
metadata actions (which currently checks subject/announce/ephemeral with fields
present) to include these extra expect(...).toEqual([]) assertions referencing
mapZapoGroup so the behavior is covered.

In `@packages/types/src/engine.ts`:
- Around line 102-110: The participants array in groupParticipantsEventSchema
currently allows empty arrays; update the participants field (in
groupParticipantsEventSchema) to require at least one entry by applying a
minimum-length constraint (e.g., change participants: z.array(z.string()) to
participants: z.array(z.string()).min(1)) so events like 'add' cannot validate
with an empty participants list.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: e1d65ae0-9f9b-4c61-8e98-c0198eb78062

📥 Commits

Reviewing files that changed from the base of the PR and between e82f48a and 0628359.

📒 Files selected for processing (11)
  • 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
  • vitest.config.ts

Comment thread packages/engine-baileys/src/events.ts Outdated
Comment thread packages/engine-zapo/src/events.ts
@jobasfernandes
jobasfernandes merged commit 2408fdb into w3nder:main Jun 5, 2026
2 checks passed
@jobasfernandes
jobasfernandes deleted the feat/normalize-more-events branch June 5, 2026 22:46
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): normalizar mais eventos (chamadas, participantes/metadados de grupo, canais)

1 participant