Skip to content

Conversation

nandobfer
Copy link

@nandobfer nandobfer commented Oct 3, 2025

📋 Description

When trying to save any message, the server would fail because messageTimestamp was being received as an object instead of a number.

That caused all instances to have 0 messages and never save a new message.

I have fixed that by just checking if it's an object and handling long-like, then converting correctly.

🧪 Type of Change

  • 🐛 Bug fix (non-breaking change which fixes an issue)
  • ✨ New feature (non-breaking change which adds functionality)
  • [ X ] 💥 Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • 📚 Documentation update
  • 🔧 Refactoring (no functional changes)
  • ⚡ Performance improvement
  • 🧹 Code cleanup
  • 🔒 Security fix

🧪 Testing

  • [ X ] Manual testing completed
  • [ X ] Functionality verified in development environment
  • [ X ] No breaking changes introduced
  • Tested with different connection types (if applicable)

📸 Screenshots (if applicable)

✅ Checklist

  • [ X ] My code follows the project's style guidelines
  • [ X ] I have performed a self-review of my code
  • [ X ] I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • [ X ] My changes generate no new warnings
  • [ X ] I have manually tested my changes thoroughly
  • I have verified the changes work with different scenarios
  • Any dependent changes have been merged and published

📝 Additional Notes

Summary by Sourcery

Fix messageTimestamp conversion issues by detecting and converting Long and Long-like objects throughout message processing, add safeguards and logging for missing original messages, and update the Baileys session assertion signature.

Bug Fixes:

  • Correct timestamp conversion for editedMessage.timestampMs and message.messageTimestamp by handling Long, Long-like objects, and falling back appropriately

Enhancements:

  • Extend convertLongToNumber utility to process objects with low/high properties
  • Log a warning and skip updates when the original message cannot be found

Copy link
Contributor

sourcery-ai bot commented Oct 3, 2025

Reviewer's Guide

This PR fixes failures in saving messages by robustly converting timestamp fields from various object formats to numbers, improves handling when the original message isn’t found during updates, and removes an unnecessary parameter from the session assertion method.

Sequence diagram for robust message timestamp conversion during message save

sequenceDiagram
participant S as "BaileysStartupService"
participant M as "Message Object"
participant DB as "Database"
S->>M: Receive message with messageTimestamp
alt messageTimestamp is Long
    S->>S: Convert using toNumber()
else messageTimestamp is Long-like object
    S->>S: Convert using Long.fromValue()
else messageTimestamp is number
    S->>S: Use as is
end
S->>DB: Save message with numeric timestamp
Loading

Class diagram for updated BaileysStartupService methods

classDiagram
class BaileysStartupService {
  +convertLongToNumber(obj)
  +baileysAssertSessions(jids: string[])
  // message saving logic now robustly converts timestamps
}
BaileysStartupService --|> ChannelStartupService
Loading

File-Level Changes

Change Details Files
Enhanced timestamp conversion to support long-like object formats
  • Added branch in edited message handler to detect objects with low/high fields and convert via Long.fromValue
  • Extended convertLongToNumber utility to handle generic long-like objects
  • Inserted object check in raw messageTimestamp extraction with fallback to Date.now()
src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts
Improved original message lookup handling
  • Changed condition to check findMessage.id instead of truthy findMessage
  • Logged a warning and continued loop when original message is not found
  • Assigned message.messageId only after confirming findMessage.id exists
src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts
Removed deprecated force parameter from session assertion
  • Updated baileysAssertSessions signature to accept only jids array
  • Removed force argument in the call to client.assertSessions
src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey there - I've reviewed your changes - here's some feedback:

  • Consider extracting the repeated Long-like object detection and conversion logic into a shared utility or type guard to reduce duplication and improve maintainability.
  • Double-check that removing the force parameter from baileysAssertSessions won’t break any existing callers, since it alters the method signature and behavior.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- Consider extracting the repeated Long-like object detection and conversion logic into a shared utility or type guard to reduce duplication and improve maintainability.
- Double-check that removing the `force` parameter from `baileysAssertSessions` won’t break any existing callers, since it alters the method signature and behavior.

## Individual Comments

### Comment 1
<location> `src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts:4376-4382` </location>
<code_context>
     }

