Skip to content

Conversation

@ViperTecCorporation
Copy link
Contributor

@ViperTecCorporation ViperTecCorporation commented Jan 24, 2026

Português:
Permite enviar reações a mensagens existentes no WhatsApp informando o message_id e o emoji. Útil para responder sem enviar texto novo; o envio referencia a mensagem original e gera um evento de reação no destinatário.

Permite enviar figurinhas (stickers) via endpoint de mensagens. PNG/JPG/GIF são automaticamente convertidos para WEBP antes do envio, garantindo compatibilidade com o WhatsApp. Basta informar o link da mídia no payload.

English:
Allows sending reactions to existing WhatsApp messages by providing the message_id and an emoji. Useful to respond without sending new text; the reaction references the original message and triggers a reaction event for the recipient.

Allows sending stickers through the messages endpoint. PNG/JPG/GIF are automatically converted to WEBP before sending to ensure WhatsApp compatibility. Just provide the media link in the payload.

Permite enviar figurinhas (stickers) via endpoint de mensagens. PNG/JPG/GIF são automaticamente convertidos para WEBP antes do envio, garantindo compatibilidade com o WhatsApp. Basta informar o link da mídia no payload.

Summary by CodeRabbit

  • New Features

    • Send stickers with automatic on-the-fly WEBP conversion.
    • Send reactions to specific messages with resolved targets and emoji.
  • Improvements

    • Per-recipient send routing with recipient-keyed delays and preserved send options.
    • Sticker conversion is non-blocking and falls back gracefully when conversion fails.
  • Documentation

    • Added README examples for sending reactions and stickers.
  • Tests

    • Added tests covering reaction resolution and sticker handling.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Jan 24, 2026

Warning

Rate limit exceeded

@ViperTecCorporation has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 13 minutes and 22 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📝 Walkthrough

Walkthrough

Adds README examples for sticker and reaction requests; adds a WEBP sticker conversion utility; implements reaction resolution and routing plus sticker conversion in the Baileys client service; extends transformer to handle sticker and reaction types and adds tests for both (some tests duplicated).

Changes

Cohort / File(s) Summary
Documentation
README.md
Added usage examples showing how to send sticker and reaction payloads (curl commands and headers).
Sticker Conversion Utility
src/utils/sticker_convert.ts
New convertToWebpSticker(input: Buffer, opts?) to resize ≤512×512 and encode as WEBP (quality 80, effort 4), supports animated option, returns Buffer.
Reaction Resolver
src/services/reaction_helper.ts
New resolveReactionPayload(payload, dataStore) and ReactionResolveResult type: validates payload, resolves message key via dataStore (with fallbacks), derives emoji, and returns { emoji, reactionKey, targetTo, messageId }; throws SendError on missing/invalid inputs.
Messaging Service (Baileys client)
src/services/client_baileys.ts
Added private maybeConvertStickerToWebp, integrated sticker conversion into send flow (non-blocking on error), added reaction outgoing type handling that uses resolveReactionPayload, routes sends to resolved targetTo, keys per-target delays by targetTo, and propagates extraSendOptions into final sends.
Transformer & Tests
src/services/transformer.ts, __tests__/services/transformer.ts, __tests__/services/reaction_helper.ts
toBaileysMessageContent now treats sticker as media and adds case "reaction" to construct Baileys reaction content (validates key); tests added for reaction and sticker transformations and reaction helper resolution/error cases (note: transformer tests contain duplicated reaction test blocks).

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Service as Message Service
    participant ImageUtil as Sticker Converter
    participant Queue as Message Queue

    Client->>Service: POST /send (type: sticker, payload)
    Service->>Service: fetch sticker buffer from URL
    Service->>ImageUtil: convertToWebpSticker(buffer)
    alt Conversion successful
        ImageUtil-->>Service: WEBP buffer (mimetype image/webp)
    else Conversion fails
        ImageUtil-->>Service: Error (logged), continue with original buffer
    end
    Service->>Service: determine targetTo and apply per-target delay
    Service->>Queue: enqueue/send message to targetTo with extraSendOptions
    Queue-->>Client: delivery result
Loading
sequenceDiagram
    participant Client
    participant Service as Message Service
    participant Store as Data Store
    participant Remote as Remote JID

    Client->>Service: POST /send (type: reaction, payload)
    Service->>Service: extract message_id and reaction fields
    Service->>Store: resolve message key (loadKey / loadUnoId)
    Store-->>Service: original message key (or error)
    Service->>Service: build reaction content (emoji/text + key), determine targetTo
    Service->>Service: apply per-target delay
    Service->>Remote: send reaction to targetTo with extraSendOptions
    Remote-->>Client: reaction ack/delivery
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

