Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat/read-on-receipt #95

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open

feat/read-on-receipt #95

wants to merge 1 commit into from

Conversation

clairton
Copy link
Owner

@clairton clairton commented Jan 28, 2025

Summary by CodeRabbit

Based on the comprehensive summary, here are the release notes:

  • New Features

    • Added support for configurable read receipts in WhatsApp messaging
    • Introduced new configuration option readWhenReceipt to control message read status
  • Improvements

    • Simplified class and function signatures by removing incoming parameter
    • Enhanced message handling and configuration management
    • Added more flexible instance management for phone number configurations
  • Configuration

    • New environment variable support for read receipt behavior
    • Added VALIDATE_MEDIA_LINK_BEFORE_SEND and READ_WHEN_RECEIPT configuration options
  • Technical Enhancements

    • Refactored service classes to reduce dependencies
    • Improved logging and traceability in various services

Copy link

coderabbitai bot commented Jan 28, 2025

Warning

There were issues while running some tools. Please review the errors and either fix the tool’s configuration or disable the tool if it’s a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

src/bridge.ts

Oops! Something went wrong! :(

ESLint: 8.57.1

TypeError: prettier.resolveConfig.sync is not a function
Occurred while linting /src/bridge.ts:1
Rule: "prettier/prettier"
at Program (/node_modules/eslint-plugin-prettier/eslint-plugin-prettier.js:138:40)
at ruleErrorHandler (/node_modules/eslint/lib/linter/linter.js:1076:28)
at /node_modules/eslint/lib/linter/safe-emitter.js:45:58
at Array.forEach ()
at Object.emit (/node_modules/eslint/lib/linter/safe-emitter.js:45:38)
at NodeEventGenerator.applySelector (/node_modules/eslint/lib/linter/node-event-generator.js:297:26)
at NodeEventGenerator.applySelectors (/node_modules/eslint/lib/linter/node-event-generator.js:326:22)
at NodeEventGenerator.enterNode (/node_modules/eslint/lib/linter/node-event-generator.js:340:14)
at CodePathAnalyzer.enterNode (/node_modules/eslint/lib/linter/code-path-analysis/code-path-analyzer.js:803:23)
at /node_modules/eslint/lib/linter/linter.js:1111:32

__tests__/services/client_baileys.ts

Oops! Something went wrong! :(

ESLint: 8.57.1

TypeError: prettier.resolveConfig.sync is not a function
Occurred while linting /tests/services/client_baileys.ts:1
Rule: "prettier/prettier"
at Program (/node_modules/eslint-plugin-prettier/eslint-plugin-prettier.js:138:40)
at ruleErrorHandler (/node_modules/eslint/lib/linter/linter.js:1076:28)
at /node_modules/eslint/lib/linter/safe-emitter.js:45:58
at Array.forEach ()
at Object.emit (/node_modules/eslint/lib/linter/safe-emitter.js:45:38)
at NodeEventGenerator.applySelector (/node_modules/eslint/lib/linter/node-event-generator.js:297:26)
at NodeEventGenerator.applySelectors (/node_modules/eslint/lib/linter/node-event-generator.js:326:22)
at NodeEventGenerator.enterNode (/node_modules/eslint/lib/linter/node-event-generator.js:340:14)
at CodePathAnalyzer.enterNode (/node_modules/eslint/lib/linter/code-path-analysis/code-path-analyzer.js:803:23)
at /node_modules/eslint/lib/linter/linter.js:1111:32

src/index.ts

Oops! Something went wrong! :(

ESLint: 8.57.1

TypeError: prettier.resolveConfig.sync is not a function
Occurred while linting /src/index.ts:1
Rule: "prettier/prettier"
at Program (/node_modules/eslint-plugin-prettier/eslint-plugin-prettier.js:138:40)
at ruleErrorHandler (/node_modules/eslint/lib/linter/linter.js:1076:28)
at /node_modules/eslint/lib/linter/safe-emitter.js:45:58
at Array.forEach ()
at Object.emit (/node_modules/eslint/lib/linter/safe-emitter.js:45:38)
at NodeEventGenerator.applySelector (/node_modules/eslint/lib/linter/node-event-generator.js:297:26)
at NodeEventGenerator.applySelectors (/node_modules/eslint/lib/linter/node-event-generator.js:326:22)
at NodeEventGenerator.enterNode (/node_modules/eslint/lib/linter/node-event-generator.js:340:14)
at CodePathAnalyzer.enterNode (/node_modules/eslint/lib/linter/code-path-analysis/code-path-analyzer.js:803:23)
at /node_modules/eslint/lib/linter/linter.js:1111:32

  • 15 others

Walkthrough

This pull request introduces significant architectural changes to the messaging service, primarily focusing on removing the Incoming parameter from various components and adding a new readWhenReceipt feature. The modifications span multiple files, simplifying class constructors, removing dependencies on the Incoming type, and introducing a configurable mechanism for handling message read receipts. The changes aim to streamline the codebase and provide more flexible configuration options for message processing.

Changes

File Change Summary
__tests__/services/client_baileys.ts Removed incoming parameter from ClientBaileys instantiation
__tests__/services/incoming_baileys.ts Removed incoming parameter from getClientDummy function
__tests__/services/transformer.ts Added new test case for documentWithCaptionMessage
src/bridge.ts Removed incomingAmqp instantiation and references
src/defaults.ts Added new environment-based constants VALIDATE_MEDIA_LINK_BEFORE_SEND and READ_WHEN_RECEIPT
src/index.ts, src/jobs/bind_bridge.ts Added readWhenReceipt functionality and updated class instantiations
src/services/* Widespread removal of Incoming parameter across multiple service classes
src/services/config.ts Added readWhenReceipt property to Config type
src/services/read_when_receipt.ts New module for managing message read receipts

Poem

🐰 Hop, hop, through the code we go,
Removing incoming, letting services flow
Read receipts dance, a new feature bright
Simplifying logic with rabbit delight!
CodeRabbit's magic makes systems light 🌟

✨ Finishing Touches
  • 📝 Generate Docstrings (Beta)

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Beta)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@clairton clairton changed the title temp commit feat/read-on-receipt Jan 28, 2025
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: 11

🧹 Nitpick comments (7)
__tests__/services/transformer.ts (1)

91-93: Consider adding more test cases for edge scenarios.

The test only covers the happy path. Consider adding test cases for:

  • Missing caption
  • Invalid document message format
  • Empty document message

Here's an example of additional test cases:

test('return messageType documentWithCaptionMessage with missing caption', async () => {
  const payload = {
    message: {
      documentWithCaptionMessage: {
        message: {
          documentMessage: {
            url: "mock-url",
            mimetype: "video/mp4",
            title: "mock-video.mp4"
          }
        }
      }
    }
  }
  expect(getMessageType(payload)).toEqual('documentWithCaptionMessage')
})

test('return messageType documentWithCaptionMessage with empty document message', async () => {
  const payload = {
    message: {
      documentWithCaptionMessage: {
        message: {
          documentMessage: {}
        }
      }
    }
  }
  expect(getMessageType(payload)).toEqual('documentWithCaptionMessage')
})
src/services/read_when_receipt.ts (3)

5-8: Clarify interface contract for test() method.
Currently, test() does not explicitly define its return type or document its intended usage. Consider adding a return type or documentation to convey its purpose clearly, or remove it if it's not needed.


10-13: Confirm necessity of placeholder implementation.
readWhenReceiptDisabled implements send and test as no-ops. If these methods are never called in production, that’s fine, but it may be helpful to add explanatory comments clarifying that these methods intentionally do nothing.


37-39: Rename the interface to avoid confusion.
Having an interface named getReadWhenReceipt and a function of the same name may cause confusion. Consider renaming the interface to something like GetReadWhenReceiptFunction or removing it if it’s unnecessary.

src/services/reload_baileys.ts (1)

Line range hint 21-39: Refactor duplicate client creation logic.

The method creates a client twice with identical parameters. Consider extracting the client creation logic to a private method to improve maintainability and reduce code duplication.

+  private async createClient(phone: string) {
+    return this.getClient({
+      phone,
+      listener: this.listener,
+      getConfig: this.getConfig,
+      onNewLogin: this.onNewLogin,
+    })
+  }
+
   async run(phone: string) {
-    const currentClient = await this.getClient({
-      phone,
-      listener: this.listener,
-      getConfig: this.getConfig,
-      onNewLogin: this.onNewLogin,
-    })
+    const currentClient = await this.createClient(phone)
     const config = await this.getConfig(phone)
     const store = await config.getStore(phone, config)
     const { sessionStore }  = store
@@ -39,12 +31,7 @@
       await currentClient.disconnect()
     }
     await super.run(phone)
-    const newClient = await this.getClient({
-      phone,
-      listener: this.listener,
-      getConfig: this.getConfig,
-      onNewLogin: this.onNewLogin,
-    })
+    const newClient = await this.createClient(phone)
     await newClient.connect(1)
   }
src/standalone.ts (1)

159-162: Consider preserving stack traces in error handling.

The new error handling loses stack trace information, which could make debugging more difficult.

 process.on('unhandledRejection', (args) => {
-  // logger.error('unhandledRejection: %s', reason.stack)
-  logger.error('promise: %s', JSON.stringify(args))
-  // throw reason
+  const reason = args instanceof Error ? args : new Error(JSON.stringify(args))
+  logger.error('unhandledRejection: %s', reason.stack || reason.message)
+  throw reason
 })
src/defaults.ts (1)

16-19: LGTM! Well-structured environment variable configuration.

The new environment variables follow the established pattern and have sensible defaults.

Consider adding documentation for these new environment variables in the project's README or configuration guide.

Also applies to: 122-122

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c2c6256 and d556fab.

📒 Files selected for processing (22)
  • __tests__/services/client_baileys.ts (1 hunks)
  • __tests__/services/incoming_baileys.ts (0 hunks)
  • __tests__/services/transformer.ts (1 hunks)
  • src/bridge.ts (2 hunks)
  • src/defaults.ts (2 hunks)
  • src/index.ts (1 hunks)
  • src/jobs/bind_bridge.ts (1 hunks)
  • src/services/auto_connect.ts (1 hunks)
  • src/services/client.ts (0 hunks)
  • src/services/client_baileys.ts (5 hunks)
  • src/services/config.ts (2 hunks)
  • src/services/config_by_env.ts (2 hunks)
  • src/services/contact_baileys.ts (1 hunks)
  • src/services/data_store_redis.ts (2 hunks)
  • src/services/incoming_baileys.ts (0 hunks)
  • src/services/instance.ts (1 hunks)
  • src/services/listener_baileys.ts (4 hunks)
  • src/services/logout_baileys.ts (1 hunks)
  • src/services/read_when_receipt.ts (1 hunks)
  • src/services/redis.ts (2 hunks)
  • src/services/reload_baileys.ts (1 hunks)
  • src/standalone.ts (5 hunks)
💤 Files with no reviewable changes (3)
  • src/services/incoming_baileys.ts
  • tests/services/incoming_baileys.ts
  • src/services/client.ts
✅ Files skipped from review due to trivial changes (2)
  • src/services/redis.ts
  • src/services/config.ts
🧰 Additional context used
🪛 Biome (1.9.4)
src/jobs/bind_bridge.ts

[error] 30-30: Shouldn't redeclare 'getConfig'. Consider to delete it or rename it.

'getConfig' is defined here:

(lint/suspicious/noRedeclare)

🔇 Additional comments (15)
src/services/logout_baileys.ts (1)

13-13: Verify removal of incoming parameter.
The constructor no longer accepts incoming. Ensure that all references to the old constructor signature have been updated. Consider searching the codebase to confirm no remaining references to LogoutBaileys expect incoming.

✅ Verification successful

Constructor signature update is complete
All instances of LogoutBaileys instantiation in the codebase use the new constructor signature with four parameters. No references to the old signature with incoming parameter were found.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify that no references use the old constructor signature with `incoming`.
rg -A 1 'new LogoutBaileys\(.*\,\s*incoming'

Length of output: 168


Script:

#!/bin/bash
# Search for any instantiation of LogoutBaileys
rg "new LogoutBaileys" -A 2

# Search for type definitions and interfaces related to LogoutBaileys
rg "LogoutBaileys" -g "*.ts" -g "*.d.ts" -A 3

# Use ast-grep to find class instantiations
ast-grep --pattern 'new LogoutBaileys($_)'

Length of output: 2608

src/services/contact_baileys.ts (2)

1-1: Check imports for unused references.
Since Incoming usage was removed, confirm that all imports are still necessary. Any unused imports increase maintenance overhead.

✅ Verification successful

All imports are actively used in the codebase
The Contact import and all other imports in this file are necessary and actively used. The Contact interface is used in the class implementation, and there are no unused imports present.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Confirm that no references to `Incoming` remain in this file.
rg 'Incoming' src/services/contact_baileys.ts

Length of output: 45


Script:

#!/bin/bash
# Check for Contact usage and get file contents
echo "=== Searching for Contact usage ==="
rg "Contact" src/services/contact_baileys.ts

echo -e "\n=== File contents ==="
cat src/services/contact_baileys.ts

Length of output: 1229


13-13: Validate backward compatibility for constructor changes.
Removing the incoming parameter simplifies the constructor, but ensure that callers were updated accordingly. This might break internal or external code that expected the old signature.

✅ Verification successful

Constructor changes are verified and safe
The removal of the incoming parameter is safe as the only usage of ContactBaileys constructor in standalone.ts already matches the new signature. No other code references were found that could be impacted by this change.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search all references to `ContactBaileys` constructor usage to confirm it matches the new signature.
rg -A 3 'new ContactBaileys\(.*\)'

Length of output: 246


Script:

#!/bin/bash
# Check git history for the file
git log -p src/services/contact_baileys.ts | grep -A 10 "constructor"

# Search for type definitions and exports
rg "export.*ContactBaileys" -A 3

# Search for test files
fd "contact.*test" --type f
fd "contact.*spec" --type f

Length of output: 369


Script:

#!/bin/bash
# Find Contact interface definition
rg "interface Contact" -A 5

# Search for imports of ContactBaileys
rg "import.*ContactBaileys"

# Search for usage of Contact interface
rg "Contact\s*[:{]" -A 3

Length of output: 1647

src/services/reload_baileys.ts (1)

13-19: LGTM! Constructor changes align with removal of incoming parameter.

The constructor has been correctly updated to remove the incoming parameter while maintaining essential dependencies.

src/bridge.ts (1)

40-43: LGTM! Changes consistently remove the incoming parameter.

The modifications correctly update the constructor calls and function parameters to align with the removal of the incoming parameter across the codebase.

Also applies to: 63-63

src/index.ts (1)

45-46: LGTM! Parameter removal aligns with PR objectives.

The removal of the incomingBaileys parameter from ReloadBaileys, LogoutBaileys, and autoConnect is consistent with the PR's goal of simplifying the architecture.

Also applies to: 53-53

src/services/config_by_env.ts (1)

41-41: LGTM! Configuration changes are well-structured.

The addition of READ_WHEN_RECEIPT to the configuration is clean and follows the existing pattern.

Also applies to: 73-73

__tests__/services/client_baileys.ts (1)

75-75: Consider adding tests for read receipt functionality.

While the removal of the incoming parameter is correct, the test file should be updated to include test cases for the new read receipt functionality.

Consider adding the following test cases:

  1. Successful read receipt sending
  2. Failed read receipt sending
  3. Error handling scenarios

I can help generate these test cases if needed.

src/services/data_store_redis.ts (2)

85-88: LGTM! Improved JID handling logic.

The change to use isJidUser provides more precise handling of user JIDs compared to the previous group-based check.


91-94: Verify consistent JID handling across the codebase.

The JID handling logic has been updated. Let's verify this change is consistent with other JID transformations in the codebase.

✅ Verification successful

JID handling is consistent across the codebase

The JID transformation logic is properly centralized in the transformer service and consistently used throughout the codebase, including data stores, client communications, and media handling. The changes maintain this consistency.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for other JID transformations that might need similar updates
rg -A 2 "jidToPhoneNumber|phoneNumberToJid|isJidUser|isJidGroup" --type ts

Length of output: 15438

src/standalone.ts (1)

68-76: LGTM! Well-structured read receipt implementation.

The implementation correctly handles the read receipt functionality with proper debug logging and payload structure.

src/services/listener_baileys.ts (1)

99-101: LGTM! Well-implemented read receipt handling.

The read receipt is correctly triggered only for incoming messages (!i?.key?.fromMe).

src/services/client_baileys.ts (3)

52-52: LGTM: Constructor changes align with PR objectives.

The removal of the incoming parameter from both the constructor call and signature is implemented consistently.

Also applies to: 223-227


125-125: LGTM: Error handling refactored correctly.

The error notification has been properly migrated from this.incoming.send to this.sendMessage.


314-316: LGTM: Call rejection handling refactored correctly.

The call rejection message has been properly migrated from this.incoming.send to this.sendMessage.

Comment on lines +91 to +93
test('return messageType documentWithCaptionMessage', async () => {
const payload = {"key":{"remoteJid":"[email protected]","fromMe":false,"id":"3EB0AA0FA8CF9A5BD4D13D"},"messageTimestamp":1737746252,"pushName":"Emerson Casemiro","broadcast":false,"message":{"messageContextInfo":{"deviceListMetadata":{"senderKeyHash":"Cx7OGNKcbwqyqQ==","senderTimestamp":"1737203328","senderAccountType":"E2EE","receiverAccountType":"E2EE","recipientKeyHash":"S8o1LEWk33YRoA==","recipientTimestamp":"1737744851"},"deviceListMetadataVersion":2,"messageSecret":"+HGjutFitYLj4+gVC8F7S7CCM7fYeFhZM+SIdX0LYcM="},"documentWithCaptionMessage":{"message":{"documentMessage":{"url":"https://mmg.whatsapp.net/v/t62.7119-24/12161728_1172632827186041_246669122271751635_n.enc?ccb=11-4&oh=01_Q5AaIGXESRZeIDpQa_xrdaJw77EfYWwfgqkE6gf8fAXiD0-n&oe=66EDCD0C&_nc_sid=5e03e0&mms3=true","mimetype":"video/mp4","title":"video1981450644.mp4","fileSha256":"NW9GHqDFA8rZO6bFzeHxjFA7FSubZRkGHxGTz5CjqGA=","fileLength":"5740942","pageCount":0,"mediaKey":"tQoQcgWxymM12mmNlh3kcAgmOUo/lymVz3kPqcnFAGA=","fileName":"video1981450644.mp4","fileEncSha256":"KRf3aTRRWSp9gSclIu6iSjUk6ek6C4bFDCjBsrXQYSU=","directPath":"/v/t62.7119-24/32409775_1146339107002189_7733160102753112682_n.enc?ccb=11-4&oh=01_Q5AaIMPEs_9ILdnvkFSoZdM4zRZetoNGBM-a45BuI7vihuag&oe=67BB6FBC&_nc_sid=5e03e0&_nc_hot=1737746251","mediaKeyTimestamp":"1724272727","contactVcard":false,"caption":"video1981450644.mp4"},"messageContextInfo":{"messageSecret":"+HGjutFitYLj4+gVC8F7S7CCM7fYeFhZM+SIdX0LYcM="}}}},"profilePicture":"https://pps.whatsapp.net/v/t61.24694-24/389368984_315748354525689_7231214457442380254_n.jpg?stp=dst-jpg_s96x96_tt6&ccb=11-4&oh=01_Q5AaIGrFzQWqLHY6drciBsqcEvehTMtbjVVYtm3G7BwA4L51&oe=67A0FECA&_nc_sid=5e03e0&_nc_cat=106"}
expect(getMessageType(payload)).toEqual('documentWithCaptionMessage')
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Sanitize sensitive information in test data.

The test payload contains sensitive information such as phone numbers and URLs. Consider replacing them with mock data.

Apply this diff to sanitize the test data:

   test('return messageType documentWithCaptionMessage', async () => {
-    const payload = {"key":{"remoteJid":"[email protected]","fromMe":false,"id":"3EB0AA0FA8CF9A5BD4D13D"},"messageTimestamp":1737746252,"pushName":"Emerson Casemiro","broadcast":false,"message":{"messageContextInfo":{"deviceListMetadata":{"senderKeyHash":"Cx7OGNKcbwqyqQ==","senderTimestamp":"1737203328","senderAccountType":"E2EE","receiverAccountType":"E2EE","recipientKeyHash":"S8o1LEWk33YRoA==","recipientTimestamp":"1737744851"},"deviceListMetadataVersion":2,"messageSecret":"+HGjutFitYLj4+gVC8F7S7CCM7fYeFhZM+SIdX0LYcM="},"documentWithCaptionMessage":{"message":{"documentMessage":{"url":"https://mmg.whatsapp.net/v/t62.7119-24/12161728_1172632827186041_246669122271751635_n.enc?ccb=11-4&oh=01_Q5AaIGXESRZeIDpQa_xrdaJw77EfYWwfgqkE6gf8fAXiD0-n&oe=66EDCD0C&_nc_sid=5e03e0&mms3=true","mimetype":"video/mp4","title":"video1981450644.mp4","fileSha256":"NW9GHqDFA8rZO6bFzeHxjFA7FSubZRkGHxGTz5CjqGA=","fileLength":"5740942","pageCount":0,"mediaKey":"tQoQcgWxymM12mmNlh3kcAgmOUo/lymVz3kPqcnFAGA=","fileName":"video1981450644.mp4","fileEncSha256":"KRf3aTRRWSp9gSclIu6iSjUk6ek6C4bFDCjBsrXQYSU=","directPath":"/v/t62.7119-24/32409775_1146339107002189_7733160102753112682_n.enc?ccb=11-4&oh=01_Q5AaIMPEs_9ILdnvkFSoZdM4zRZetoNGBM-a45BuI7vihuag&oe=67BB6FBC&_nc_sid=5e03e0&_nc_hot=1737746251","mediaKeyTimestamp":"1724272727","contactVcard":false,"caption":"video1981450644.mp4"},"messageContextInfo":{"messageSecret":"+HGjutFitYLj4+gVC8F7S7CCM7fYeFhZM+SIdX0LYcM="}}}},"profilePicture":"https://pps.whatsapp.net/v/t61.24694-24/389368984_315748354525689_7231214457442380254_n.jpg?stp=dst-jpg_s96x96_tt6&ccb=11-4&oh=01_Q5AaIGrFzQWqLHY6drciBsqcEvehTMtbjVVYtm3G7BwA4L51&oe=67A0FECA&_nc_sid=5e03e0&_nc_cat=106"}
+    const payload = {
+      key: {
+        remoteJid: "[email protected]",
+        fromMe: false,
+        id: "mock-id"
+      },
+      message: {
+        documentWithCaptionMessage: {
+          message: {
+            documentMessage: {
+              url: "mock-url",
+              mimetype: "video/mp4",
+              title: "mock-video.mp4",
+              caption: "mock-caption"
+            }
+          }
+        }
+      }
+    }
     expect(getMessageType(payload)).toEqual('documentWithCaptionMessage')
   })
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
test('return messageType documentWithCaptionMessage', async () => {
const payload = {"key":{"remoteJid":"[email protected]","fromMe":false,"id":"3EB0AA0FA8CF9A5BD4D13D"},"messageTimestamp":1737746252,"pushName":"Emerson Casemiro","broadcast":false,"message":{"messageContextInfo":{"deviceListMetadata":{"senderKeyHash":"Cx7OGNKcbwqyqQ==","senderTimestamp":"1737203328","senderAccountType":"E2EE","receiverAccountType":"E2EE","recipientKeyHash":"S8o1LEWk33YRoA==","recipientTimestamp":"1737744851"},"deviceListMetadataVersion":2,"messageSecret":"+HGjutFitYLj4+gVC8F7S7CCM7fYeFhZM+SIdX0LYcM="},"documentWithCaptionMessage":{"message":{"documentMessage":{"url":"https://mmg.whatsapp.net/v/t62.7119-24/12161728_1172632827186041_246669122271751635_n.enc?ccb=11-4&oh=01_Q5AaIGXESRZeIDpQa_xrdaJw77EfYWwfgqkE6gf8fAXiD0-n&oe=66EDCD0C&_nc_sid=5e03e0&mms3=true","mimetype":"video/mp4","title":"video1981450644.mp4","fileSha256":"NW9GHqDFA8rZO6bFzeHxjFA7FSubZRkGHxGTz5CjqGA=","fileLength":"5740942","pageCount":0,"mediaKey":"tQoQcgWxymM12mmNlh3kcAgmOUo/lymVz3kPqcnFAGA=","fileName":"video1981450644.mp4","fileEncSha256":"KRf3aTRRWSp9gSclIu6iSjUk6ek6C4bFDCjBsrXQYSU=","directPath":"/v/t62.7119-24/32409775_1146339107002189_7733160102753112682_n.enc?ccb=11-4&oh=01_Q5AaIMPEs_9ILdnvkFSoZdM4zRZetoNGBM-a45BuI7vihuag&oe=67BB6FBC&_nc_sid=5e03e0&_nc_hot=1737746251","mediaKeyTimestamp":"1724272727","contactVcard":false,"caption":"video1981450644.mp4"},"messageContextInfo":{"messageSecret":"+HGjutFitYLj4+gVC8F7S7CCM7fYeFhZM+SIdX0LYcM="}}}},"profilePicture":"https://pps.whatsapp.net/v/t61.24694-24/389368984_315748354525689_7231214457442380254_n.jpg?stp=dst-jpg_s96x96_tt6&ccb=11-4&oh=01_Q5AaIGrFzQWqLHY6drciBsqcEvehTMtbjVVYtm3G7BwA4L51&oe=67A0FECA&_nc_sid=5e03e0&_nc_cat=106"}
expect(getMessageType(payload)).toEqual('documentWithCaptionMessage')
test('return messageType documentWithCaptionMessage', async () => {
const payload = {
key: {
remoteJid: "[email protected]",
fromMe: false,
id: "mock-id"
},
message: {
documentWithCaptionMessage: {
message: {
documentMessage: {
url: "mock-url",
mimetype: "video/mp4",
title: "mock-video.mp4",
caption: "mock-caption"
}
}
}
}
}
expect(getMessageType(payload)).toEqual('documentWithCaptionMessage')
})

Comment on lines +15 to +33
export class ReadWhenReceiptEnabled implements ReadWhenReceipt {
private incoming: Incoming

constructor(incoming: Incoming) {
this.incoming = incoming
}

test() {}

async send(phone, from, messageId){
logger.debug('Send reading phone: %s from: %s message: %s', phone, from, messageId)
const payload = {
messaging_product: 'whatsapp',
status: 'read',
message_id: messageId
}
await this.incoming.send(from, payload, {})
}
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Ensure robust error handling in ReadWhenReceiptEnabled class.
When calling this.incoming.send, consider adding minimal error handling (e.g., logging error messages). This helps avoid silent failures if this.incoming.send rejects.

 async send(phone, from, messageId) {
   logger.debug('Send reading phone: %s from: %s message: %s', phone, from, messageId)
   const payload = {
     messaging_product: 'whatsapp',
     status: 'read',
     message_id: messageId
   }
-  await this.incoming.send(from, payload, {})
+  try {
+    await this.incoming.send(from, payload, {})
+  } catch (error) {
+    logger.error('Failed to send read receipt: %s', error)
+  }
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export class ReadWhenReceiptEnabled implements ReadWhenReceipt {
private incoming: Incoming
constructor(incoming: Incoming) {
this.incoming = incoming
}
test() {}
async send(phone, from, messageId){
logger.debug('Send reading phone: %s from: %s message: %s', phone, from, messageId)
const payload = {
messaging_product: 'whatsapp',
status: 'read',
message_id: messageId
}
await this.incoming.send(from, payload, {})
}
}
export class ReadWhenReceiptEnabled implements ReadWhenReceipt {
private incoming: Incoming
constructor(incoming: Incoming) {
this.incoming = incoming
}
test() {}
async send(phone, from, messageId){
logger.debug('Send reading phone: %s from: %s message: %s', phone, from, messageId)
const payload = {
messaging_product: 'whatsapp',
status: 'read',
message_id: messageId
}
try {
await this.incoming.send(from, payload, {})
} catch (error) {
logger.error('Failed to send read receipt: %s', error)
}
}
}

Comment on lines +45 to +58
export const getReadWhenReceipt = (phone, config, incoming): ReadWhenReceipt => {
const instance = instances.get(phone)!
try {
instance.test()
} catch (e) {
if (e instanceof TypeError && e.message == "Cannot read properties of undefined (reading 'test')") {
const i: ReadWhenReceipt = config.readWhenReceipt ? new ReadWhenReceiptEnabled(incoming) : readWhenReceiptDisabled
instances.set(phone, i)
} else {
throw e
}
}
return instances.get(phone)!
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Use a straightforward existence check instead of exception-based logic.
Catching a TypeError to detect an uninitialized instance is potentially fragile if the error message changes or if other TypeErrors occur. Consider checking if (!instance) directly before trying instance.test().

 export const getReadWhenReceipt = (phone, config, incoming): ReadWhenReceipt => {
   const instance = instances.get(phone)!
-  try {
-    instance.test()
-  } catch (e) {
-    if (e instanceof TypeError && e.message == "Cannot read properties of undefined (reading 'test')") {
-      const i: ReadWhenReceipt = config.readWhenReceipt ? new ReadWhenReceiptEnabled(incoming) : readWhenReceiptDisabled
-      instances.set(phone, i)
-    } else {
-      throw e
-    }
+  if (!instance) {
+    const i: ReadWhenReceipt = config.readWhenReceipt
+      ? new ReadWhenReceiptEnabled(incoming)
+      : readWhenReceiptDisabled
+    instances.set(phone, i)
   }
   return instances.get(phone)!
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export const getReadWhenReceipt = (phone, config, incoming): ReadWhenReceipt => {
const instance = instances.get(phone)!
try {
instance.test()
} catch (e) {
if (e instanceof TypeError && e.message == "Cannot read properties of undefined (reading 'test')") {
const i: ReadWhenReceipt = config.readWhenReceipt ? new ReadWhenReceiptEnabled(incoming) : readWhenReceiptDisabled
instances.set(phone, i)
} else {
throw e
}
}
return instances.get(phone)!
}
export const getReadWhenReceipt = (phone, config, incoming): ReadWhenReceipt => {
const instance = instances.get(phone)!
if (!instance) {
const i: ReadWhenReceipt = config.readWhenReceipt
? new ReadWhenReceiptEnabled(incoming)
: readWhenReceiptDisabled
instances.set(phone, i)
}
return instances.get(phone)!
}

import logger from './logger';
import { Outgoing } from './outgoing'

export const intances: Map<string, Intance> = new Map()
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix typo in Map variable name.

The variable name intances has a typo and should be instances.

-export const intances: Map<string, Intance> = new Map()
+export const instances: Map<string, Instance> = new Map()
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export const intances: Map<string, Intance> = new Map()
export const instances: Map<string, Instance> = new Map()

Comment on lines +16 to +25
export const getIntance = async <T>(phone: string, env: Env<T>): Promise<Intance> => {
if (!intances.has(phone)) {
logger.info('Creating instance %s', phone)
const getConfigVar: getConfig = env.REDIS_URL ? getConfigRedis : getConfigByEnv

} else {
logger.debug('Retrieving intances %s', phone)
}
return intances.get(phone)!
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Complete the implementation of getIntance function.

The function is incomplete:

  1. It doesn't create a new instance when one doesn't exist
  2. It has a typo in its name
  3. The logging message has a typo
  4. It's missing error handling for non-existent instances
-export const getIntance  = async <T>(phone: string, env: Env<T>): Promise<Intance> => {
+export const getInstance = async <T>(phone: string, env: Env<T>): Promise<Instance> => {
   if (!instances.has(phone)) {
     logger.info('Creating instance %s', phone)
     const getConfigVar: getConfig = env.REDIS_URL ? getConfigRedis : getConfigByEnv
+    const config = await getConfigVar(phone)
+    const instance = new Instance(env, config)
+    instances.set(phone, instance)
   } else {
-    logger.debug('Retrieving intances %s', phone)
+    logger.debug('Retrieving instance %s', phone)
   }
-  return intances.get(phone)!
+  const instance = instances.get(phone)
+  if (!instance) {
+    throw new Error(`Instance not found for phone ${phone}`)
+  }
+  return instance
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export const getIntance = async <T>(phone: string, env: Env<T>): Promise<Intance> => {
if (!intances.has(phone)) {
logger.info('Creating instance %s', phone)
const getConfigVar: getConfig = env.REDIS_URL ? getConfigRedis : getConfigByEnv
} else {
logger.debug('Retrieving intances %s', phone)
}
return intances.get(phone)!
}
export const getInstance = async <T>(phone: string, env: Env<T>): Promise<Instance> => {
if (!instances.has(phone)) {
logger.info('Creating instance %s', phone)
const getConfigVar: getConfig = env.REDIS_URL ? getConfigRedis : getConfigByEnv
const config = await getConfigVar(phone)
const instance = new Instance(env, config)
instances.set(phone, instance)
} else {
logger.debug('Retrieving instance %s', phone)
}
const instance = instances.get(phone)
if (!instance) {
throw new Error(`Instance not found for phone ${phone}`)
}
return instance
}

@@ -39,7 +37,7 @@ export const autoConnect = async (
logger.info(`Update session status to auto connect ${phone}...`)
await sessionStore.setStatus(phone, 'offline')
}
getClient({ phone, incoming, listener, getConfig, onNewLogin })
getClient({ phone, listener, getConfig, onNewLogin })
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix missing await for async function call.

The getClient function is asynchronous but its result is not being awaited. This could lead to race conditions or unexpected behavior.

-          getClient({ phone, listener, getConfig, onNewLogin })
+          await getClient({ phone, listener, getConfig, onNewLogin })
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
getClient({ phone, listener, getConfig, onNewLogin })
await getClient({ phone, listener, getConfig, onNewLogin })

Comment on lines +31 to +39
const readWhenReceipt: ReadWhenReceipt = async (from, messageId) => {
console.log('>>>>>>>>>>>>>>>>>>>>>>>>>>')
const payload = {
messaging_product: 'whatsapp',
status: 'read',
message_id: messageId
}
await incomingBaileys.send(from, payload, {})
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Remove debug log and add error handling.

The implementation has several issues that need to be addressed:

  1. Debug console.log statement should be removed
  2. Using incomingBaileys before it's defined could cause runtime issues
  3. Missing error handling for the async operation

Apply this diff to fix the issues:

 const readWhenReceipt: ReadWhenReceipt = async (from, messageId) => {
-  console.log('>>>>>>>>>>>>>>>>>>>>>>>>>>')
   const payload = {
     messaging_product: 'whatsapp',
     status: 'read',
     message_id: messageId
   }
-  await incomingBaileys.send(from, payload, {})
+  try {
+    await incomingBaileys.send(from, payload, {})
+  } catch (error) {
+    logger.error('Failed to send read receipt', { error, from, messageId })
+    throw error
+  }
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const readWhenReceipt: ReadWhenReceipt = async (from, messageId) => {
console.log('>>>>>>>>>>>>>>>>>>>>>>>>>>')
const payload = {
messaging_product: 'whatsapp',
status: 'read',
message_id: messageId
}
await incomingBaileys.send(from, payload, {})
}
const readWhenReceipt: ReadWhenReceipt = async (from, messageId) => {
const payload = {
messaging_product: 'whatsapp',
status: 'read',
message_id: messageId
}
try {
await incomingBaileys.send(from, payload, {})
} catch (error) {
logger.error('Failed to send read receipt', { error, from, messageId })
throw error
}
}


const outgoingAmqp: Outgoing = new OutgoingAmqp(getConfigRedis)
const listenerAmqp: Listener = new ListenerAmqp()
const broadcastAmqp: Broadcast = new BroadcastAmqp()
const listenerBaileys: Listener = new ListenerBaileys(outgoingAmqp, broadcastAmqp, getConfigRedis)

const getConfig: getConfig = getConfigRedis
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Rename redeclared getConfig variable.

The static analysis tool correctly flags that getConfig is being redeclared. This could lead to confusion.

Apply this diff to fix the issue:

-const getConfig: getConfig = getConfigRedis
+const configGetter: getConfig = getConfigRedis
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const getConfig: getConfig = getConfigRedis
const configGetter: getConfig = getConfigRedis
🧰 Tools
🪛 Biome (1.9.4)

[error] 30-30: Shouldn't redeclare 'getConfig'. Consider to delete it or rename it.

'getConfig' is defined here:

(lint/suspicious/noRedeclare)

Comment on lines +31 to +38
const readWhenReceipt: ReadWhenReceipt = async (from, messageId) => {
const payload = {
messaging_product: 'whatsapp',
status: 'read',
message_id: messageId
}
await incomingBaileys.send(from, payload, {})
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix read receipt implementation.

The implementation has the same issues as in index.ts:

  1. No error handling for the async operation
  2. Using incomingBaileys before it's defined

Apply this diff to fix the issues:

 const readWhenReceipt: ReadWhenReceipt = async (from, messageId) => {
   const payload = {
     messaging_product: 'whatsapp',
     status: 'read',
     message_id: messageId
   }
-  await incomingBaileys.send(from, payload, {})
+  try {
+    await incomingBaileys.send(from, payload, {})
+  } catch (error) {
+    logger.error('Failed to send read receipt', { error, from, messageId })
+    throw error
+  }
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const readWhenReceipt: ReadWhenReceipt = async (from, messageId) => {
const payload = {
messaging_product: 'whatsapp',
status: 'read',
message_id: messageId
}
await incomingBaileys.send(from, payload, {})
}
const readWhenReceipt: ReadWhenReceipt = async (from, messageId) => {
const payload = {
messaging_product: 'whatsapp',
status: 'read',
message_id: messageId
}
try {
await incomingBaileys.send(from, payload, {})
} catch (error) {
logger.error('Failed to send read receipt', { error, from, messageId })
throw error
}
}

@@ -360,13 +351,15 @@ export class ClientBaileys implements Client {
async send(payload: any, options: any = {}) {
const { status, type, to } = payload
try {
console.log('!!!!!!!!!!!')
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Remove debug console.log statements.

These debug statements should be removed:

  1. They use console.log instead of the established logger utility
  2. They contain non-descriptive content ('!!!!!!!!!!!')
  3. They may expose sensitive information (message IDs)

Apply this diff to remove the debug statements:

-      console.log('!!!!!!!!!!!')
       if (status) {
         if (['sent', 'delivered', 'failed', 'progress', 'read'].includes(status)) {
           if (status == 'read') {
             const currentStatus = await this.store?.dataStore?.loadStatus(payload?.message_id)
             if (currentStatus != status) {
               const key = await this.store?.dataStore?.loadKey(payload?.message_id)
               logger.debug('key %s for %s', JSON.stringify(key), payload?.message_id)
-              console.log(payload?.message_id, key)
               if (key?.id) {

Also applies to: 362-362

@clairton clairton force-pushed the feat/read-on-receipt branch from d556fab to f27c2ec Compare January 28, 2025 11:12
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

♻️ Duplicate comments (2)
src/jobs/bind_bridge.ts (1)

30-30: ⚠️ Potential issue

Fix variable redeclaration.

The variable getConfig is being redeclared, which could lead to confusion.

Apply this diff to fix the issue:

-const getConfig: getConfig = getConfigRedis
+const configGetter: getConfig = getConfigRedis
🧰 Tools
🪛 Biome (1.9.4)

[error] 30-30: Shouldn't redeclare 'getConfig'. Consider to delete it or rename it.

'getConfig' is defined here:

(lint/suspicious/noRedeclare)

src/services/client_baileys.ts (1)

354-354: ⚠️ Potential issue

Remove debug console.log statements.

These debug statements should be removed:

  1. They use console.log instead of the established logger utility
  2. They contain non-descriptive content ('!!!!!!!!!!!')
  3. They may expose sensitive information (message IDs)

Apply this diff to remove the debug statements:

-      console.log('!!!!!!!!!!!')
       if (status) {
         if (['sent', 'delivered', 'failed', 'progress', 'read'].includes(status)) {
           if (status == 'read') {
             const currentStatus = await this.store?.dataStore?.loadStatus(payload?.message_id)
             if (currentStatus != status) {
               const key = await this.store?.dataStore?.loadKey(payload?.message_id)
               logger.debug('key %s for %s', JSON.stringify(key), payload?.message_id)
-              console.log(payload?.message_id, key)
               if (key?.id) {

Also applies to: 362-362

🧹 Nitpick comments (1)
src/standalone.ts (1)

159-162: Improve unhandledRejection error handling.

The current implementation removes the stack trace and doesn't rethrow the error, which could make debugging more difficult.

Apply this diff to improve error handling:

-process.on('unhandledRejection', (args) => {
-  // logger.error('unhandledRejection: %s', reason.stack)
-  logger.error('promise: %s', JSON.stringify(args))
-  // throw reason
+process.on('unhandledRejection', (reason, promise) => {
+  logger.error('Unhandled Rejection at:', {
+    promise,
+    reason: reason instanceof Error ? {
+      message: reason.message,
+      stack: reason.stack
+    } : reason
+  })
+  // Optional: Exit process with error
+  process.exit(1)
 })
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d556fab and f27c2ec.

📒 Files selected for processing (21)
  • __tests__/services/client_baileys.ts (1 hunks)
  • __tests__/services/incoming_baileys.ts (0 hunks)
  • __tests__/services/transformer.ts (1 hunks)
  • src/bridge.ts (2 hunks)
  • src/defaults.ts (2 hunks)
  • src/index.ts (1 hunks)
  • src/jobs/bind_bridge.ts (1 hunks)
  • src/services/auto_connect.ts (1 hunks)
  • src/services/client.ts (0 hunks)
  • src/services/client_baileys.ts (5 hunks)
  • src/services/config.ts (2 hunks)
  • src/services/config_by_env.ts (2 hunks)
  • src/services/contact_baileys.ts (1 hunks)
  • src/services/incoming_baileys.ts (0 hunks)
  • src/services/instance.ts (1 hunks)
  • src/services/listener_baileys.ts (4 hunks)
  • src/services/logout_baileys.ts (1 hunks)
  • src/services/read_when_receipt.ts (1 hunks)
  • src/services/redis.ts (2 hunks)
  • src/services/reload_baileys.ts (1 hunks)
  • src/standalone.ts (5 hunks)
💤 Files with no reviewable changes (3)
  • src/services/client.ts
  • src/services/incoming_baileys.ts
  • tests/services/incoming_baileys.ts
🚧 Files skipped from review as they are similar to previous changes (15)
  • src/defaults.ts
  • tests/services/client_baileys.ts
  • src/services/redis.ts
  • src/services/contact_baileys.ts
  • src/services/auto_connect.ts
  • src/services/logout_baileys.ts
  • src/services/config.ts
  • src/services/instance.ts
  • src/services/reload_baileys.ts
  • src/services/config_by_env.ts
  • src/services/listener_baileys.ts
  • tests/services/transformer.ts
  • src/index.ts
  • src/services/read_when_receipt.ts
  • src/bridge.ts
🧰 Additional context used
🪛 Biome (1.9.4)
src/jobs/bind_bridge.ts

[error] 30-30: Shouldn't redeclare 'getConfig'. Consider to delete it or rename it.

'getConfig' is defined here:

(lint/suspicious/noRedeclare)

🔇 Additional comments (3)
src/jobs/bind_bridge.ts (2)

40-40: LGTM: Proper initialization of ListenerBaileys.

The initialization includes all required parameters including the new readWhenReceipt function.


31-38: ⚠️ Potential issue

Fix potential race condition in readWhenReceipt implementation.

The implementation has two issues:

  1. Using incomingBaileys before it's defined (line 37)
  2. No error handling for the async operation

Apply this diff to fix the issues:

 const readWhenReceipt: ReadWhenReceipt = async (from, messageId) => {
   const payload = {
     messaging_product: 'whatsapp',
     status: 'read',
     message_id: messageId
   }
-  await incomingBaileys.send(from, payload, {})
+  try {
+    await incomingBaileys.send(from, payload, {})
+  } catch (error) {
+    logger.error('Failed to send read receipt', { error, from, messageId })
+    throw error
+  }
 }

Likely invalid or redundant comment.

src/services/client_baileys.ts (1)

223-223: LGTM: Simplified constructor signature.

The constructor has been correctly simplified by removing the unused incoming parameter.

Comment on lines +68 to +76
const readWhenReceipt: ReadWhenReceipt = !READ_WHEN_RECEIPT ? readWhenReceiptDefault : async (phone, from, messageId) => {
logger.debug('Send reading phone: %s from: %s message: %s', phone, from, messageId)
const payload = {
messaging_product: 'whatsapp',
status: 'read',
message_id: messageId
}
await incoming.send(from, payload, {})
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Improve error handling in readWhenReceipt implementation.

The implementation needs better error handling and logging.

Apply this diff to improve error handling:

 const readWhenReceipt: ReadWhenReceipt = !READ_WHEN_RECEIPT ? readWhenReceiptDefault : async (phone, from, messageId) => {
   logger.debug('Send reading phone: %s from: %s message: %s', phone, from, messageId)
   const payload = {
     messaging_product: 'whatsapp',
     status: 'read',
     message_id: messageId
   }
-  await incoming.send(from, payload, {})
+  try {
+    await incoming.send(from, payload, {})
+  } catch (error) {
+    logger.error('Failed to send read receipt', { error, phone, from, messageId })
+    throw error
+  }
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const readWhenReceipt: ReadWhenReceipt = !READ_WHEN_RECEIPT ? readWhenReceiptDefault : async (phone, from, messageId) => {
logger.debug('Send reading phone: %s from: %s message: %s', phone, from, messageId)
const payload = {
messaging_product: 'whatsapp',
status: 'read',
message_id: messageId
}
await incoming.send(from, payload, {})
}
const readWhenReceipt: ReadWhenReceipt = !READ_WHEN_RECEIPT ? readWhenReceiptDefault : async (phone, from, messageId) => {
logger.debug('Send reading phone: %s from: %s message: %s', phone, from, messageId)
const payload = {
messaging_product: 'whatsapp',
status: 'read',
message_id: messageId
}
try {
await incoming.send(from, payload, {})
} catch (error) {
logger.error('Failed to send read receipt', { error, phone, from, messageId })
throw error
}
}

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