+    // Handle Long-like objects that aren't detected by Long.isLong()
+    if (
+      obj &&
+      typeof obj === 'object' &&
+      'low' in obj &&
+      'high' in obj &&
+      typeof obj.low === 'number' &&
+      typeof obj.high === 'number'
+    ) {
+      return Long.fromValue(obj).toNumber();
</code_context>

<issue_to_address>
**suggestion:** The Long-like object detection logic is duplicated in multiple places.

Refactor the Long-like object detection and conversion into a shared utility to avoid code duplication and enhance maintainability.
</issue_to_address>

### Comment 2
<location> `src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts:4408-4423` </location>
<code_context>
     const contentMsg = message?.message[contentType] as any;

+    // Convert messageTimestamp to number properly
+    let messageTimestamp: number;
+    if (Long.isLong(message.messageTimestamp)) {
+      messageTimestamp = message.messageTimestamp.toNumber();
+    } else if (
+      message.messageTimestamp &&
+      typeof message.messageTimestamp === 'object' &&
+      message.messageTimestamp &&
+      'low' in message.messageTimestamp &&
+      'high' in message.messageTimestamp
+    ) {
+      // Handle Long-like objects that aren't detected by Long.isLong()
+      messageTimestamp = Long.fromValue(message.messageTimestamp).toNumber();
+    } else {
+      messageTimestamp = (message.messageTimestamp as number) || Date.now();
+    }
+
</code_context>

<issue_to_address>
**suggestion (bug_risk):** Defaulting to Date.now() if messageTimestamp is falsy may introduce inaccurate timestamps.

Explicitly handle missing timestamps instead of defaulting to Date.now(), such as by assigning null or logging a warning to avoid misleading data.

```suggestion
    // Convert messageTimestamp to number properly
    let messageTimestamp: number | null;
    if (Long.isLong(message.messageTimestamp)) {
      messageTimestamp = message.messageTimestamp.toNumber();
    } else if (
      message.messageTimestamp &&
      typeof message.messageTimestamp === 'object' &&
      'low' in message.messageTimestamp &&
      'high' in message.messageTimestamp
    ) {
      // Handle Long-like objects that aren't detected by Long.isLong()
      messageTimestamp = Long.fromValue(message.messageTimestamp).toNumber();
    } else if (typeof message.messageTimestamp === 'number') {
      messageTimestamp = message.messageTimestamp;
    } else {
      messageTimestamp = null;
      this.logger.warn(`Missing or invalid messageTimestamp for message: ${JSON.stringify(message)}`);
    }
```
</issue_to_address>

### Comment 3
<location> `src/api/integrations/channel/whatsapp/whatsapp.baileys.service.ts:4607-4609` </location>
<code_context>
    const response = await this.client.assertSessions(jids);

    return response;

</code_context>

<issue_to_address>
**suggestion (code-quality):** Inline variable that is immediately returned ([`inline-immediately-returned-variable`](https://docs.sourcery.ai/Reference/Rules-and-In-Line-Suggestions/TypeScript/Default-Rules/inline-immediately-returned-variable))

```suggestion
    return await this.client.assertSessions(jids);

```

<br/><details><summary>Explanation</summary>Something that we often see in people's code is assigning to a result variable
and then immediately returning it.

Returning the result directly shortens the code and removes an unnecessary
variable, reducing the mental load of reading the function.

Where intermediate variables can be useful is if they then get used as a
parameter or a condition, and the name can act like a comment on what the
variable represents. In the case where you're returning it from a function, the
function name is there to tell you what the result is, so the variable name
is unnecessary.
</details>
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment on lines +4376 to +4382
if (
obj &&
typeof obj === 'object' &&
'low' in obj &&
'high' in obj &&
typeof obj.low === 'number' &&
typeof obj.high === 'number'
Copy link
Contributor

Choose a reason for hiding this comment

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

suggestion: The Long-like object detection logic is duplicated in multiple places.

Refactor the Long-like object detection and conversion into a shared utility to avoid code duplication and enhance maintainability.

Comment on lines +4607 to 4609
const response = await this.client.assertSessions(jids);

return response;
Copy link
Contributor

Choose a reason for hiding this comment

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

suggestion (code-quality): Inline variable that is immediately returned (inline-immediately-returned-variable)

Suggested change
const response = await this.client.assertSessions(jids);
return response;
return await this.client.assertSessions(jids);


ExplanationSomething that we often see in people's code is assigning to a result variable
and then immediately returning it.

Returning the result directly shortens the code and removes an unnecessary
variable, reducing the mental load of reading the function.

Where intermediate variables can be useful is if they then get used as a
parameter or a condition, and the name can act like a comment on what the
variable represents. In the case where you're returning it from a function, the
function name is there to tell you what the result is, so the variable name
is unnecessary.

@DavidsonGomes DavidsonGomes changed the base branch from main to develop October 3, 2025 22:05
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.

2 participants