🐰 I nibble bytes and spin a sticker bright,

I turn a PNG to WebP in the moonlight,
I chase the message key and tuck it tight,
I tap an emoji and send a tiny light,
Hop-hop — your reaction lands just right ✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main changes: adding support for sending reactions and stickers, which are the core features introduced across multiple new files and modifications.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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


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.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@src/services/client_baileys.ts`:
- Around line 543-551: The sticker download path (where stickerLink is fetched
under the condition involving isWebp and (content as any)?.sticker?.url) buffers
the entire response into memory then converts via convertToWebpSticker, which
can OOM on large inputs; add a MAX_STICKER_BYTES constant and before calling
resp.arrayBuffer() validate resp.headers.get('content-length') (if present)
against the limit and throw a clear error if too large, then after obtaining the
ArrayBuffer check arrayBuffer.byteLength against MAX_STICKER_BYTES and throw if
exceeded; keep using the same AbortSignal timeout (FETCH_TIMEOUT_MS) and ensure
all thrown errors include context like "sticker_too_large" so callers can handle
them.
🧹 Nitpick comments (1)
src/utils/sticker_convert.ts (1)

7-12: Add an input-pixel guard for untrusted images.
Sharp will decode the full image before resize; a conservative limitInputPixels helps prevent memory spikes from oversized inputs.

♻️ Proposed change
 export const convertToWebpSticker = async (input: Buffer, opts: StickerConvertOptions = {}) => {
-  const image = sharp(input, { animated: !!opts.animated })
+  const image = sharp(input, { animated: !!opts.animated, limitInputPixels: 16_777_216 })
   return image
     .resize(512, 512, { fit: 'inside', withoutEnlargement: true })
     .webp({ lossless: !opts.animated, quality: 80, effort: 4 })
     .toBuffer()
 }

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@src/services/client_baileys.ts`:
- Around line 469-522: The reaction branch resolves a recipient into targetTo
but later response construction still uses the original to, causing
jidToPhoneNumber failures when to is undefined; update all places after the
reaction handling that build success/error responses (and any calls to
jidToPhoneNumber) to use targetTo (fallback to to if targetTo is unset) instead
of to so responses use the resolved recipient; refer to the variables targetTo,
to, reactionKey, content, extraSendOptions when locating the response-building
logic to change.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/services/transformer.ts (1)

463-485: Guard against media-case fallthrough when link is missing.

Without a link, this case falls through into contacts, producing malformed output instead of failing fast. Add an explicit error (or early return) to avoid silent misrouting.

🛠️ Proposed fix
     const link = payload[type].link
     if (link) {
       let mimetype: string = getMimetype(payload)
       if (type == 'audio' && SEND_AUDIO_MESSAGE_AS_PTT) {
         response.ptt = true
       }
       if (payload[type].filename) {
         response.fileName = payload[type].filename
       }
       if (mimetype) {
         response.mimetype = mimetype
       }
       if (payload[type].caption) {
         response.caption = customMessageCharactersFunction(payload[type].caption)
       }
       response[type] = { url: link }
       break
     }
+    throw new Error(`invalid_media_payload: missing link for ${type}`)

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/services/client_baileys.ts (1)

452-524: Guard error responses when to is absent in reaction failures.
If resolveReactionPayload throws (e.g., missing/unknown message_id) and the payload has no to, the catch block still calls jidToPhoneNumber(to, ''), which can throw and mask the intended SendError response.

🐛 Suggested fix
  async send(payload: any, options: any = {}) {
    const { status, type } = payload
-   let { to } = payload
+   let { to } = payload
+   let safeTo = to || this.phone
@@
          if ('reaction' === type) {
            const resolved = await resolveReactionPayload(payload, this.store?.dataStore)
@@
            targetTo = resolved.targetTo
            to = targetTo
+           safeTo = targetTo
@@
      if (e instanceof SendError) {
@@
-          contacts: [
-            {
-              wa_id: jidToPhoneNumber(to, ''),
-            },
-          ],
+          contacts: [
+            {
+              wa_id: jidToPhoneNumber(safeTo, ''),
+            },
+          ],
@@
-                        recipient_id: jidToPhoneNumber(to || this.phone, ''),
+                        recipient_id: jidToPhoneNumber(safeTo, ''),

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